diff --git a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/service/connection/sqlserver/MsSqlServerEnvironment.java b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/service/connection/sqlserver/MsSqlServerEnvironment.java new file mode 100644 index 00000000000..b895efbe6e8 --- /dev/null +++ b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/service/connection/sqlserver/MsSqlServerEnvironment.java @@ -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.docker.compose.service.connection.sqlserver; + +import java.util.Map; + +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +/** + * MS SQL Server environment details. + * + * @author Andy Wilkinson + */ +class MsSqlServerEnvironment { + + private final String username = "SA"; + + private final String password; + + MsSqlServerEnvironment(Map env) { + this.password = extractPassword(env); + } + + private String extractPassword(Map 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; + } + +} diff --git a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/service/connection/sqlserver/MsSqlServerR2dbcDockerComposeConnectionDetailsFactory.java b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/service/connection/sqlserver/MsSqlServerR2dbcDockerComposeConnectionDetailsFactory.java new file mode 100644 index 00000000000..5cfaf28c0da --- /dev/null +++ b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/service/connection/sqlserver/MsSqlServerR2dbcDockerComposeConnectionDetailsFactory.java @@ -0,0 +1,72 @@ +/* + * 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.docker.compose.service.connection.sqlserver; + +import io.r2dbc.spi.ConnectionFactoryOptions; + +import org.springframework.boot.autoconfigure.r2dbc.R2dbcConnectionDetails; +import org.springframework.boot.docker.compose.core.RunningService; +import org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory; +import org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource; +import org.springframework.boot.docker.compose.service.connection.r2dbc.ConnectionFactoryOptionsBuilder; + +/** + * {@link DockerComposeConnectionDetailsFactory} to create {@link R2dbcConnectionDetails} + * for a {@code mssql} service. + * + * @author Moritz Halbritter + * @author Andy Wilkinson + * @author Phillip Webb + */ +class MsSqlServerR2dbcDockerComposeConnectionDetailsFactory + extends DockerComposeConnectionDetailsFactory { + + MsSqlServerR2dbcDockerComposeConnectionDetailsFactory() { + super("mssql/server", "io.r2dbc.spi.ConnectionFactoryOptions"); + } + + @Override + protected R2dbcConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) { + return new MsSqlR2dbcDockerComposeConnectionDetails(source.getRunningService()); + } + + /** + * {@link R2dbcConnectionDetails} backed by a {@code mssql} {@link RunningService}. + */ + static class MsSqlR2dbcDockerComposeConnectionDetails extends DockerComposeConnectionDetails + implements R2dbcConnectionDetails { + + private static final ConnectionFactoryOptionsBuilder connectionFactoryOptionsBuilder = new ConnectionFactoryOptionsBuilder( + "mssql", 1433); + + private final ConnectionFactoryOptions connectionFactoryOptions; + + MsSqlR2dbcDockerComposeConnectionDetails(RunningService service) { + super(service); + MsSqlServerEnvironment environment = new MsSqlServerEnvironment(service.env()); + this.connectionFactoryOptions = connectionFactoryOptionsBuilder.build(service, "", + environment.getUsername(), environment.getPassword()); + } + + @Override + public ConnectionFactoryOptions getConnectionFactoryOptions() { + return this.connectionFactoryOptions; + } + + } + +} diff --git a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/service/connection/sqlserver/package-info.java b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/service/connection/sqlserver/package-info.java new file mode 100644 index 00000000000..adff96befd7 --- /dev/null +++ b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/service/connection/sqlserver/package-info.java @@ -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. + */ + +/** + * Auto-configuration for docker compose MS SQL Server service connections. + */ +package org.springframework.boot.docker.compose.service.connection.sqlserver; diff --git a/spring-boot-project/spring-boot-docker-compose/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-docker-compose/src/main/resources/META-INF/spring.factories index 686a604b9ab..c0ca1bb615c 100644 --- a/spring-boot-project/spring-boot-docker-compose/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-docker-compose/src/main/resources/META-INF/spring.factories @@ -15,4 +15,5 @@ org.springframework.boot.docker.compose.service.connection.postgres.PostgresJdbc org.springframework.boot.docker.compose.service.connection.postgres.PostgresR2dbcDockerComposeConnectionDetailsFactory,\ org.springframework.boot.docker.compose.service.connection.rabbit.RabbitDockerComposeConnectionDetailsFactory,\ org.springframework.boot.docker.compose.service.connection.redis.RedisDockerComposeConnectionDetailsFactory,\ +org.springframework.boot.docker.compose.service.connection.sqlserver.MsSqlServerR2dbcDockerComposeConnectionDetailsFactory,\ org.springframework.boot.docker.compose.service.connection.zipkin.ZipkinDockerComposeConnectionDetailsFactory diff --git a/spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/service/connection/sqlserver/MsSqlServerEnvironmentTests.java b/spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/service/connection/sqlserver/MsSqlServerEnvironmentTests.java new file mode 100644 index 00000000000..cd6b63b224a --- /dev/null +++ b/spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/service/connection/sqlserver/MsSqlServerEnvironmentTests.java @@ -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.docker.compose.service.connection.sqlserver; + +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 MsSqlServerEnvironment}. + * + * @author Andy Wilkinson + */ +class MsSqlServerEnvironmentTests { + + @Test + void createWhenHasNoPasswordThrowsException() { + assertThatIllegalStateException().isThrownBy(() -> new MsSqlServerEnvironment(Collections.emptyMap())) + .withMessage("No MSSQL password found"); + } + + @Test + void getUsernameWhenHasNoMsSqlUser() { + MsSqlServerEnvironment environment = new MsSqlServerEnvironment(Map.of("MSSQL_SA_PASSWORD", "secret")); + assertThat(environment.getUsername()).isEqualTo("SA"); + } + + @Test + void getPasswordWhenHasMsSqlSaPassword() { + MsSqlServerEnvironment environment = new MsSqlServerEnvironment(Map.of("MSSQL_SA_PASSWORD", "secret")); + assertThat(environment.getPassword()).isEqualTo("secret"); + } + + @Test + void getPasswordWhenHasSaPassword() { + MsSqlServerEnvironment environment = new MsSqlServerEnvironment(Map.of("SA_PASSWORD", "secret")); + assertThat(environment.getPassword()).isEqualTo("secret"); + } + + @Test + void getPasswordWhenHasMsSqlSaPasswordAndSaPasswordPrefersMsSqlSaPassword() { + MsSqlServerEnvironment environment = new MsSqlServerEnvironment( + Map.of("MSSQL_SA_PASSWORD", "secret", "SA_PASSWORD", "not used")); + assertThat(environment.getPassword()).isEqualTo("secret"); + } + +} diff --git a/spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/service/connection/sqlserver/MsSqlServerR2dbcDockerComposeConnectionDetailsFactoryIntegrationTests.java b/spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/service/connection/sqlserver/MsSqlServerR2dbcDockerComposeConnectionDetailsFactoryIntegrationTests.java new file mode 100644 index 00000000000..07a661b3a9f --- /dev/null +++ b/spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/service/connection/sqlserver/MsSqlServerR2dbcDockerComposeConnectionDetailsFactoryIntegrationTests.java @@ -0,0 +1,48 @@ +/* + * 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.docker.compose.service.connection.sqlserver; + +import io.r2dbc.spi.ConnectionFactoryOptions; +import org.junit.jupiter.api.Test; + +import org.springframework.boot.autoconfigure.r2dbc.R2dbcConnectionDetails; +import org.springframework.boot.docker.compose.service.connection.test.AbstractDockerComposeIntegrationTests; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Integration tests for {@link MsSqlServerR2dbcDockerComposeConnectionDetailsFactory} + * + * @author Andy Wilkinson + */ +class MsSqlServerR2dbcDockerComposeConnectionDetailsFactoryIntegrationTests + extends AbstractDockerComposeIntegrationTests { + + MsSqlServerR2dbcDockerComposeConnectionDetailsFactoryIntegrationTests() { + super("mssqlserver-compose.yaml"); + } + + @Test + void runCreatesConnectionDetails() { + R2dbcConnectionDetails connectionDetails = run(R2dbcConnectionDetails.class); + ConnectionFactoryOptions connectionFactoryOptions = connectionDetails.getConnectionFactoryOptions(); + assertThat(connectionFactoryOptions.toString()).contains("driver=mssql", "password=REDACTED", "user=SA"); + assertThat(connectionFactoryOptions.getRequiredValue(ConnectionFactoryOptions.PASSWORD)) + .isEqualTo("verYs3cret"); + } + +} diff --git a/spring-boot-project/spring-boot-docker-compose/src/test/resources/org/springframework/boot/docker/compose/service/connection/sqlserver/mssqlserver-compose.yaml b/spring-boot-project/spring-boot-docker-compose/src/test/resources/org/springframework/boot/docker/compose/service/connection/sqlserver/mssqlserver-compose.yaml new file mode 100644 index 00000000000..412c563586a --- /dev/null +++ b/spring-boot-project/spring-boot-docker-compose/src/test/resources/org/springframework/boot/docker/compose/service/connection/sqlserver/mssqlserver-compose.yaml @@ -0,0 +1,8 @@ +services: + database: + image: 'mcr.microsoft.com/mssql/server' + ports: + - '1433' + environment: + - 'MSSQL_SA_PASSWORD=verYs3cret' + - 'ACCEPT_EULA=yes' diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/docker-compose.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/docker-compose.adoc index d1ee8622a54..82d07177454 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/docker-compose.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/docker-compose.adoc @@ -47,7 +47,7 @@ The following service connections are currently supported: | Containers named "mongo" | `R2dbcConnectionDetails` -| Containers named "mariadb", "mysql" or "postgres" +| Containers named "mariadb", "mssql/server", "mysql" or "postgres" | `RabbitConnectionDetails` | Containers named "rabbitmq"