Move JDBC Docker Compose support into spring-boot-jdbc

This commit is contained in:
Phillip Webb
2025-05-19 19:25:25 -07:00
parent 7444a39a83
commit d1cd43bc68
49 changed files with 1357 additions and 38 deletions

View File

@@ -20,6 +20,7 @@ dependencies {
optional(project(":spring-boot-project:spring-boot-actuator-autoconfigure"))
optional(project(":spring-boot-project:spring-boot-autoconfigure"))
optional(project(":spring-boot-project:spring-boot-docker-compose"))
optional(project(":spring-boot-project:spring-boot-testcontainers"))
optional("com.h2database:h2")
optional("com.mchange:c3p0")
@@ -37,9 +38,15 @@ dependencies {
dockerTestImplementation(project(":spring-boot-project:spring-boot-test"))
dockerTestImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support-docker"))
dockerTestImplementation(testFixtures(project(":spring-boot-project:spring-boot-docker-compose")))
dockerTestImplementation("org.testcontainers:junit-jupiter")
dockerTestImplementation("org.testcontainers:postgresql")
dockerTestRuntimeOnly("com.clickhouse:clickhouse-jdbc")
dockerTestRuntimeOnly("com.microsoft.sqlserver:mssql-jdbc")
dockerTestRuntimeOnly("org.lz4:lz4-java:1.8.0")
dockerTestRuntimeOnly("org.postgresql:postgresql")
testImplementation(project(":spring-boot-project:spring-boot-test"))
testImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support"))
testImplementation(testFixtures(project(":spring-boot-project:spring-boot-autoconfigure")))

View File

@@ -0,0 +1,69 @@
/*
* 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.jdbc.docker.compose;
import java.sql.Driver;
import org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;
import org.springframework.boot.jdbc.DatabaseDriver;
import org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails;
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 ClickHouseJdbcDockerComposeConnectionDetailsFactory}.
*
* @author Stephane Nicoll
*/
class ClickHouseJdbcDockerComposeConnectionDetailsFactoryIntegrationTests {
@DockerComposeTest(composeFile = "clickhouse-compose.yaml", image = TestImage.CLICKHOUSE)
void runCreatesConnectionDetails(JdbcConnectionDetails connectionDetails) throws ClassNotFoundException {
assertConnectionDetails(connectionDetails);
checkDatabaseAccess(connectionDetails);
}
@DockerComposeTest(composeFile = "clickhouse-bitnami-compose.yaml", image = TestImage.BITNAMI_CLICKHOUSE)
void runWithBitnamiImageCreatesConnectionDetails(JdbcConnectionDetails connectionDetails) {
assertConnectionDetails(connectionDetails);
// See https://github.com/bitnami/containers/issues/73550
// checkDatabaseAccess(connectionDetails);
}
private void assertConnectionDetails(JdbcConnectionDetails connectionDetails) {
assertThat(connectionDetails.getUsername()).isEqualTo("myuser");
assertThat(connectionDetails.getPassword()).isEqualTo("secret");
assertThat(connectionDetails.getJdbcUrl()).startsWith("jdbc:clickhouse://").endsWith("/mydatabase");
}
@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.CLICKHOUSE.getValidationQuery(), Integer.class)).isEqualTo(1);
}
}

View File

@@ -0,0 +1,51 @@
/*
* 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.jdbc.docker.compose;
import org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;
import org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails;
import org.springframework.boot.testsupport.container.TestImage;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration tests for {@link MariaDbJdbcDockerComposeConnectionDetailsFactory}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
* @author Scott Frederick
*/
class MariaDbJdbcDockerComposeConnectionDetailsFactoryIntegrationTests {
@DockerComposeTest(composeFile = "mariadb-compose.yaml", image = TestImage.MARIADB)
void runCreatesConnectionDetails(JdbcConnectionDetails connectionDetails) {
assertConnectionDetails(connectionDetails);
}
@DockerComposeTest(composeFile = "mariadb-bitnami-compose.yaml", image = TestImage.BITNAMI_MARIADB)
void runWithBitnamiImageCreatesConnectionDetails(JdbcConnectionDetails connectionDetails) {
assertConnectionDetails(connectionDetails);
}
private void assertConnectionDetails(JdbcConnectionDetails connectionDetails) {
assertThat(connectionDetails.getUsername()).isEqualTo("myuser");
assertThat(connectionDetails.getPassword()).isEqualTo("secret");
assertThat(connectionDetails.getJdbcUrl()).startsWith("jdbc:mariadb://").endsWith("/mydatabase");
}
}

View File

@@ -0,0 +1,51 @@
/*
* 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.jdbc.docker.compose;
import org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;
import org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails;
import org.springframework.boot.testsupport.container.TestImage;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration tests for {@link MySqlJdbcDockerComposeConnectionDetailsFactory}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
* @author Scott Frederick
*/
class MySqlJdbcDockerComposeConnectionDetailsFactoryIntegrationTests {
@DockerComposeTest(composeFile = "mysql-compose.yaml", image = TestImage.MYSQL)
void runCreatesConnectionDetails(JdbcConnectionDetails connectionDetails) {
assertConnectionDetails(connectionDetails);
}
@DockerComposeTest(composeFile = "mysql-bitnami-compose.yaml", image = TestImage.BITNAMI_MYSQL)
void runWithBitnamiImageCreatesConnectionDetails(JdbcConnectionDetails connectionDetails) {
assertConnectionDetails(connectionDetails);
}
private void assertConnectionDetails(JdbcConnectionDetails connectionDetails) {
assertThat(connectionDetails.getUsername()).isEqualTo("myuser");
assertThat(connectionDetails.getPassword()).isEqualTo("secret");
assertThat(connectionDetails.getJdbcUrl()).startsWith("jdbc:mysql://").endsWith("/mydatabase");
}
}

View File

@@ -0,0 +1,61 @@
/*
* Copyright 2012-2025 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.jdbc.docker.compose;
import java.sql.Driver;
import java.time.Duration;
import org.awaitility.Awaitility;
import org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;
import org.springframework.boot.jdbc.DatabaseDriver;
import org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails;
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 OracleFreeJdbcDockerComposeConnectionDetailsFactory}.
*
* @author Andy Wilkinson
*/
class OracleFreeJdbcDockerComposeConnectionDetailsFactoryIntegrationTests {
@SuppressWarnings("unchecked")
@DockerComposeTest(composeFile = "oracle-compose.yaml", image = TestImage.ORACLE_FREE)
void runCreatesConnectionDetailsThatCanBeUsedToAccessDatabase(JdbcConnectionDetails connectionDetails)
throws Exception {
assertThat(connectionDetails.getUsername()).isEqualTo("app_user");
assertThat(connectionDetails.getPassword()).isEqualTo("app_user_secret");
assertThat(connectionDetails.getJdbcUrl()).startsWith("jdbc:oracle:thin:@").endsWith("/freepdb1");
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()));
Awaitility.await().atMost(Duration.ofMinutes(1)).ignoreExceptions().untilAsserted(() -> {
JdbcTemplate template = new JdbcTemplate(dataSource);
assertThat(template.queryForObject(DatabaseDriver.ORACLE.getValidationQuery(), String.class))
.isEqualTo("Hello");
});
}
}

View File

@@ -0,0 +1,65 @@
/*
* 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.jdbc.docker.compose;
import java.sql.Driver;
import java.time.Duration;
import org.awaitility.Awaitility;
import org.junit.jupiter.api.condition.OS;
import org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;
import org.springframework.boot.jdbc.DatabaseDriver;
import org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails;
import org.springframework.boot.testsupport.container.TestImage;
import org.springframework.boot.testsupport.junit.DisabledOnOs;
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 OracleXeJdbcDockerComposeConnectionDetailsFactory}.
*
* @author Andy Wilkinson
*/
@DisabledOnOs(os = { OS.LINUX, OS.MAC }, architecture = "aarch64",
disabledReason = "The Oracle image has no ARM support")
class OracleXeJdbcDockerComposeConnectionDetailsFactoryIntegrationTests {
@SuppressWarnings("unchecked")
@DockerComposeTest(composeFile = "oracle-compose.yaml", image = TestImage.ORACLE_XE)
void runCreatesConnectionDetailsThatCanBeUsedToAccessDatabase(JdbcConnectionDetails connectionDetails)
throws Exception {
assertThat(connectionDetails.getUsername()).isEqualTo("app_user");
assertThat(connectionDetails.getPassword()).isEqualTo("app_user_secret");
assertThat(connectionDetails.getJdbcUrl()).startsWith("jdbc:oracle:thin:@").endsWith("/xepdb1");
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()));
Awaitility.await().atMost(Duration.ofMinutes(1)).ignoreExceptions().untilAsserted(() -> {
JdbcTemplate template = new JdbcTemplate(dataSource);
assertThat(template.queryForObject(DatabaseDriver.ORACLE.getValidationQuery(), String.class))
.isEqualTo("Hello");
});
}
}

View File

@@ -0,0 +1,98 @@
/*
* Copyright 2012-2025 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.jdbc.docker.compose;
import java.sql.Driver;
import org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;
import org.springframework.boot.jdbc.DatabaseDriver;
import org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails;
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 PostgresJdbcDockerComposeConnectionDetailsFactory}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
* @author Scott Frederick
* @author He Zean
*/
class PostgresJdbcDockerComposeConnectionDetailsFactoryIntegrationTests {
@DockerComposeTest(composeFile = "postgres-compose.yaml", image = TestImage.POSTGRESQL)
void runCreatesConnectionDetails(JdbcConnectionDetails connectionDetails) throws ClassNotFoundException {
assertConnectionDetails(connectionDetails);
checkDatabaseAccess(connectionDetails);
}
@DockerComposeTest(composeFile = "postgres-with-trust-host-auth-method-compose.yaml", image = TestImage.POSTGRESQL)
void runCreatesConnectionDetailsThatCanAccessDatabaseWhenHostAuthMethodIsTrust(
JdbcConnectionDetails connectionDetails) throws ClassNotFoundException {
assertThat(connectionDetails.getUsername()).isEqualTo("myuser");
assertThat(connectionDetails.getPassword()).isNull();
assertThat(connectionDetails.getJdbcUrl()).startsWith("jdbc:postgresql://").endsWith("/mydatabase");
checkDatabaseAccess(connectionDetails);
}
@DockerComposeTest(composeFile = "postgres-bitnami-compose.yaml", image = TestImage.BITNAMI_POSTGRESQL)
void runWithBitnamiImageCreatesConnectionDetails(JdbcConnectionDetails connectionDetails)
throws ClassNotFoundException {
assertConnectionDetails(connectionDetails);
checkDatabaseAccess(connectionDetails);
}
@DockerComposeTest(composeFile = "postgres-application-name-compose.yaml", image = TestImage.POSTGRESQL)
void runCreatesConnectionDetailsApplicationName(JdbcConnectionDetails connectionDetails)
throws ClassNotFoundException {
assertThat(connectionDetails.getUsername()).isEqualTo("myuser");
assertThat(connectionDetails.getPassword()).isEqualTo("secret");
assertThat(connectionDetails.getJdbcUrl()).startsWith("jdbc:postgresql://")
.endsWith("?ApplicationName=spring+boot");
assertThat(executeQuery(connectionDetails, "select current_setting('application_name')", String.class))
.isEqualTo("spring boot");
}
private void assertConnectionDetails(JdbcConnectionDetails connectionDetails) {
assertThat(connectionDetails.getUsername()).isEqualTo("myuser");
assertThat(connectionDetails.getPassword()).isEqualTo("secret");
assertThat(connectionDetails.getJdbcUrl()).startsWith("jdbc:postgresql://").endsWith("/mydatabase");
}
private void checkDatabaseAccess(JdbcConnectionDetails connectionDetails) throws ClassNotFoundException {
assertThat(executeQuery(connectionDetails, DatabaseDriver.POSTGRESQL.getValidationQuery(), Integer.class))
.isEqualTo(1);
}
@SuppressWarnings("unchecked")
private <T> T executeQuery(JdbcConnectionDetails connectionDetails, String sql, Class<T> resultClass)
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()));
return new JdbcTemplate(dataSource).queryForObject(sql, resultClass);
}
}

View File

@@ -0,0 +1,74 @@
/*
* 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.jdbc.docker.compose;
import java.sql.Driver;
import org.junit.jupiter.api.condition.OS;
import org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;
import org.springframework.boot.jdbc.DatabaseDriver;
import org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails;
import org.springframework.boot.testsupport.container.TestImage;
import org.springframework.boot.testsupport.junit.DisabledOnOs;
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 SqlServerJdbcDockerComposeConnectionDetailsFactory}.
*
* @author Andy Wilkinson
*/
@DisabledOnOs(os = { OS.LINUX, OS.MAC }, architecture = "aarch64",
disabledReason = "The SQL server image has no ARM support")
class SqlServerJdbcDockerComposeConnectionDetailsFactoryIntegrationTests {
@DockerComposeTest(composeFile = "mssqlserver-compose.yaml", image = TestImage.SQL_SERVER)
void runCreatesConnectionDetailsThatCanBeUsedToAccessDatabase(JdbcConnectionDetails connectionDetails)
throws ClassNotFoundException, LinkageError {
assertThat(connectionDetails.getUsername()).isEqualTo("SA");
assertThat(connectionDetails.getPassword()).isEqualTo("verYs3cret");
assertThat(connectionDetails.getJdbcUrl()).startsWith("jdbc:sqlserver://");
checkDatabaseAccess(connectionDetails);
}
@DockerComposeTest(composeFile = "mssqlserver-with-jdbc-parameters-compose.yaml", image = TestImage.SQL_SERVER)
void runWithJdbcParametersCreatesConnectionDetailsThatCanBeUsedToAccessDatabase(
JdbcConnectionDetails connectionDetails) throws ClassNotFoundException {
assertThat(connectionDetails.getUsername()).isEqualTo("SA");
assertThat(connectionDetails.getPassword()).isEqualTo("verYs3cret");
assertThat(connectionDetails.getJdbcUrl()).startsWith("jdbc:sqlserver://")
.contains(";sendStringParametersAsUnicode=false;");
checkDatabaseAccess(connectionDetails);
}
@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.SQLSERVER.getValidationQuery(), Integer.class)).isEqualTo(1);
}
}

View File

@@ -0,0 +1,9 @@
services:
database:
image: '{imageName}'
ports:
- '8123'
environment:
- 'CLICKHOUSE_USER=myuser'
- 'CLICKHOUSE_PASSWORD=secret'
- 'CLICKHOUSE_DB=mydatabase'

View File

@@ -0,0 +1,9 @@
services:
database:
image: '{imageName}'
ports:
- '8123'
environment:
- 'CLICKHOUSE_USER=myuser'
- 'CLICKHOUSE_PASSWORD=secret'
- 'CLICKHOUSE_DB=mydatabase'

View File

@@ -0,0 +1,10 @@
services:
database:
image: '{imageName}'
ports:
- '3306'
environment:
- 'MARIADB_ROOT_PASSWORD=verysecret'
- 'MARIADB_USER=myuser'
- 'MARIADB_PASSWORD=secret'
- 'MARIADB_DATABASE=mydatabase'

View File

@@ -0,0 +1,11 @@
services:
database:
image: '{imageName}'
ports:
- '3306'
environment:
- 'MARIADB_ROOT_PASSWORD=verysecret'
- 'MARIADB_USER=myuser'
- 'MARIADB_PASSWORD=secret'
- 'MARIADB_DATABASE=mydatabase'

View File

@@ -0,0 +1,9 @@
services:
database:
image: '{imageName}'
ports:
- '1433'
environment:
- 'MSSQL_PID=express'
- 'MSSQL_SA_PASSWORD=verYs3cret'
- 'ACCEPT_EULA=yes'

View File

@@ -0,0 +1,11 @@
services:
database:
image: '{imageName}'
ports:
- '1433'
environment:
- 'MSSQL_PID=express'
- 'MSSQL_SA_PASSWORD=verYs3cret'
- 'ACCEPT_EULA=yes'
labels:
org.springframework.boot.jdbc.parameters: sendStringParametersAsUnicode=false

View File

@@ -0,0 +1,10 @@
services:
database:
image: '{imageName}'
ports:
- '3306'
environment:
- 'MYSQL_ROOT_PASSWORD=verysecret'
- 'MYSQL_USER=myuser'
- 'MYSQL_PASSWORD=secret'
- 'MYSQL_DATABASE=mydatabase'

View File

@@ -0,0 +1,10 @@
services:
database:
image: '{imageName}'
ports:
- '3306'
environment:
- 'MYSQL_ROOT_PASSWORD=verysecret'
- 'MYSQL_USER=myuser'
- 'MYSQL_PASSWORD=secret'
- 'MYSQL_DATABASE=mydatabase'

View File

@@ -0,0 +1,15 @@
services:
database:
image: '{imageName}'
ports:
- '1521'
environment:
- 'APP_USER=app_user'
- 'APP_USER_PASSWORD=app_user_secret'
- 'ORACLE_PASSWORD=secret'
healthcheck:
test: ["CMD-SHELL", "healthcheck.sh"]
interval: 10s
timeout: 5s
retries: 10

View File

@@ -0,0 +1,6 @@
services:
otlp:
image: '{imageName}'
ports:
- '4317'
- '4318'

View File

@@ -0,0 +1,12 @@
services:
database:
image: '{imageName}'
ports:
- '5432'
environment:
- 'POSTGRES_USER=myuser'
- 'POSTGRES_DB=mydatabase'
- 'POSTGRES_PASSWORD=secret'
labels:
org.springframework.boot.jdbc.parameters: 'ApplicationName=spring+boot'
org.springframework.boot.r2dbc.parameters: 'applicationName=spring boot'

View File

@@ -0,0 +1,9 @@
services:
database:
image: '{imageName}'
ports:
- '5432'
environment:
- 'POSTGRESQL_USERNAME=myuser'
- 'POSTGRESQL_DATABASE=mydatabase'
- 'POSTGRESQL_PASSWORD=secret'

View File

@@ -0,0 +1,9 @@
services:
database:
image: '{imageName}'
ports:
- '5432'
environment:
- 'POSTGRES_USER=myuser'
- 'POSTGRES_DB=mydatabase'
- 'POSTGRES_PASSWORD=secret'

View File

@@ -0,0 +1,9 @@
services:
database:
image: '{imageName}'
ports:
- '5432'
environment:
- 'POSTGRES_USER=myuser'
- 'POSTGRES_DB=mydatabase'
- 'POSTGRES_HOST_AUTH_METHOD=trust'

View File

@@ -0,0 +1,62 @@
/*
* Copyright 2012-2025 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.jdbc.docker.compose;
import java.util.Map;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* ClickHouse environment details.
*
* @author Stephane Nicoll
*/
class ClickHouseEnvironment {
private final String username;
private final String password;
private final String database;
ClickHouseEnvironment(Map<String, String> env) {
this.username = env.getOrDefault("CLICKHOUSE_USER", "default");
this.password = extractPassword(env);
this.database = env.getOrDefault("CLICKHOUSE_DB", "default");
}
private String extractPassword(Map<String, String> env) {
boolean allowEmpty = env.containsKey("ALLOW_EMPTY_PASSWORD");
String password = env.get("CLICKHOUSE_PASSWORD");
Assert.state(StringUtils.hasLength(password) || allowEmpty, "No ClickHouse password found");
return (password != null) ? password : "";
}
String getUsername() {
return this.username;
}
String getPassword() {
return this.password;
}
String getDatabase() {
return this.database;
}
}

View File

@@ -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.jdbc.docker.compose;
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.jdbc.autoconfigure.JdbcConnectionDetails;
/**
* {@link DockerComposeConnectionDetailsFactory} to create {@link JdbcConnectionDetails}
* for a {@code clickhouse} service.
*
* @author Stephane Nicoll
*/
class ClickHouseJdbcDockerComposeConnectionDetailsFactory
extends DockerComposeConnectionDetailsFactory<JdbcConnectionDetails> {
private static final String[] CLICKHOUSE_CONTAINER_NAMES = { "clickhouse/clickhouse-server", "bitnami/clickhouse" };
protected ClickHouseJdbcDockerComposeConnectionDetailsFactory() {
super(CLICKHOUSE_CONTAINER_NAMES);
}
@Override
protected JdbcConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {
return new ClickhouseJdbcDockerComposeConnectionDetails(source.getRunningService());
}
/**
* {@link JdbcConnectionDetails} backed by a {@code clickhouse}
* {@link RunningService}.
*/
static class ClickhouseJdbcDockerComposeConnectionDetails extends DockerComposeConnectionDetails
implements JdbcConnectionDetails {
private static final JdbcUrlBuilder jdbcUrlBuilder = new JdbcUrlBuilder("clickhouse", 8123);
private final ClickHouseEnvironment environment;
private final String jdbcUrl;
ClickhouseJdbcDockerComposeConnectionDetails(RunningService service) {
super(service);
this.environment = new ClickHouseEnvironment(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;
}
}
}

View File

@@ -0,0 +1,99 @@
/*
* Copyright 2012-2025 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.jdbc.docker.compose;
import org.springframework.boot.docker.compose.core.RunningService;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Utility used to build a JDBC URL for a {@link RunningService}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class JdbcUrlBuilder {
private static final String PARAMETERS_LABEL = "org.springframework.boot.jdbc.parameters";
private final String driverProtocol;
private final int containerPort;
/**
* Create a new {@link JdbcUrlBuilder} instance.
* @param driverProtocol the driver protocol
* @param containerPort the source container port
*/
JdbcUrlBuilder(String driverProtocol, int containerPort) {
Assert.notNull(driverProtocol, "'driverProtocol' must not be null");
this.driverProtocol = driverProtocol;
this.containerPort = containerPort;
}
/**
* Build a JDBC URL for the given {@link RunningService}.
* @param service the running service
* @return a new JDBC URL
*/
String build(RunningService service) {
return build(service, null);
}
/**
* Build a JDBC URL for the given {@link RunningService} and database.
* @param service the running service
* @param database the database to connect to
* @return a new JDBC URL
*/
String build(RunningService service, String database) {
return urlFor(service, database);
}
private String urlFor(RunningService service, String database) {
Assert.notNull(service, "'service' must not be null");
StringBuilder url = new StringBuilder("jdbc:%s://%s:%d".formatted(this.driverProtocol, service.host(),
service.ports().get(this.containerPort)));
if (StringUtils.hasLength(database)) {
url.append("/");
url.append(database);
}
String parameters = getParameters(service);
if (StringUtils.hasLength(parameters)) {
appendParameters(url, parameters);
}
return url.toString();
}
/**
* Appends to the given {@code url} the given {@code parameters}.
* <p>
* The default implementation appends a {@code ?} followed by the {@code parameters}.
* @param url the url
* @param parameters the parameters
* @since 3.2.7
*/
protected void appendParameters(StringBuilder url, String parameters) {
url.append("?").append(parameters);
}
private String getParameters(RunningService service) {
return service.labels().get(PARAMETERS_LABEL);
}
}

View File

@@ -0,0 +1,84 @@
/*
* 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.jdbc.docker.compose;
import java.util.Map;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* MariaDB environment details.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
* @author Scott Frederick
*/
class MariaDbEnvironment {
private final String username;
private final String password;
private final String database;
MariaDbEnvironment(Map<String, String> env) {
this.username = extractUsername(env);
this.password = extractPassword(env);
this.database = extractDatabase(env);
}
private String extractUsername(Map<String, String> env) {
String user = env.get("MARIADB_USER");
return (user != null) ? user : env.getOrDefault("MYSQL_USER", "root");
}
private String extractPassword(Map<String, String> env) {
Assert.state(!env.containsKey("MARIADB_RANDOM_ROOT_PASSWORD"), "MARIADB_RANDOM_ROOT_PASSWORD is not supported");
Assert.state(!env.containsKey("MYSQL_RANDOM_ROOT_PASSWORD"), "MYSQL_RANDOM_ROOT_PASSWORD is not supported");
Assert.state(!env.containsKey("MARIADB_ROOT_PASSWORD_HASH"), "MARIADB_ROOT_PASSWORD_HASH is not supported");
boolean allowEmpty = env.containsKey("MARIADB_ALLOW_EMPTY_PASSWORD")
|| env.containsKey("MYSQL_ALLOW_EMPTY_PASSWORD") || env.containsKey("ALLOW_EMPTY_PASSWORD");
String password = env.get("MARIADB_PASSWORD");
password = (password != null) ? password : env.get("MYSQL_PASSWORD");
password = (password != null) ? password : env.get("MARIADB_ROOT_PASSWORD");
password = (password != null) ? password : env.get("MYSQL_ROOT_PASSWORD");
Assert.state(StringUtils.hasLength(password) || allowEmpty, "No MariaDB password found");
return (password != null) ? password : "";
}
private String extractDatabase(Map<String, String> env) {
String database = env.get("MARIADB_DATABASE");
database = (database != null) ? database : env.get("MYSQL_DATABASE");
Assert.state(database != null, "No MARIADB_DATABASE defined");
return database;
}
String getUsername() {
return this.username;
}
String getPassword() {
return this.password;
}
String getDatabase() {
return this.database;
}
}

View File

@@ -0,0 +1,82 @@
/*
* 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.jdbc.docker.compose;
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.jdbc.autoconfigure.JdbcConnectionDetails;
/**
* {@link DockerComposeConnectionDetailsFactory} to create {@link JdbcConnectionDetails}
* for a {@code mariadb} service.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
* @author Scott Frederick
*/
class MariaDbJdbcDockerComposeConnectionDetailsFactory
extends DockerComposeConnectionDetailsFactory<JdbcConnectionDetails> {
private static final String[] MARIADB_CONTAINER_NAMES = { "mariadb", "bitnami/mariadb" };
protected MariaDbJdbcDockerComposeConnectionDetailsFactory() {
super(MARIADB_CONTAINER_NAMES);
}
@Override
protected JdbcConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {
return new MariaDbJdbcDockerComposeConnectionDetails(source.getRunningService());
}
/**
* {@link JdbcConnectionDetails} backed by a {@code mariadb} {@link RunningService}.
*/
static class MariaDbJdbcDockerComposeConnectionDetails extends DockerComposeConnectionDetails
implements JdbcConnectionDetails {
private static final JdbcUrlBuilder jdbcUrlBuilder = new JdbcUrlBuilder("mariadb", 3306);
private final MariaDbEnvironment environment;
private final String jdbcUrl;
MariaDbJdbcDockerComposeConnectionDetails(RunningService service) {
super(service);
this.environment = new MariaDbEnvironment(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;
}
}
}

View File

@@ -0,0 +1,73 @@
/*
* 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.jdbc.docker.compose;
import java.util.Map;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* MySQL environment details.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
* @author Scott Frederick
*/
class MySqlEnvironment {
private final String username;
private final String password;
private final String database;
MySqlEnvironment(Map<String, String> env) {
this.username = env.getOrDefault("MYSQL_USER", "root");
this.password = extractPassword(env);
this.database = extractDatabase(env);
}
private String extractPassword(Map<String, String> env) {
Assert.state(!env.containsKey("MYSQL_RANDOM_ROOT_PASSWORD"), "MYSQL_RANDOM_ROOT_PASSWORD is not supported");
boolean allowEmpty = env.containsKey("MYSQL_ALLOW_EMPTY_PASSWORD") || env.containsKey("ALLOW_EMPTY_PASSWORD");
String password = env.get("MYSQL_PASSWORD");
password = (password != null) ? password : env.get("MYSQL_ROOT_PASSWORD");
Assert.state(StringUtils.hasLength(password) || allowEmpty, "No MySQL password found");
return (password != null) ? password : "";
}
private String extractDatabase(Map<String, String> env) {
String database = env.get("MYSQL_DATABASE");
Assert.state(database != null, "No MYSQL_DATABASE defined");
return database;
}
String getUsername() {
return this.username;
}
String getPassword() {
return this.password;
}
String getDatabase() {
return this.database;
}
}

View File

@@ -0,0 +1,82 @@
/*
* 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.jdbc.docker.compose;
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.jdbc.autoconfigure.JdbcConnectionDetails;
/**
* {@link DockerComposeConnectionDetailsFactory} to create {@link JdbcConnectionDetails}
* for a {@code mysql} service.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
* @author Scott Frederick
*/
class MySqlJdbcDockerComposeConnectionDetailsFactory
extends DockerComposeConnectionDetailsFactory<JdbcConnectionDetails> {
private static final String[] MYSQL_CONTAINER_NAMES = { "mysql", "bitnami/mysql" };
protected MySqlJdbcDockerComposeConnectionDetailsFactory() {
super(MYSQL_CONTAINER_NAMES);
}
@Override
protected JdbcConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {
return new MySqlJdbcDockerComposeConnectionDetails(source.getRunningService());
}
/**
* {@link JdbcConnectionDetails} backed by a {@code mysql} {@link RunningService}.
*/
static class MySqlJdbcDockerComposeConnectionDetails extends DockerComposeConnectionDetails
implements JdbcConnectionDetails {
private static final JdbcUrlBuilder jdbcUrlBuilder = new JdbcUrlBuilder("mysql", 3306);
private final MySqlEnvironment environment;
private final String jdbcUrl;
MySqlJdbcDockerComposeConnectionDetails(RunningService service) {
super(service);
this.environment = new MySqlEnvironment(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;
}
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2012-2023 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.jdbc.docker.compose;
/**
* Enumeration of supported Oracle containers.
*
* @author Andy Wilkinson
*/
enum OracleContainer {
FREE("gvenzl/oracle-free", "freepdb1"),
XE("gvenzl/oracle-xe", "xepdb1");
private final String imageName;
private final String defaultDatabase;
OracleContainer(String imageName, String defaultDatabase) {
this.imageName = imageName;
this.defaultDatabase = defaultDatabase;
}
String getImageName() {
return this.imageName;
}
String getDefaultDatabase() {
return this.defaultDatabase;
}
}

View File

@@ -0,0 +1,68 @@
/*
* Copyright 2012-2023 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.jdbc.docker.compose;
import java.util.Map;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Oracle Database environment details.
*
* @author Andy Wilkinson
*/
class OracleEnvironment {
private final String username;
private final String password;
private final String database;
OracleEnvironment(Map<String, String> env, String defaultDatabase) {
this.username = env.getOrDefault("APP_USER", "system");
this.password = extractPassword(env);
this.database = env.getOrDefault("ORACLE_DATABASE", defaultDatabase);
}
private String extractPassword(Map<String, String> env) {
if (env.containsKey("APP_USER")) {
String password = env.get("APP_USER_PASSWORD");
Assert.state(StringUtils.hasLength(password), "No Oracle app password found");
return password;
}
Assert.state(!env.containsKey("ORACLE_RANDOM_PASSWORD"),
"ORACLE_RANDOM_PASSWORD is not supported without APP_USER and APP_USER_PASSWORD");
String password = env.get("ORACLE_PASSWORD");
Assert.state(StringUtils.hasLength(password), "No Oracle password found");
return password;
}
String getUsername() {
return this.username;
}
String getPassword() {
return this.password;
}
String getDatabase() {
return this.database;
}
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2012-2023 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.jdbc.docker.compose;
import org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;
import org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails;
/**
* {@link DockerComposeConnectionDetailsFactory} to create {@link JdbcConnectionDetails}
* for an {@link OracleContainer#FREE} service.
*
* @author Andy Wilkinson
*/
class OracleFreeJdbcDockerComposeConnectionDetailsFactory extends OracleJdbcDockerComposeConnectionDetailsFactory {
protected OracleFreeJdbcDockerComposeConnectionDetailsFactory() {
super(OracleContainer.FREE);
}
}

View File

@@ -0,0 +1,90 @@
/*
* Copyright 2012-2023 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.jdbc.docker.compose;
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.jdbc.autoconfigure.JdbcConnectionDetails;
import org.springframework.util.StringUtils;
/**
* Base class for a {@link DockerComposeConnectionDetailsFactory} to create
* {@link JdbcConnectionDetails} for an {@code oracle-free} or {@code oracle-xe} service.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
abstract class OracleJdbcDockerComposeConnectionDetailsFactory
extends DockerComposeConnectionDetailsFactory<JdbcConnectionDetails> {
private final String defaultDatabase;
protected OracleJdbcDockerComposeConnectionDetailsFactory(OracleContainer container) {
super(container.getImageName());
this.defaultDatabase = container.getDefaultDatabase();
}
@Override
protected JdbcConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {
return new OracleJdbcDockerComposeConnectionDetails(source.getRunningService(), this.defaultDatabase);
}
/**
* {@link JdbcConnectionDetails} backed by an {@code oracle-xe} or {@code oracle-free}
* {@link RunningService}.
*/
static class OracleJdbcDockerComposeConnectionDetails extends DockerComposeConnectionDetails
implements JdbcConnectionDetails {
private static final String PARAMETERS_LABEL = "org.springframework.boot.jdbc.parameters";
private final OracleEnvironment environment;
private final String jdbcUrl;
OracleJdbcDockerComposeConnectionDetails(RunningService service, String defaultDatabase) {
super(service);
this.environment = new OracleEnvironment(service.env(), defaultDatabase);
this.jdbcUrl = "jdbc:oracle:thin:@" + service.host() + ":" + service.ports().get(1521) + "/"
+ this.environment.getDatabase() + getParameters(service);
}
private String getParameters(RunningService service) {
String parameters = service.labels().get(PARAMETERS_LABEL);
return (StringUtils.hasLength(parameters)) ? "?" + parameters : "";
}
@Override
public String getUsername() {
return this.environment.getUsername();
}
@Override
public String getPassword() {
return this.environment.getPassword();
}
@Override
public String getJdbcUrl() {
return this.jdbcUrl;
}
}
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2012-2023 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.jdbc.docker.compose;
import org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;
import org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails;
/**
* {@link DockerComposeConnectionDetailsFactory} to create {@link JdbcConnectionDetails}
* for an {@link OracleContainer#XE} service.
*
* @author Andy Wilkinson
*/
class OracleXeJdbcDockerComposeConnectionDetailsFactory extends OracleJdbcDockerComposeConnectionDetailsFactory {
protected OracleXeJdbcDockerComposeConnectionDetailsFactory() {
super(OracleContainer.XE);
}
}

View File

@@ -0,0 +1,92 @@
/*
* Copyright 2012-2025 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.jdbc.docker.compose;
import java.util.Map;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Postgres environment details.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
* @author Scott Frederick
* @author Sidmar Theodoro
* @author He Zean
*/
class PostgresEnvironment {
private static final String[] USERNAME_KEYS = new String[] { "POSTGRES_USER", "POSTGRESQL_USER",
"POSTGRESQL_USERNAME" };
private static final String DEFAULT_USERNAME = "postgres";
private static final String[] DATABASE_KEYS = new String[] { "POSTGRES_DB", "POSTGRESQL_DB",
"POSTGRESQL_DATABASE" };
private final String username;
private final String password;
private final String database;
PostgresEnvironment(Map<String, String> env) {
this.username = extract(env, USERNAME_KEYS, DEFAULT_USERNAME);
this.password = extractPassword(env);
this.database = extract(env, DATABASE_KEYS, this.username);
}
private String extract(Map<String, String> env, String[] keys, String defaultValue) {
for (String key : keys) {
if (env.containsKey(key)) {
return env.get(key);
}
}
return defaultValue;
}
private String extractPassword(Map<String, String> env) {
if (isUsingTrustHostAuthMethod(env)) {
return null;
}
String password = env.getOrDefault("POSTGRES_PASSWORD", env.get("POSTGRESQL_PASSWORD"));
boolean allowEmpty = env.containsKey("ALLOW_EMPTY_PASSWORD");
Assert.state(allowEmpty || StringUtils.hasLength(password), "No PostgreSQL password found");
return (password != null) ? password : "";
}
private boolean isUsingTrustHostAuthMethod(Map<String, String> env) {
String hostAuthMethod = env.get("POSTGRES_HOST_AUTH_METHOD");
return "trust".equals(hostAuthMethod);
}
String getUsername() {
return this.username;
}
String getPassword() {
return this.password;
}
String getDatabase() {
return this.database;
}
}

View File

@@ -0,0 +1,109 @@
/*
* Copyright 2012-2025 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.jdbc.docker.compose;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
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.jdbc.autoconfigure.JdbcConnectionDetails;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;
/**
* {@link DockerComposeConnectionDetailsFactory} to create {@link JdbcConnectionDetails}
* for a {@code postgres} service.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
* @author Scott Frederick
*/
class PostgresJdbcDockerComposeConnectionDetailsFactory
extends DockerComposeConnectionDetailsFactory<JdbcConnectionDetails> {
private static final String[] POSTGRES_CONTAINER_NAMES = { "postgres", "bitnami/postgresql" };
protected PostgresJdbcDockerComposeConnectionDetailsFactory() {
super(POSTGRES_CONTAINER_NAMES);
}
@Override
protected JdbcConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {
return new PostgresJdbcDockerComposeConnectionDetails(source.getRunningService(), source.getEnvironment());
}
/**
* {@link JdbcConnectionDetails} backed by a {@code postgres} {@link RunningService}.
*/
static class PostgresJdbcDockerComposeConnectionDetails extends DockerComposeConnectionDetails
implements JdbcConnectionDetails {
private static final JdbcUrlBuilder jdbcUrlBuilder = new JdbcUrlBuilder("postgresql", 5432);
private final PostgresEnvironment environment;
private final String jdbcUrl;
PostgresJdbcDockerComposeConnectionDetails(RunningService service, Environment environment) {
super(service);
this.environment = new PostgresEnvironment(service.env());
this.jdbcUrl = addApplicationNameIfNecessary(jdbcUrlBuilder.build(service, this.environment.getDatabase()),
environment);
}
@Override
public String getUsername() {
return this.environment.getUsername();
}
@Override
public String getPassword() {
return this.environment.getPassword();
}
@Override
public String getJdbcUrl() {
return this.jdbcUrl;
}
private static String addApplicationNameIfNecessary(String jdbcUrl, Environment environment) {
if (jdbcUrl.contains("&ApplicationName=") || jdbcUrl.contains("?ApplicationName=")) {
return jdbcUrl;
}
String applicationName = environment.getProperty("spring.application.name");
if (!StringUtils.hasText(applicationName)) {
return jdbcUrl;
}
StringBuilder jdbcUrlBuilder = new StringBuilder(jdbcUrl);
if (!jdbcUrl.contains("?")) {
jdbcUrlBuilder.append("?");
}
else if (!jdbcUrl.endsWith("&")) {
jdbcUrlBuilder.append("&");
}
return jdbcUrlBuilder.append("ApplicationName")
.append('=')
.append(URLEncoder.encode(applicationName, StandardCharsets.UTF_8))
.toString();
}
}
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright 2012-2023 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.jdbc.docker.compose;
import java.util.Map;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* MS SQL Server environment details.
*
* @author Andy Wilkinson
*/
class SqlServerEnvironment {
private final String username = "SA";
private final String password;
SqlServerEnvironment(Map<String, String> env) {
this.password = extractPassword(env);
}
private String extractPassword(Map<String, String> env) {
String password = env.get("MSSQL_SA_PASSWORD");
password = (password != null) ? password : env.get("SA_PASSWORD");
Assert.state(StringUtils.hasLength(password), "No MSSQL password found");
return password;
}
String getUsername() {
return this.username;
}
String getPassword() {
return this.password;
}
}

View File

@@ -0,0 +1,103 @@
/*
* 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.jdbc.docker.compose;
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.jdbc.autoconfigure.JdbcConnectionDetails;
/**
* {@link DockerComposeConnectionDetailsFactory} to create {@link JdbcConnectionDetails}
* for a {@code mssql/server} service.
*
* @author Andy Wilkinson
*/
class SqlServerJdbcDockerComposeConnectionDetailsFactory
extends DockerComposeConnectionDetailsFactory<JdbcConnectionDetails> {
protected SqlServerJdbcDockerComposeConnectionDetailsFactory() {
super("mssql/server");
}
@Override
protected JdbcConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {
return new SqlServerJdbcDockerComposeConnectionDetails(source.getRunningService());
}
/**
* {@link JdbcConnectionDetails} backed by a {@code mssql/server}
* {@link RunningService}.
*/
static class SqlServerJdbcDockerComposeConnectionDetails extends DockerComposeConnectionDetails
implements JdbcConnectionDetails {
private static final JdbcUrlBuilder jdbcUrlBuilder = new SqlServerJdbcUrlBuilder("sqlserver", 1433);
private final SqlServerEnvironment environment;
private final String jdbcUrl;
SqlServerJdbcDockerComposeConnectionDetails(RunningService service) {
super(service);
this.environment = new SqlServerEnvironment(service.env());
this.jdbcUrl = disableEncryptionIfNecessary(jdbcUrlBuilder.build(service));
}
private String disableEncryptionIfNecessary(String jdbcUrl) {
if (jdbcUrl.contains(";encrypt=false;")) {
return jdbcUrl;
}
StringBuilder jdbcUrlBuilder = new StringBuilder(jdbcUrl);
if (!jdbcUrl.endsWith(";")) {
jdbcUrlBuilder.append(";");
}
jdbcUrlBuilder.append("encrypt=false;");
return jdbcUrlBuilder.toString();
}
@Override
public String getUsername() {
return this.environment.getUsername();
}
@Override
public String getPassword() {
return this.environment.getPassword();
}
@Override
public String getJdbcUrl() {
return this.jdbcUrl;
}
private static final class SqlServerJdbcUrlBuilder extends JdbcUrlBuilder {
private SqlServerJdbcUrlBuilder(String driverProtocol, int containerPort) {
super(driverProtocol, containerPort);
}
@Override
protected void appendParameters(StringBuilder url, String parameters) {
url.append(";").append(parameters);
}
}
}
}

View File

@@ -0,0 +1,20 @@
/*
* Copyright 2012-2023 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.
*/
/**
* Support for Docker Compose JDBC service connections.
*/
package org.springframework.boot.jdbc.docker.compose;

View File

@@ -5,6 +5,13 @@ org.springframework.boot.jdbc.autoconfigure.HikariDriverConfigurationFailureAnal
# Connection Details Factories
org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactory=\
org.springframework.boot.jdbc.docker.compose.ClickHouseJdbcDockerComposeConnectionDetailsFactory,\
org.springframework.boot.jdbc.docker.compose.MariaDbJdbcDockerComposeConnectionDetailsFactory,\
org.springframework.boot.jdbc.docker.compose.MySqlJdbcDockerComposeConnectionDetailsFactory,\
org.springframework.boot.jdbc.docker.compose.OracleFreeJdbcDockerComposeConnectionDetailsFactory,\
org.springframework.boot.jdbc.docker.compose.OracleXeJdbcDockerComposeConnectionDetailsFactory,\
org.springframework.boot.jdbc.docker.compose.PostgresJdbcDockerComposeConnectionDetailsFactory,\
org.springframework.boot.jdbc.docker.compose.SqlServerJdbcDockerComposeConnectionDetailsFactory,\
org.springframework.boot.jdbc.testcontainers.JdbcContainerConnectionDetailsFactory
# Database Initializer Detectors

View File

@@ -0,0 +1,84 @@
/*
* Copyright 2012-2025 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.jdbc.docker.compose;
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 ClickHouseEnvironment}.
*
* @author Stephane Nicoll
*/
class ClickHouseEnvironmentTests {
@Test
void createWhenNoPasswordThrowsException() {
assertThatIllegalStateException().isThrownBy(() -> new ClickHouseEnvironment(Collections.emptyMap()))
.withMessage("No ClickHouse password found");
}
@Test
void getPasswordWhenHasPassword() {
ClickHouseEnvironment environment = new ClickHouseEnvironment(Map.of("CLICKHOUSE_PASSWORD", "secret"));
assertThat(environment.getPassword()).isEqualTo("secret");
}
@Test
void getPasswordWhenHasNoPasswordAndAllowEmptyPassword() {
ClickHouseEnvironment environment = new ClickHouseEnvironment(Map.of("ALLOW_EMPTY_PASSWORD", "true"));
assertThat(environment.getPassword()).isEmpty();
}
@Test
void getPasswordWhenHasNoPasswordAndAllowEmptyPasswordIsYes() {
ClickHouseEnvironment environment = new ClickHouseEnvironment(Map.of("ALLOW_EMPTY_PASSWORD", "yes"));
assertThat(environment.getPassword()).isEmpty();
}
@Test
void getUsernameWhenNoUser() {
ClickHouseEnvironment environment = new ClickHouseEnvironment(Map.of("CLICKHOUSE_PASSWORD", "secret"));
assertThat(environment.getUsername()).isEqualTo("default");
}
@Test
void getUsernameWhenHasUser() {
ClickHouseEnvironment environment = new ClickHouseEnvironment(
Map.of("CLICKHOUSE_USER", "me", "CLICKHOUSE_PASSWORD", "secret"));
assertThat(environment.getUsername()).isEqualTo("me");
}
@Test
void getDatabaseWhenNoDatabase() {
ClickHouseEnvironment environment = new ClickHouseEnvironment(Map.of("CLICKHOUSE_PASSWORD", "secret"));
assertThat(environment.getDatabase()).isEqualTo("default");
}
@Test
void getDatabaseWhenHasDatabase() {
ClickHouseEnvironment environment = new ClickHouseEnvironment(
Map.of("CLICKHOUSE_DB", "db", "CLICKHOUSE_PASSWORD", "secret"));
assertThat(environment.getDatabase()).isEqualTo("db");
}
}

View File

@@ -0,0 +1,104 @@
/*
* Copyright 2012-2025 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.jdbc.docker.compose;
import java.util.Collections;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.springframework.boot.docker.compose.core.ConnectionPorts;
import org.springframework.boot.docker.compose.core.RunningService;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link JdbcUrlBuilder}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class JdbcUrlBuilderTests {
private JdbcUrlBuilder builder = new JdbcUrlBuilder("mydb", 1234);
@Test
void createWhenDriverProtocolIsNullThrowsException() {
assertThatIllegalArgumentException().isThrownBy(() -> new JdbcUrlBuilder(null, 123))
.withMessage("'driverProtocol' must not be null");
}
@Test
void buildBuildsUrlForService() {
RunningService service = mockService(456);
String url = this.builder.build(service);
assertThat(url).isEqualTo("jdbc:mydb://myhost:456");
}
@Test
void buildBuildsUrlForServiceAndDatabase() {
RunningService service = mockService(456);
String url = this.builder.build(service, "mydb");
assertThat(url).isEqualTo("jdbc:mydb://myhost:456/mydb");
}
@Test
void buildWhenHasParamsLabelBuildsUrl() {
RunningService service = mockService(456, Map.of("org.springframework.boot.jdbc.parameters", "foo=bar"));
String url = this.builder.build(service, "mydb");
assertThat(url).isEqualTo("jdbc:mydb://myhost:456/mydb?foo=bar");
}
@Test
void buildWithCustomAppendParametersWhenHasParamsLabelBuildsUrl() {
RunningService service = mockService(456, Map.of("org.springframework.boot.jdbc.parameters", "foo=bar"));
String url = new JdbcUrlBuilder("mydb", 1234) {
@Override
protected void appendParameters(StringBuilder url, String parameters) {
url.append(";").append(parameters);
}
}.build(service, "mydb");
assertThat(url).isEqualTo("jdbc:mydb://myhost:456/mydb;foo=bar");
}
@Test
void buildWhenServiceIsNullThrowsException() {
assertThatIllegalArgumentException().isThrownBy(() -> this.builder.build(null, "mydb"))
.withMessage("'service' must not be null");
}
private RunningService mockService(int mappedPort) {
return mockService(mappedPort, Collections.emptyMap());
}
private RunningService mockService(int mappedPort, Map<String, String> labels) {
RunningService service = mock(RunningService.class);
ConnectionPorts ports = mock(ConnectionPorts.class);
given(ports.get(1234)).willReturn(mappedPort);
given(service.host()).willReturn("myhost");
given(service.ports()).willReturn(ports);
given(service.labels()).willReturn(labels);
return service;
}
}

View File

@@ -0,0 +1,176 @@
/*
* 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.jdbc.docker.compose;
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 MariaDbEnvironment}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
* @author Jinseong Hwang
* @author Scott Frederick
*/
class MariaDbEnvironmentTests {
@Test
void createWhenHasMariadbRandomRootPasswordThrowsException() {
assertThatIllegalStateException()
.isThrownBy(() -> new MariaDbEnvironment(Map.of("MARIADB_RANDOM_ROOT_PASSWORD", "true")))
.withMessage("MARIADB_RANDOM_ROOT_PASSWORD is not supported");
}
@Test
void createWhenHasMysqlRandomRootPasswordThrowsException() {
assertThatIllegalStateException()
.isThrownBy(() -> new MariaDbEnvironment(Map.of("MYSQL_RANDOM_ROOT_PASSWORD", "true")))
.withMessage("MYSQL_RANDOM_ROOT_PASSWORD is not supported");
}
@Test
void createWhenHasMariadbRootPasswordHashThrowsException() {
assertThatIllegalStateException()
.isThrownBy(() -> new MariaDbEnvironment(Map.of("MARIADB_ROOT_PASSWORD_HASH", "0FF")))
.withMessage("MARIADB_ROOT_PASSWORD_HASH is not supported");
}
@Test
void createWhenHasNoPasswordThrowsException() {
assertThatIllegalStateException().isThrownBy(() -> new MariaDbEnvironment(Collections.emptyMap()))
.withMessage("No MariaDB password found");
}
@Test
void createWhenHasNoDatabaseThrowsException() {
assertThatIllegalStateException().isThrownBy(() -> new MariaDbEnvironment(Map.of("MARIADB_PASSWORD", "secret")))
.withMessage("No MARIADB_DATABASE defined");
}
@Test
void getUsernameWhenHasMariadbUser() {
MariaDbEnvironment environment = new MariaDbEnvironment(
Map.of("MARIADB_USER", "myself", "MARIADB_PASSWORD", "secret", "MARIADB_DATABASE", "db"));
assertThat(environment.getUsername()).isEqualTo("myself");
}
@Test
void getUsernameWhenHasMysqlUser() {
MariaDbEnvironment environment = new MariaDbEnvironment(
Map.of("MYSQL_USER", "myself", "MARIADB_PASSWORD", "secret", "MARIADB_DATABASE", "db"));
assertThat(environment.getUsername()).isEqualTo("myself");
}
@Test
void getUsernameWhenHasMariadbUserAndMysqlUser() {
MariaDbEnvironment environment = new MariaDbEnvironment(Map.of("MARIADB_USER", "myself", "MYSQL_USER", "me",
"MARIADB_PASSWORD", "secret", "MARIADB_DATABASE", "db"));
assertThat(environment.getUsername()).isEqualTo("myself");
}
@Test
void getUsernameWhenHasNoMariadbUserOrMysqlUser() {
MariaDbEnvironment environment = new MariaDbEnvironment(
Map.of("MARIADB_PASSWORD", "secret", "MARIADB_DATABASE", "db"));
assertThat(environment.getUsername()).isEqualTo("root");
}
@Test
void getPasswordWhenHasMariadbPassword() {
MariaDbEnvironment environment = new MariaDbEnvironment(
Map.of("MARIADB_PASSWORD", "secret", "MARIADB_DATABASE", "db"));
assertThat(environment.getPassword()).isEqualTo("secret");
}
@Test
void getPasswordWhenHasMysqlPassword() {
MariaDbEnvironment environment = new MariaDbEnvironment(
Map.of("MYSQL_PASSWORD", "secret", "MARIADB_DATABASE", "db"));
assertThat(environment.getPassword()).isEqualTo("secret");
}
@Test
void getPasswordWhenHasMysqlRootPassword() {
MariaDbEnvironment environment = new MariaDbEnvironment(
Map.of("MYSQL_ROOT_PASSWORD", "secret", "MARIADB_DATABASE", "db"));
assertThat(environment.getPassword()).isEqualTo("secret");
}
@Test
void getPasswordWhenHasMariadbPasswordAndMysqlPassword() {
MariaDbEnvironment environment = new MariaDbEnvironment(
Map.of("MARIADB_PASSWORD", "secret", "MYSQL_PASSWORD", "donttell", "MARIADB_DATABASE", "db"));
assertThat(environment.getPassword()).isEqualTo("secret");
}
@Test
void getPasswordWhenHasMariadbPasswordAndMysqlRootPassword() {
MariaDbEnvironment environment = new MariaDbEnvironment(
Map.of("MARIADB_PASSWORD", "secret", "MYSQL_ROOT_PASSWORD", "donttell", "MARIADB_DATABASE", "db"));
assertThat(environment.getPassword()).isEqualTo("secret");
}
@Test
void getPasswordWhenHasNoPasswordAndAllowEmptyPassword() {
MariaDbEnvironment environment = new MariaDbEnvironment(
Map.of("ALLOW_EMPTY_PASSWORD", "true", "MARIADB_DATABASE", "db"));
assertThat(environment.getPassword()).isEmpty();
}
@Test
void getPasswordWhenHasNoPasswordAndMariadbAllowEmptyPassword() {
MariaDbEnvironment environment = new MariaDbEnvironment(
Map.of("MARIADB_ALLOW_EMPTY_PASSWORD", "true", "MARIADB_DATABASE", "db"));
assertThat(environment.getPassword()).isEmpty();
}
@Test
void getPasswordWhenHasNoPasswordAndMysqlAllowEmptyPassword() {
MariaDbEnvironment environment = new MariaDbEnvironment(
Map.of("MYSQL_ALLOW_EMPTY_PASSWORD", "true", "MARIADB_DATABASE", "db"));
assertThat(environment.getPassword()).isEmpty();
}
@Test
void getDatabaseWhenHasMariadbDatabase() {
MariaDbEnvironment environment = new MariaDbEnvironment(
Map.of("MARIADB_ALLOW_EMPTY_PASSWORD", "true", "MARIADB_DATABASE", "db"));
assertThat(environment.getDatabase()).isEqualTo("db");
}
@Test
void getDatabaseWhenHasMysqlDatabase() {
MariaDbEnvironment environment = new MariaDbEnvironment(
Map.of("MARIADB_ALLOW_EMPTY_PASSWORD", "true", "MYSQL_DATABASE", "db"));
assertThat(environment.getDatabase()).isEqualTo("db");
}
@Test
void getDatabaseWhenHasMariadbAndMysqlDatabase() {
MariaDbEnvironment environment = new MariaDbEnvironment(
Map.of("MARIADB_ALLOW_EMPTY_PASSWORD", "true", "MARIADB_DATABASE", "db", "MYSQL_DATABASE", "otherdb"));
assertThat(environment.getDatabase()).isEqualTo("db");
}
}

View File

@@ -0,0 +1,104 @@
/*
* 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.jdbc.docker.compose;
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 MySqlEnvironment}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
* @author Jinseong Hwang
* @author Scott Frederick
*/
class MySqlEnvironmentTests {
@Test
void createWhenHasMysqlRandomRootPasswordThrowsException() {
assertThatIllegalStateException()
.isThrownBy(() -> new MySqlEnvironment(Map.of("MYSQL_RANDOM_ROOT_PASSWORD", "true")))
.withMessage("MYSQL_RANDOM_ROOT_PASSWORD is not supported");
}
@Test
void createWhenHasNoPasswordThrowsException() {
assertThatIllegalStateException().isThrownBy(() -> new MySqlEnvironment(Collections.emptyMap()))
.withMessage("No MySQL password found");
}
@Test
void createWhenHasNoDatabaseThrowsException() {
assertThatIllegalStateException().isThrownBy(() -> new MySqlEnvironment(Map.of("MYSQL_PASSWORD", "secret")))
.withMessage("No MYSQL_DATABASE defined");
}
@Test
void getUsernameWhenHasMysqlUser() {
MySqlEnvironment environment = new MySqlEnvironment(
Map.of("MYSQL_USER", "myself", "MYSQL_PASSWORD", "secret", "MYSQL_DATABASE", "db"));
assertThat(environment.getUsername()).isEqualTo("myself");
}
@Test
void getUsernameWhenHasNoMysqlUser() {
MySqlEnvironment environment = new MySqlEnvironment(Map.of("MYSQL_PASSWORD", "secret", "MYSQL_DATABASE", "db"));
assertThat(environment.getUsername()).isEqualTo("root");
}
@Test
void getPasswordWhenHasMysqlPassword() {
MySqlEnvironment environment = new MySqlEnvironment(Map.of("MYSQL_PASSWORD", "secret", "MYSQL_DATABASE", "db"));
assertThat(environment.getPassword()).isEqualTo("secret");
}
@Test
void getPasswordWhenHasMysqlRootPassword() {
MySqlEnvironment environment = new MySqlEnvironment(
Map.of("MYSQL_ROOT_PASSWORD", "secret", "MYSQL_DATABASE", "db"));
assertThat(environment.getPassword()).isEqualTo("secret");
}
@Test
void getPasswordWhenHasNoPasswordAndMysqlAllowEmptyPassword() {
MySqlEnvironment environment = new MySqlEnvironment(
Map.of("MYSQL_ALLOW_EMPTY_PASSWORD", "true", "MYSQL_DATABASE", "db"));
assertThat(environment.getPassword()).isEmpty();
}
@Test
void getPasswordWhenHasNoPasswordAndAllowEmptyPassword() {
MySqlEnvironment environment = new MySqlEnvironment(
Map.of("ALLOW_EMPTY_PASSWORD", "true", "MYSQL_DATABASE", "db"));
assertThat(environment.getPassword()).isEmpty();
}
@Test
void getDatabaseWhenHasMysqlDatabase() {
MySqlEnvironment environment = new MySqlEnvironment(
Map.of("MYSQL_ALLOW_EMPTY_PASSWORD", "true", "MYSQL_DATABASE", "db"));
assertThat(environment.getDatabase()).isEqualTo("db");
}
}

View File

@@ -0,0 +1,115 @@
/*
* Copyright 2012-2023 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.jdbc.docker.compose;
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;
import static org.assertj.core.api.Assertions.assertThatNoException;
/**
* Tests for {@link OracleEnvironment}.
*
* @author Andy Wilkinson
*/
class OracleEnvironmentTests {
@Test
void getUsernameWhenHasAppUser() {
OracleEnvironment environment = new OracleEnvironment(
Map.of("APP_USER", "alice", "APP_USER_PASSWORD", "secret"), "defaultDb");
assertThat(environment.getUsername()).isEqualTo("alice");
}
@Test
void getUsernameWhenHasNoAppUser() {
OracleEnvironment environment = new OracleEnvironment(Map.of("ORACLE_PASSWORD", "secret"), "defaultDb");
assertThat(environment.getUsername()).isEqualTo("system");
}
@Test
void getPasswordWhenHasAppPassword() {
OracleEnvironment environment = new OracleEnvironment(
Map.of("APP_USER", "alice", "APP_USER_PASSWORD", "secret"), "defaultDb");
assertThat(environment.getPassword()).isEqualTo("secret");
}
@Test
void getPasswordWhenHasOraclePassword() {
OracleEnvironment environment = new OracleEnvironment(Map.of("ORACLE_PASSWORD", "secret"), "defaultDb");
assertThat(environment.getPassword()).isEqualTo("secret");
}
@Test
void createWhenRandomPasswordAndAppPasswordDoesNotThrow() {
assertThatNoException().isThrownBy(() -> new OracleEnvironment(
Map.of("APP_USER", "alice", "APP_USER_PASSWORD", "secret", "ORACLE_RANDOM_PASSWORD", "true"),
"defaultDb"));
}
@Test
void createWhenRandomPasswordThrowsException() {
assertThatIllegalStateException()
.isThrownBy(() -> new OracleEnvironment(Map.of("ORACLE_RANDOM_PASSWORD", "true"), "defaultDb"))
.withMessage("ORACLE_RANDOM_PASSWORD is not supported without APP_USER and APP_USER_PASSWORD");
}
@Test
void createWhenAppUserAndNoAppPasswordThrowsException() {
assertThatIllegalStateException()
.isThrownBy(() -> new OracleEnvironment(Map.of("APP_USER", "alice"), "defaultDb"))
.withMessage("No Oracle app password found");
}
@Test
void createWhenAppUserAndEmptyAppPasswordThrowsException() {
assertThatIllegalStateException()
.isThrownBy(() -> new OracleEnvironment(Map.of("APP_USER", "alice", "APP_USER_PASSWORD", ""), "defaultDb"))
.withMessage("No Oracle app password found");
}
@Test
void createWhenHasNoPasswordThrowsException() {
assertThatIllegalStateException().isThrownBy(() -> new OracleEnvironment(Collections.emptyMap(), "defaultDb"))
.withMessage("No Oracle password found");
}
@Test
void createWhenHasEmptyPasswordThrowsException() {
assertThatIllegalStateException()
.isThrownBy(() -> new OracleEnvironment(Map.of("ORACLE_PASSWORD", ""), "defaultDb"))
.withMessage("No Oracle password found");
}
@Test
void getDatabaseWhenHasNoOracleDatabase() {
OracleEnvironment environment = new OracleEnvironment(Map.of("ORACLE_PASSWORD", "secret"), "defaultDb");
assertThat(environment.getDatabase()).isEqualTo("defaultDb");
}
@Test
void getDatabaseWhenHasOracleDatabase() {
OracleEnvironment environment = new OracleEnvironment(
Map.of("ORACLE_PASSWORD", "secret", "ORACLE_DATABASE", "db"), "defaultDb");
assertThat(environment.getDatabase()).isEqualTo("db");
}
}

View File

@@ -0,0 +1,156 @@
/*
* Copyright 2012-2025 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.jdbc.docker.compose;
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 PostgresEnvironment}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
* @author Scott Frederick
* @author Sidmar Theodoro
* @author He Zean
*/
class PostgresEnvironmentTests {
@Test
void createWhenNoPostgresPasswordThrowsException() {
assertThatIllegalStateException().isThrownBy(() -> new PostgresEnvironment(Collections.emptyMap()))
.withMessage("No PostgreSQL password found");
}
@Test
void getUsernameWhenNoPostgresUser() {
PostgresEnvironment environment = new PostgresEnvironment(Map.of("POSTGRES_PASSWORD", "secret"));
assertThat(environment.getUsername()).isEqualTo("postgres");
}
@Test
void getUsernameWhenNoPostgresqlUser() {
PostgresEnvironment environment = new PostgresEnvironment(Map.of("POSTGRESQL_PASSWORD", "secret"));
assertThat(environment.getUsername()).isEqualTo("postgres");
}
@Test
void getUsernameWhenHasPostgresUser() {
PostgresEnvironment environment = new PostgresEnvironment(
Map.of("POSTGRES_USER", "me", "POSTGRES_PASSWORD", "secret"));
assertThat(environment.getUsername()).isEqualTo("me");
}
@Test
void getUsernameWhenHasPostgresqlUser() {
PostgresEnvironment environment = new PostgresEnvironment(
Map.of("POSTGRESQL_USER", "me", "POSTGRESQL_PASSWORD", "secret"));
assertThat(environment.getUsername()).isEqualTo("me");
}
@Test
void getUsernameWhenHasPostgresqlUsername() {
PostgresEnvironment environment = new PostgresEnvironment(
Map.of("POSTGRESQL_USERNAME", "me", "POSTGRESQL_PASSWORD", "secret"));
assertThat(environment.getUsername()).isEqualTo("me");
}
@Test
void getPasswordWhenHasPostgresPassword() {
PostgresEnvironment environment = new PostgresEnvironment(Map.of("POSTGRES_PASSWORD", "secret"));
assertThat(environment.getPassword()).isEqualTo("secret");
}
@Test
void getPasswordWhenHasPostgresqlPassword() {
PostgresEnvironment environment = new PostgresEnvironment(Map.of("POSTGRESQL_PASSWORD", "secret"));
assertThat(environment.getPassword()).isEqualTo("secret");
}
@Test
void getPasswordWhenHasTrustHostAuthMethod() {
PostgresEnvironment environment = new PostgresEnvironment(Map.of("POSTGRES_HOST_AUTH_METHOD", "trust"));
assertThat(environment.getPassword()).isNull();
}
@Test
void getPasswordWhenHasNoPasswordAndAllowEmptyPassword() {
PostgresEnvironment environment = new PostgresEnvironment(Map.of("ALLOW_EMPTY_PASSWORD", "yes"));
assertThat(environment.getPassword()).isEmpty();
}
@Test
void getDatabaseWhenNoPostgresDbOrPostgresUser() {
PostgresEnvironment environment = new PostgresEnvironment(Map.of("POSTGRES_PASSWORD", "secret"));
assertThat(environment.getDatabase()).isEqualTo("postgres");
}
@Test
void getDatabaseWhenNoPostgresqlDbOrPostgresUser() {
PostgresEnvironment environment = new PostgresEnvironment(Map.of("POSTGRESQL_PASSWORD", "secret"));
assertThat(environment.getDatabase()).isEqualTo("postgres");
}
@Test
void getDatabaseWhenNoPostgresDbAndPostgresUser() {
PostgresEnvironment environment = new PostgresEnvironment(
Map.of("POSTGRES_USER", "me", "POSTGRES_PASSWORD", "secret"));
assertThat(environment.getDatabase()).isEqualTo("me");
}
@Test
void getDatabaseWhenNoPostgresqlDbAndPostgresUser() {
PostgresEnvironment environment = new PostgresEnvironment(
Map.of("POSTGRESQL_USER", "me", "POSTGRESQL_PASSWORD", "secret"));
assertThat(environment.getDatabase()).isEqualTo("me");
}
@Test
void getDatabaseWhenNoPostgresqlDatabaseAndPostgresqlUsername() {
PostgresEnvironment environment = new PostgresEnvironment(
Map.of("POSTGRESQL_USERNAME", "me", "POSTGRESQL_PASSWORD", "secret"));
assertThat(environment.getDatabase()).isEqualTo("me");
}
@Test
void getDatabaseWhenHasPostgresDb() {
PostgresEnvironment environment = new PostgresEnvironment(
Map.of("POSTGRES_DB", "db", "POSTGRES_PASSWORD", "secret"));
assertThat(environment.getDatabase()).isEqualTo("db");
}
@Test
void getDatabaseWhenHasPostgresqlDb() {
PostgresEnvironment environment = new PostgresEnvironment(
Map.of("POSTGRESQL_DB", "db", "POSTGRESQL_PASSWORD", "secret"));
assertThat(environment.getDatabase()).isEqualTo("db");
}
@Test
void getDatabaseWhenHasPostgresqlDatabase() {
PostgresEnvironment environment = new PostgresEnvironment(
Map.of("POSTGRESQL_DATABASE", "db", "POSTGRESQL_PASSWORD", "secret"));
assertThat(environment.getDatabase()).isEqualTo("db");
}
}

View File

@@ -0,0 +1,120 @@
/*
* Copyright 2012-2025 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.jdbc.docker.compose;
import java.util.LinkedHashMap;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.springframework.boot.docker.compose.core.ConnectionPorts;
import org.springframework.boot.docker.compose.core.RunningService;
import org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails;
import org.springframework.mock.env.MockEnvironment;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
/**
* Tests for
* {@link PostgresJdbcDockerComposeConnectionDetailsFactory.PostgresJdbcDockerComposeConnectionDetails}.
*
* @author Dmytro Nosan
*/
class PostgresJdbcDockerComposeConnectionDetailsFactoryConnectionDetailsTests {
private final RunningService service = mock(RunningService.class);
private final MockEnvironment environment = new MockEnvironment();
private final Map<String, String> labels = new LinkedHashMap<>();
PostgresJdbcDockerComposeConnectionDetailsFactoryConnectionDetailsTests() {
given(this.service.env())
.willReturn(Map.of("POSTGRES_USER", "user", "POSTGRES_PASSWORD", "password", "POSTGRES_DB", "database"));
given(this.service.labels()).willReturn(this.labels);
ConnectionPorts connectionPorts = mock(ConnectionPorts.class);
given(this.service.ports()).willReturn(connectionPorts);
given(this.service.host()).willReturn("localhost");
given(connectionPorts.get(5432)).willReturn(30001);
}
@Test
void createConnectionDetails() {
JdbcConnectionDetails connectionDetails = getConnectionDetails();
assertConnectionDetails(connectionDetails);
assertThat(connectionDetails.getJdbcUrl()).endsWith("/database");
}
@Test
void createConnectionDetailsWithLabels() {
this.labels.put("org.springframework.boot.jdbc.parameters", "connectTimeout=30&ApplicationName=spring-boot");
JdbcConnectionDetails connectionDetails = getConnectionDetails();
assertConnectionDetails(connectionDetails);
assertThat(connectionDetails.getJdbcUrl()).endsWith("?connectTimeout=30&ApplicationName=spring-boot");
}
@Test
void createConnectionDetailsWithApplicationNameLabelTakesPrecedence() {
this.labels.put("org.springframework.boot.jdbc.parameters", "ApplicationName=spring-boot");
this.environment.setProperty("spring.application.name", "my-app");
JdbcConnectionDetails connectionDetails = getConnectionDetails();
assertConnectionDetails(connectionDetails);
assertThat(connectionDetails.getJdbcUrl()).endsWith("?ApplicationName=spring-boot");
}
@Test
void createConnectionDetailsWithSpringApplicationName() {
this.environment.setProperty("spring.application.name", "spring boot");
JdbcConnectionDetails connectionDetails = getConnectionDetails();
assertConnectionDetails(connectionDetails);
assertThat(connectionDetails.getJdbcUrl()).endsWith("?ApplicationName=spring+boot");
}
@Test
void createConnectionDetailsAppendSpringApplicationName() {
this.labels.put("org.springframework.boot.jdbc.parameters", "connectTimeout=30");
this.environment.setProperty("spring.application.name", "spring boot");
JdbcConnectionDetails connectionDetails = getConnectionDetails();
assertConnectionDetails(connectionDetails);
assertThat(connectionDetails.getJdbcUrl()).endsWith("?connectTimeout=30&ApplicationName=spring+boot");
}
@Test
void createConnectionDetailsAppendSpringApplicationNameParametersEndedWithAmpersand() {
this.labels.put("org.springframework.boot.jdbc.parameters", "connectTimeout=30&");
this.environment.setProperty("spring.application.name", "spring boot");
JdbcConnectionDetails connectionDetails = getConnectionDetails();
assertConnectionDetails(connectionDetails);
assertThat(connectionDetails.getJdbcUrl()).endsWith("?connectTimeout=30&ApplicationName=spring+boot");
}
private void assertConnectionDetails(JdbcConnectionDetails connectionDetails) {
assertThat(connectionDetails.getUsername()).isEqualTo("user");
assertThat(connectionDetails.getPassword()).isEqualTo("password");
assertThat(connectionDetails.getJdbcUrl()).startsWith("jdbc:postgresql://localhost:30001/database");
assertThat(connectionDetails.getDriverClassName()).isEqualTo("org.postgresql.Driver");
}
private JdbcConnectionDetails getConnectionDetails() {
return new PostgresJdbcDockerComposeConnectionDetailsFactory.PostgresJdbcDockerComposeConnectionDetails(
this.service, this.environment);
}
}

View File

@@ -0,0 +1,65 @@
/*
* Copyright 2012-2023 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.jdbc.docker.compose;
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 SqlServerEnvironment}.
*
* @author Andy Wilkinson
*/
class SqlServerEnvironmentTests {
@Test
void createWhenHasNoPasswordThrowsException() {
assertThatIllegalStateException().isThrownBy(() -> new SqlServerEnvironment(Collections.emptyMap()))
.withMessage("No MSSQL password found");
}
@Test
void getUsernameWhenHasNoMsSqlUser() {
SqlServerEnvironment environment = new SqlServerEnvironment(Map.of("MSSQL_SA_PASSWORD", "secret"));
assertThat(environment.getUsername()).isEqualTo("SA");
}
@Test
void getPasswordWhenHasMsSqlSaPassword() {
SqlServerEnvironment environment = new SqlServerEnvironment(Map.of("MSSQL_SA_PASSWORD", "secret"));
assertThat(environment.getPassword()).isEqualTo("secret");
}
@Test
void getPasswordWhenHasSaPassword() {
SqlServerEnvironment environment = new SqlServerEnvironment(Map.of("SA_PASSWORD", "secret"));
assertThat(environment.getPassword()).isEqualTo("secret");
}
@Test
void getPasswordWhenHasMsSqlSaPasswordAndSaPasswordPrefersMsSqlSaPassword() {
SqlServerEnvironment environment = new SqlServerEnvironment(
Map.of("MSSQL_SA_PASSWORD", "secret", "SA_PASSWORD", "not used"));
assertThat(environment.getPassword()).isEqualTo("secret");
}
}