Add Docker Compose support

Add `spring-boot-docker-compose` module with service connection
support.

Closes gh-34747

Co-authored-by: Phillip Webb <pwebb@vmware.com>
Co-authored-by: "Andy Wilkinson <wilkinsona@vmware.com>
This commit is contained in:
Mortitz Halbritter
2023-04-07 10:33:48 -04:00
committed by Phillip Webb
parent 4ae24e404e
commit 842e17eced
160 changed files with 11454 additions and 2 deletions

View File

@@ -0,0 +1,88 @@
/*
* 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.core;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.boot.docker.compose.core.DefaultConnectionPorts.ContainerPort;
import org.springframework.core.io.ClassPathResource;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
import static org.assertj.core.api.Assertions.entry;
/**
* Tests for {@link DefaultConnectionPorts}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class DefaultConnectionPortsTests {
@Test
void createWhenBridgeNetwork() throws IOException {
DefaultConnectionPorts ports = createForJson("docker-inspect-bridge-network.json");
assertThat(ports.getMappings()).containsExactly(entry(new ContainerPort(6379, "tcp"), 32770));
}
@Test
void createWhenHostNetwork() throws Exception {
DefaultConnectionPorts ports = createForJson("docker-inspect-host-network.json");
assertThat(ports.getMappings()).containsExactly(entry(new ContainerPort(6379, "tcp"), 6379));
}
private DefaultConnectionPorts createForJson(String path) throws IOException {
String json = new ClassPathResource(path, getClass()).getContentAsString(StandardCharsets.UTF_8);
DockerCliInspectResponse inspectResponse = DockerJson.deserialize(json, DockerCliInspectResponse.class);
return new DefaultConnectionPorts(inspectResponse);
}
@Nested
class ContainerPortTests {
@Test
void parse() {
ContainerPort port = ContainerPort.parse("123/tcp");
assertThat(port).isEqualTo(new ContainerPort(123, "tcp"));
}
@Test
void parseWhenNoSlashThrowsException() {
assertThatIllegalStateException().isThrownBy(() -> ContainerPort.parse("123"))
.withMessage("Unable to parse container port '123'");
}
@Test
void parseWhenMultipleSlashesThrowsException() {
assertThatIllegalStateException().isThrownBy(() -> ContainerPort.parse("123/tcp/ip"))
.withMessage("Unable to parse container port '123/tcp/ip'");
}
@Test
void parseWhenNotNumberThrowsException() {
assertThatIllegalStateException().isThrownBy(() -> ContainerPort.parse("tcp/123"))
.withMessage("Unable to parse container port 'tcp/123'");
}
}
}

View File

@@ -0,0 +1,163 @@
/*
* 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.core;
import java.time.Duration;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.springframework.boot.docker.compose.core.DockerCliInspectResponse.Config;
import org.springframework.boot.docker.compose.core.DockerCliInspectResponse.ExposedPort;
import org.springframework.boot.docker.compose.core.DockerCliInspectResponse.HostConfig;
import org.springframework.boot.docker.compose.core.DockerCliInspectResponse.NetworkSettings;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;
import static org.mockito.BDDMockito.then;
import static org.mockito.BDDMockito.willReturn;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link DefaultDockerCompose}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class DefaultDockerComposeTests {
private static final String HOST = "192.168.1.1";
private DockerCli cli = mock(DockerCli.class);
@Test
void upRunsUpCommand() {
DefaultDockerCompose compose = new DefaultDockerCompose(this.cli, HOST);
compose.up();
then(this.cli).should().run(new DockerCliCommand.ComposeUp());
}
@Test
void downRunsDownCommand() {
DefaultDockerCompose compose = new DefaultDockerCompose(this.cli, HOST);
Duration timeout = Duration.ofSeconds(1);
compose.down(timeout);
then(this.cli).should().run(new DockerCliCommand.ComposeDown(timeout));
}
@Test
void startRunsStartCommand() {
DefaultDockerCompose compose = new DefaultDockerCompose(this.cli, HOST);
compose.start();
then(this.cli).should().run(new DockerCliCommand.ComposeStart());
}
@Test
void stopRunsStopCommand() {
DefaultDockerCompose compose = new DefaultDockerCompose(this.cli, HOST);
Duration timeout = Duration.ofSeconds(1);
compose.stop(timeout);
then(this.cli).should().run(new DockerCliCommand.ComposeStop(timeout));
}
@Test
void hasDefinedServicesWhenComposeConfigServicesIsEmptyReturnsFalse() {
willReturn(new DockerCliComposeConfigResponse("test", Collections.emptyMap())).given(this.cli)
.run(new DockerCliCommand.ComposeConfig());
DefaultDockerCompose compose = new DefaultDockerCompose(this.cli, HOST);
assertThat(compose.hasDefinedServices()).isFalse();
}
@Test
void hasDefinedServicesWhenComposeConfigServicesIsNotEmptyReturnsTrue() {
willReturn(new DockerCliComposeConfigResponse("test",
Map.of("redis", new DockerCliComposeConfigResponse.Service("redis"))))
.given(this.cli)
.run(new DockerCliCommand.ComposeConfig());
DefaultDockerCompose compose = new DefaultDockerCompose(this.cli, HOST);
assertThat(compose.hasDefinedServices()).isTrue();
}
@Test
void hasRunningServicesWhenPsListsRunningServiceReturnsTrue() {
willReturn(List.of(new DockerCliComposePsResponse("id", "name", "image", "exited"),
new DockerCliComposePsResponse("id", "name", "image", "running")))
.given(this.cli)
.run(new DockerCliCommand.ComposePs());
DefaultDockerCompose compose = new DefaultDockerCompose(this.cli, HOST);
assertThat(compose.hasRunningServices()).isTrue();
}
@Test
void hasRunningServicesWhenPsListReturnsAllExitedReturnsFalse() {
willReturn(List.of(new DockerCliComposePsResponse("id", "name", "image", "exited"),
new DockerCliComposePsResponse("id", "name", "image", "running")))
.given(this.cli)
.run(new DockerCliCommand.ComposePs());
DefaultDockerCompose compose = new DefaultDockerCompose(this.cli, HOST);
assertThat(compose.hasRunningServices()).isTrue();
}
@Test
void getRunningServicesReturnsServices() {
String id = "123";
DockerCliComposePsResponse psResponse = new DockerCliComposePsResponse(id, "name", "redis", "running");
Map<String, ExposedPort> exposedPorts = Collections.emptyMap();
Config config = new Config("redis", Map.of("spring", "boot"), exposedPorts, List.of("a=b"));
NetworkSettings networkSettings = null;
HostConfig hostConfig = null;
DockerCliInspectResponse inspectResponse = new DockerCliInspectResponse(id, config, networkSettings,
hostConfig);
willReturn(List.of(psResponse)).given(this.cli).run(new DockerCliCommand.ComposePs());
willReturn(List.of(inspectResponse)).given(this.cli).run(new DockerCliCommand.Inspect(List.of(id)));
DefaultDockerCompose compose = new DefaultDockerCompose(this.cli, HOST);
List<RunningService> runningServices = compose.getRunningServices();
assertThat(runningServices).hasSize(1);
RunningService runningService = runningServices.get(0);
assertThat(runningService.name()).isEqualTo("name");
assertThat(runningService.image()).hasToString("redis");
assertThat(runningService.host()).isEqualTo(HOST);
assertThat(runningService.ports().getAll()).isEmpty();
assertThat(runningService.env()).containsExactly(entry("a", "b"));
assertThat(runningService.labels()).containsExactly(entry("spring", "boot"));
}
@Test
void getRunningServicesWhenNoHostUsesHostFromContext() {
String id = "123";
DockerCliComposePsResponse psResponse = new DockerCliComposePsResponse(id, "name", "redis", "running");
Map<String, ExposedPort> exposedPorts = Collections.emptyMap();
Config config = new Config("redis", Map.of("spring", "boot"), exposedPorts, List.of("a=b"));
NetworkSettings networkSettings = null;
HostConfig hostConfig = null;
DockerCliInspectResponse inspectResponse = new DockerCliInspectResponse(id, config, networkSettings,
hostConfig);
willReturn(List.of(new DockerCliContextResponse("test", true, "https://192.168.1.1"))).given(this.cli)
.run(new DockerCliCommand.Context());
willReturn(List.of(psResponse)).given(this.cli).run(new DockerCliCommand.ComposePs());
willReturn(List.of(inspectResponse)).given(this.cli).run(new DockerCliCommand.Inspect(List.of(id)));
DefaultDockerCompose compose = new DefaultDockerCompose(this.cli, null);
List<RunningService> runningServices = compose.getRunningServices();
assertThat(runningServices).hasSize(1);
RunningService runningService = runningServices.get(0);
assertThat(runningService.host()).isEqualTo("192.168.1.1");
}
}

View File

@@ -0,0 +1,125 @@
/*
* 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.core;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.springframework.boot.docker.compose.core.DockerCliInspectResponse.Config;
import org.springframework.boot.docker.compose.core.DockerCliInspectResponse.ExposedPort;
import org.springframework.boot.docker.compose.core.DockerCliInspectResponse.HostConfig;
import org.springframework.boot.docker.compose.core.DockerCliInspectResponse.HostPort;
import org.springframework.boot.docker.compose.core.DockerCliInspectResponse.NetworkSettings;
import org.springframework.boot.origin.Origin;
import org.springframework.util.FileCopyUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;
/**
* Tests for {@link DefaultRunningService}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class DefaultRunningServiceTests {
@TempDir
File temp;
private DefaultRunningService runningService;
private DockerComposeFile composeFile;
@BeforeEach
void setup() throws Exception {
this.composeFile = createComposeFile();
DockerHost host = DockerHost.get("192.168.1.1", () -> Collections.emptyList());
String id = "123";
String name = "my-service";
String image = "redis";
String state = "running";
DockerCliComposePsResponse psResponse = new DockerCliComposePsResponse(id, name, image, state);
Map<String, String> labels = Map.of("spring", "boot");
Map<String, ExposedPort> exposedPorts = Map.of("8080/tcp", new ExposedPort());
List<String> env = List.of("a=b");
Config config = new Config(image, labels, exposedPorts, env);
Map<String, List<HostPort>> ports = Map.of("8080/tcp", List.of(new HostPort(null, "9090")));
NetworkSettings networkSettings = new NetworkSettings(ports);
HostConfig hostConfig = new HostConfig("bridge");
DockerCliInspectResponse inspectResponse = new DockerCliInspectResponse(id, config, networkSettings,
hostConfig);
this.runningService = new DefaultRunningService(host, this.composeFile, psResponse, inspectResponse);
}
private DockerComposeFile createComposeFile() throws IOException {
File file = new File(this.temp, "compose.yaml");
FileCopyUtils.copy(new byte[0], file);
return DockerComposeFile.of(file);
}
@Test
void getOriginReturnsOrigin() {
assertThat(Origin.from(this.runningService)).isEqualTo(new DockerComposeOrigin(this.composeFile, "my-service"));
}
@Test
void nameReturnsNameFromPsResponse() {
assertThat(this.runningService.name()).isEqualTo("my-service");
}
@Test
void imageReturnsImageFromPsResponse() {
assertThat(this.runningService.image()).hasToString("redis");
}
@Test
void hostReturnsHost() {
assertThat(this.runningService.host()).isEqualTo("192.168.1.1");
}
@Test
void portsReturnsPortsFromInspectResponse() {
ConnectionPorts ports = this.runningService.ports();
assertThat(ports.getAll("tcp")).containsExactly(9090);
assertThat(ports.get(8080)).isEqualTo(9090);
}
@Test
void envReturnsEnvFromInspectResponse() {
assertThat(this.runningService.env()).containsExactly(entry("a", "b"));
}
@Test
void labelReturnsLabelsFromInspectResponse() {
assertThat(this.runningService.labels()).containsExactly(entry("spring", "boot"));
}
@Test
void toStringReturnsServiceName() {
assertThat(this.runningService).hasToString("my-service");
}
}

View File

@@ -0,0 +1,99 @@
/*
* 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.core;
import java.time.Duration;
import java.util.List;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link DockerCliCommand}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class DockerCliCommandTests {
@Test
void context() {
DockerCliCommand<?> command = new DockerCliCommand.Context();
assertThat(command.getType()).isEqualTo(DockerCliCommand.Type.DOCKER);
assertThat(command.getCommand()).containsExactly("context", "ls", "--format={{ json . }}");
assertThat(command.deserialize("[]")).isInstanceOf(List.class);
}
@Test
void inspect() {
DockerCliCommand<?> command = new DockerCliCommand.Inspect(List.of("123", "345"));
assertThat(command.getType()).isEqualTo(DockerCliCommand.Type.DOCKER);
assertThat(command.getCommand()).containsExactly("inspect", "--format={{ json . }}", "123", "345");
assertThat(command.deserialize("[]")).isInstanceOf(List.class);
}
@Test
void composeConfig() {
DockerCliCommand<?> command = new DockerCliCommand.ComposeConfig();
assertThat(command.getType()).isEqualTo(DockerCliCommand.Type.DOCKER_COMPOSE);
assertThat(command.getCommand()).containsExactly("config", "--format=json");
assertThat(command.deserialize("{}")).isInstanceOf(DockerCliComposeConfigResponse.class);
}
@Test
void composePs() {
DockerCliCommand<?> command = new DockerCliCommand.ComposePs();
assertThat(command.getType()).isEqualTo(DockerCliCommand.Type.DOCKER_COMPOSE);
assertThat(command.getCommand()).containsExactly("ps", "--format=json");
assertThat(command.deserialize("[]")).isInstanceOf(List.class);
}
@Test
void composeUp() {
DockerCliCommand<?> command = new DockerCliCommand.ComposeUp();
assertThat(command.getType()).isEqualTo(DockerCliCommand.Type.DOCKER_COMPOSE);
assertThat(command.getCommand()).containsExactly("up", "--no-color", "--quiet-pull", "--detach", "--wait");
assertThat(command.deserialize("[]")).isNull();
}
@Test
void composeDown() {
DockerCliCommand<?> command = new DockerCliCommand.ComposeDown(Duration.ofSeconds(1));
assertThat(command.getType()).isEqualTo(DockerCliCommand.Type.DOCKER_COMPOSE);
assertThat(command.getCommand()).containsExactly("down", "--timeout", "1");
assertThat(command.deserialize("[]")).isNull();
}
@Test
void composeStart() {
DockerCliCommand<?> command = new DockerCliCommand.ComposeStart();
assertThat(command.getType()).isEqualTo(DockerCliCommand.Type.DOCKER_COMPOSE);
assertThat(command.getCommand()).containsExactly("start", "--no-color", "--quiet-pull", "--detach", "--wait");
assertThat(command.deserialize("[]")).isNull();
}
@Test
void composeStop() {
DockerCliCommand<?> command = new DockerCliCommand.ComposeStop(Duration.ofSeconds(1));
assertThat(command.getType()).isEqualTo(DockerCliCommand.Type.DOCKER_COMPOSE);
assertThat(command.getCommand()).containsExactly("stop", "--timeout", "1");
assertThat(command.deserialize("[]")).isNull();
}
}

View File

@@ -0,0 +1,49 @@
/*
* 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.core;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.springframework.boot.docker.compose.core.DockerCliComposeConfigResponse.Service;
import org.springframework.core.io.ClassPathResource;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link DockerCliComposeConfigResponse}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class DockerCliComposeConfigResponseTests {
@Test
void deserializeJson() throws IOException {
String json = new ClassPathResource("docker-compose-config.json", getClass())
.getContentAsString(StandardCharsets.UTF_8);
DockerCliComposeConfigResponse response = DockerJson.deserialize(json, DockerCliComposeConfigResponse.class);
DockerCliComposeConfigResponse expected = new DockerCliComposeConfigResponse("redis-docker",
Map.of("redis", new Service("redis:7.0")));
assertThat(response).isEqualTo(expected);
}
}

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.docker.compose.core;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import org.junit.jupiter.api.Test;
import org.springframework.core.io.ClassPathResource;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link DockerCliComposePsResponse}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class DockerCliComposePsResponseTests {
@Test
void deserializeJson() throws IOException {
String json = new ClassPathResource("docker-compose-ps.json", getClass())
.getContentAsString(StandardCharsets.UTF_8);
DockerCliComposePsResponse response = DockerJson.deserialize(json, DockerCliComposePsResponse.class);
DockerCliComposePsResponse expected = new DockerCliComposePsResponse("f5af31dae7f6", "redis-docker-redis-1",
"redis:7.0", "running");
assertThat(response).isEqualTo(expected);
}
}

View File

@@ -0,0 +1,46 @@
/*
* 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.core;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import org.junit.jupiter.api.Test;
import org.springframework.core.io.ClassPathResource;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link DockerCliComposeVersionResponse}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class DockerCliComposeVersionResponseTests {
@Test
void deserializeJson() throws IOException {
String json = new ClassPathResource("docker-compose-version.json", getClass())
.getContentAsString(StandardCharsets.UTF_8);
DockerCliComposeVersionResponse response = DockerJson.deserialize(json, DockerCliComposeVersionResponse.class);
DockerCliComposeVersionResponse expected = new DockerCliComposeVersionResponse("123");
assertThat(response).isEqualTo(expected);
}
}

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.docker.compose.core;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import org.junit.jupiter.api.Test;
import org.springframework.core.io.ClassPathResource;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link DockerCliContextResponse}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class DockerCliContextResponseTests {
@Test
void deserializeJson() throws IOException {
String json = new ClassPathResource("docker-context.json", getClass())
.getContentAsString(StandardCharsets.UTF_8);
DockerCliContextResponse response = DockerJson.deserialize(json, DockerCliContextResponse.class);
DockerCliContextResponse expected = new DockerCliContextResponse("default", true,
"unix:///var/run/docker.sock");
assertThat(response).isEqualTo(expected);
}
}

View File

@@ -0,0 +1,78 @@
/*
* 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.core;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.springframework.boot.docker.compose.core.DockerCliInspectResponse.Config;
import org.springframework.boot.docker.compose.core.DockerCliInspectResponse.ExposedPort;
import org.springframework.boot.docker.compose.core.DockerCliInspectResponse.HostConfig;
import org.springframework.boot.docker.compose.core.DockerCliInspectResponse.HostPort;
import org.springframework.boot.docker.compose.core.DockerCliInspectResponse.NetworkSettings;
import org.springframework.core.io.ClassPathResource;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link DockerCliInspectResponse}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class DockerCliInspectResponseTests {
@Test
void deserializeJson() throws IOException {
String json = new ClassPathResource("docker-inspect.json", getClass())
.getContentAsString(StandardCharsets.UTF_8);
DockerCliInspectResponse response = DockerJson.deserialize(json, DockerCliInspectResponse.class);
LinkedHashMap<String, String> expectedLabels = linkedMapOf("com.docker.compose.config-hash",
"cfdc8e119d85a53c7d47edb37a3b160a8c83ba48b0428ebc07713befec991dd0",
"com.docker.compose.container-number", "1", "com.docker.compose.depends_on", "",
"com.docker.compose.image", "sha256:e79ba23ed43baa22054741136bf45bdb041824f41c5e16c0033ea044ca164b82",
"com.docker.compose.oneoff", "False", "com.docker.compose.project", "redis-docker",
"com.docker.compose.project.config_files", "compose.yaml", "com.docker.compose.project.working_dir",
"/", "com.docker.compose.service", "redis", "com.docker.compose.version", "2.16.0");
List<String> expectedEnv = List.of("PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"GOSU_VERSION=1.16", "REDIS_VERSION=7.0.8");
Config expectedConfig = new Config("redis:7.0", expectedLabels, Map.of("6379/tcp", new ExposedPort()),
expectedEnv);
NetworkSettings expectedNetworkSettings = new NetworkSettings(
Map.of("6379/tcp", List.of(new HostPort("0.0.0.0", "32770"), new HostPort("::", "32770"))));
DockerCliInspectResponse expected = new DockerCliInspectResponse(
"f5af31dae7f665bd194ec7261bdc84e5df9c64753abb4a6cec6c33f7cf64c3fc", expectedConfig,
expectedNetworkSettings, new HostConfig("redis-docker_default"));
assertThat(response).isEqualTo(expected);
}
@SuppressWarnings("unchecked")
private <K, V> LinkedHashMap<K, V> linkedMapOf(Object... values) {
LinkedHashMap<K, V> result = new LinkedHashMap<>();
for (int i = 0; i < values.length; i = i + 2) {
result.put((K) values[i], (V) values[i + 1]);
}
return result;
}
}

View File

@@ -0,0 +1,45 @@
/*
* 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.core;
import java.util.Collections;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.springframework.boot.testsupport.process.DisabledIfProcessUnavailable;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link DockerCli}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
@DisabledIfProcessUnavailable({ "docker", "compose" })
class DockerCliTests {
@Test
void runBasicCommand() {
DockerCli cli = new DockerCli(null, null, Collections.emptySet());
List<DockerCliContextResponse> context = cli.run(new DockerCliCommand.Context());
assertThat(context).isNotEmpty();
}
}

View File

@@ -0,0 +1,137 @@
/*
* 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.core;
import java.io.File;
import java.io.IOException;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.springframework.util.FileCopyUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
/**
* Tests for {@link DockerComposeFile}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class DockerComposeFileTests {
@TempDir
File temp;
@Test
void hashCodeAndEquals() throws Exception {
File f1 = new File(this.temp, "compose.yml");
File f2 = new File(this.temp, "docker-compose.yml");
FileCopyUtils.copy(new byte[0], f1);
FileCopyUtils.copy(new byte[0], f2);
DockerComposeFile c1 = DockerComposeFile.of(f1);
DockerComposeFile c2 = DockerComposeFile.of(f1);
DockerComposeFile c3 = DockerComposeFile.find(f1.getParentFile());
DockerComposeFile c4 = DockerComposeFile.of(f2);
assertThat(c1.hashCode()).isEqualTo(c2.hashCode()).isEqualTo(c3.hashCode());
assertThat(c1).isEqualTo(c1).isEqualTo(c2).isEqualTo(c3).isNotEqualTo(c4);
}
@Test
void toStringReturnsFileName() throws Exception {
DockerComposeFile composeFile = createComposeFile("compose.yml");
assertThat(composeFile.toString()).endsWith("/compose.yml");
}
@Test
void findFindsSingleFile() throws Exception {
File file = new File(this.temp, "docker-compose.yml");
FileCopyUtils.copy(new byte[0], file);
DockerComposeFile composeFile = DockerComposeFile.find(file.getParentFile());
assertThat(composeFile.toString()).endsWith("/docker-compose.yml");
}
@Test
void findWhenMultipleFilesPicksBest() throws Exception {
File f1 = new File(this.temp, "docker-compose.yml");
FileCopyUtils.copy(new byte[0], f1);
File f2 = new File(this.temp, "compose.yml");
FileCopyUtils.copy(new byte[0], f2);
DockerComposeFile composeFile = DockerComposeFile.find(f1.getParentFile());
assertThat(composeFile.toString()).endsWith("/compose.yml");
}
@Test
void findWhenNoComposeFilesReturnsNull() throws Exception {
File file = new File(this.temp, "not-a-compose.yml");
FileCopyUtils.copy(new byte[0], file);
DockerComposeFile composeFile = DockerComposeFile.find(file.getParentFile());
assertThat(composeFile).isNull();
}
@Test
void findWhenWorkingDirectoryDoesNotExistReturnsNull() {
File directory = new File(this.temp, "missing");
DockerComposeFile composeFile = DockerComposeFile.find(directory);
assertThat(composeFile).isNull();
}
@Test
void findWhenWorkingDirectoryIsNotDirectoryThrowsException() throws Exception {
File file = new File(this.temp, "iamafile");
FileCopyUtils.copy(new byte[0], file);
assertThatIllegalArgumentException().isThrownBy(() -> DockerComposeFile.find(file))
.withMessageEndingWith("is not a directory");
}
@Test
void ofReturnsDockerComposeFile() throws Exception {
File file = new File(this.temp, "anyfile.yml");
FileCopyUtils.copy(new byte[0], file);
DockerComposeFile composeFile = DockerComposeFile.of(file);
assertThat(composeFile).isNotNull();
assertThat(composeFile.toString()).isEqualTo(file.getCanonicalPath());
}
@Test
void ofWhenFileIsNullThrowsException() {
assertThatIllegalArgumentException().isThrownBy(() -> DockerComposeFile.of(null))
.withMessage("File must not be null");
}
@Test
void ofWhenFileDoesNotExistThrowsException() {
File file = new File(this.temp, "missing");
assertThatIllegalArgumentException().isThrownBy(() -> DockerComposeFile.of(file))
.withMessageEndingWith("does not exist");
}
@Test
void ofWhenFileIsNotFileThrowsException() {
assertThatIllegalArgumentException().isThrownBy(() -> DockerComposeFile.of(this.temp))
.withMessageEndingWith("is not a file");
}
private DockerComposeFile createComposeFile(String name) throws IOException {
File file = new File(this.temp, name);
FileCopyUtils.copy(new byte[0], file);
return DockerComposeFile.of(file);
}
}

View File

@@ -0,0 +1,71 @@
/*
* 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.core;
import java.io.File;
import java.io.IOException;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.springframework.util.FileCopyUtils;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link DockerComposeOrigin}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class DockerComposeOriginTests {
@TempDir
File temp;
@Test
void hasToString() throws Exception {
DockerComposeFile composeFile = createTempComposeFile();
DockerComposeOrigin origin = new DockerComposeOrigin(composeFile, "service-1");
assertThat(origin.toString()).startsWith("Docker compose service 'service-1' defined in '")
.endsWith("compose.yaml'");
}
@Test
void equalsAndHashcode() throws Exception {
DockerComposeFile composeFile = createTempComposeFile();
DockerComposeOrigin origin1 = new DockerComposeOrigin(composeFile, "service-1");
DockerComposeOrigin origin2 = new DockerComposeOrigin(composeFile, "service-1");
DockerComposeOrigin origin3 = new DockerComposeOrigin(composeFile, "service-3");
assertThat(origin1).isEqualTo(origin1);
assertThat(origin1).isEqualTo(origin2);
assertThat(origin1).hasSameHashCodeAs(origin2);
assertThat(origin2).isEqualTo(origin1);
assertThat(origin1).isNotEqualTo(origin3);
assertThat(origin2).isNotEqualTo(origin3);
assertThat(origin3).isNotEqualTo(origin1);
assertThat(origin3).isNotEqualTo(origin2);
}
private DockerComposeFile createTempComposeFile() throws IOException {
File file = new File(this.temp, "compose.yaml");
FileCopyUtils.copy(new byte[0], file);
return DockerComposeFile.of(file);
}
}

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.docker.compose.core;
import java.util.Collections;
import java.util.List;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;
/**
* Tests for {@link DockerEnv}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class DockerEnvTests {
@Test
void createWhenEnvIsNullReturnsEmpty() {
DockerEnv env = new DockerEnv(null);
assertThat(env.asMap()).isEmpty();
}
@Test
void createWhenEnvIsEmptyReturnsEmpty() {
DockerEnv env = new DockerEnv(Collections.emptyList());
assertThat(env.asMap()).isEmpty();
}
@Test
void createParsesEnv() {
DockerEnv env = new DockerEnv(List.of("a=b", "c"));
assertThat(env.asMap()).containsExactly(entry("a", "b"), entry("c", null));
}
}

View File

@@ -0,0 +1,184 @@
/*
* 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.core;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Supplier;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link DockerHost}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class DockerHostTests {
private static final String MAC_HOST = "unix:///var/run/docker.sock";
private static final String LINUX_HOST = "unix:///var/run/docker.sock";
private static final String WINDOWS_HOST = "npipe:////./pipe/docker_engine";
private static final String WSL_HOST = "unix:///var/run/docker.sock";
private static final String HTTP_HOST = "http://192.168.1.1";
private static final String HTTPS_HOST = "https://192.168.1.1";
private static final String TCP_HOST = "tcp://192.168.1.1";
private static final Function<String, String> NO_SYSTEM_ENV = (key) -> null;
private static final Supplier<List<DockerCliContextResponse>> NO_CONTEXT = () -> Collections.emptyList();
@Test
void getWhenHasHost() {
DockerHost host = DockerHost.get("192.168.1.1", NO_SYSTEM_ENV, NO_CONTEXT);
assertThat(host).hasToString("192.168.1.1");
}
@Test
void getWhenHasServiceHostEnv() {
Map<String, String> systemEnv = Map.of("SERVICES_HOST", "192.168.1.2");
DockerHost host = DockerHost.get(null, systemEnv::get, NO_CONTEXT);
assertThat(host).hasToString("192.168.1.2");
}
@Test
void getWhenHasMacDockerHostEnv() {
Map<String, String> systemEnv = Map.of("DOCKER_HOST", MAC_HOST);
DockerHost host = DockerHost.get(null, systemEnv::get, NO_CONTEXT);
assertThat(host).hasToString("127.0.0.1");
}
@Test
void getWhenHasLinuxDockerHostEnv() {
Map<String, String> systemEnv = Map.of("DOCKER_HOST", LINUX_HOST);
DockerHost host = DockerHost.get(null, systemEnv::get, NO_CONTEXT);
assertThat(host).hasToString("127.0.0.1");
}
@Test
void getWhenHasWindowsDockerHostEnv() {
Map<String, String> systemEnv = Map.of("DOCKER_HOST", WINDOWS_HOST);
DockerHost host = DockerHost.get(null, systemEnv::get, NO_CONTEXT);
assertThat(host).hasToString("127.0.0.1");
}
@Test
void getWhenHasWslDockerHostEnv() {
Map<String, String> systemEnv = Map.of("DOCKER_HOST", WSL_HOST);
DockerHost host = DockerHost.get(null, systemEnv::get, NO_CONTEXT);
assertThat(host).hasToString("127.0.0.1");
}
@Test
void getWhenHasHttpDockerHostEnv() {
Map<String, String> systemEnv = Map.of("DOCKER_HOST", HTTP_HOST);
DockerHost host = DockerHost.get(null, systemEnv::get, NO_CONTEXT);
assertThat(host).hasToString("192.168.1.1");
}
@Test
void getWhenHasHttpsDockerHostEnv() {
Map<String, String> systemEnv = Map.of("DOCKER_HOST", HTTPS_HOST);
DockerHost host = DockerHost.get(null, systemEnv::get, NO_CONTEXT);
assertThat(host).hasToString("192.168.1.1");
}
@Test
void getWhenHasTcpDockerHostEnv() {
Map<String, String> systemEnv = Map.of("DOCKER_HOST", TCP_HOST);
DockerHost host = DockerHost.get(null, systemEnv::get, NO_CONTEXT);
assertThat(host).hasToString("192.168.1.1");
}
@Test
void getWhenHasMacContext() {
List<DockerCliContextResponse> context = List.of(new DockerCliContextResponse("test", true, MAC_HOST));
DockerHost host = DockerHost.get(null, NO_SYSTEM_ENV, () -> context);
assertThat(host).hasToString("127.0.0.1");
}
@Test
void getWhenHasLinuxContext() {
List<DockerCliContextResponse> context = List.of(new DockerCliContextResponse("test", true, LINUX_HOST));
DockerHost host = DockerHost.get(null, NO_SYSTEM_ENV, () -> context);
assertThat(host).hasToString("127.0.0.1");
}
@Test
void getWhenHasWindowsContext() {
List<DockerCliContextResponse> context = List.of(new DockerCliContextResponse("test", true, WINDOWS_HOST));
DockerHost host = DockerHost.get(null, NO_SYSTEM_ENV, () -> context);
assertThat(host).hasToString("127.0.0.1");
}
@Test
void getWhenHasWslContext() {
List<DockerCliContextResponse> context = List.of(new DockerCliContextResponse("test", true, WSL_HOST));
DockerHost host = DockerHost.get(null, NO_SYSTEM_ENV, () -> context);
assertThat(host).hasToString("127.0.0.1");
}
@Test
void getWhenHasHttpContext() {
List<DockerCliContextResponse> context = List.of(new DockerCliContextResponse("test", true, HTTP_HOST));
DockerHost host = DockerHost.get(null, NO_SYSTEM_ENV, () -> context);
assertThat(host).hasToString("192.168.1.1");
}
@Test
void getWhenHasHttpsContext() {
List<DockerCliContextResponse> context = List.of(new DockerCliContextResponse("test", true, HTTPS_HOST));
DockerHost host = DockerHost.get(null, NO_SYSTEM_ENV, () -> context);
assertThat(host).hasToString("192.168.1.1");
}
@Test
void getWhenHasTcpContext() {
List<DockerCliContextResponse> context = List.of(new DockerCliContextResponse("test", true, TCP_HOST));
DockerHost host = DockerHost.get(null, NO_SYSTEM_ENV, () -> context);
assertThat(host).hasToString("192.168.1.1");
}
@Test
void getWhenContextHasMultiple() {
List<DockerCliContextResponse> context = new ArrayList<>();
context.add(new DockerCliContextResponse("test", false, "http://192.168.1.1"));
context.add(new DockerCliContextResponse("test", true, "http://192.168.1.2"));
context.add(new DockerCliContextResponse("test", false, "http://192.168.1.3"));
DockerHost host = DockerHost.get(null, NO_SYSTEM_ENV, () -> context);
assertThat(host).hasToString("192.168.1.2");
}
@Test
void getWhenHasNone() {
DockerHost host = DockerHost.get(null, NO_SYSTEM_ENV, NO_CONTEXT);
assertThat(host).hasToString("127.0.0.1");
}
}

View File

@@ -0,0 +1,74 @@
/*
* 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.core;
import java.util.List;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link DockerJson}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class DockerJsonTests {
@Test
void deserializeWhenSentenceCase() {
String json = """
{ "Value": 1 }
""";
TestResponse response = DockerJson.deserialize(json, TestResponse.class);
assertThat(response).isEqualTo(new TestResponse(1));
}
@Test
void deserializeWhenLowerCase() {
String json = """
{ "value": 1 }
""";
TestResponse response = DockerJson.deserialize(json, TestResponse.class);
assertThat(response).isEqualTo(new TestResponse(1));
}
@Test
void deserializeToListWhenArray() {
String json = """
[{ "value": 1 }, { "value": 2 }]
""";
List<TestResponse> response = DockerJson.deserializeToList(json, TestResponse.class);
assertThat(response).containsExactly(new TestResponse(1), new TestResponse(2));
}
@Test
void deserializeToListWhenMultipleLines() {
String json = """
{ "Value": 1 }
{ "Value": 2 }
""";
List<TestResponse> response = DockerJson.deserializeToList(json, TestResponse.class);
assertThat(response).containsExactly(new TestResponse(1), new TestResponse(2));
}
record TestResponse(int value) {
}
}

View File

@@ -0,0 +1,103 @@
/*
* 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.core;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link ImageReference}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class ImageReferenceTests {
@Test
void getImageNameWhenImageOnly() {
ImageReference imageReference = ImageReference.of("redis");
assertThat(imageReference.getImageName()).isEqualTo("redis");
}
@Test
void getImageNameWhenImageAndTag() {
ImageReference imageReference = ImageReference.of("redis:5");
assertThat(imageReference.getImageName()).isEqualTo("redis");
}
@Test
void getImageNameWhenImageAndDigest() {
ImageReference imageReference = ImageReference
.of("redis@sha256:0ed5d5928d4737458944eb604cc8509e245c3e19d02ad83935398bc4b991aac7");
assertThat(imageReference.getImageName()).isEqualTo("redis");
}
@Test
void getImageNameWhenProjectAndImage() {
ImageReference imageReference = ImageReference.of("library/redis");
assertThat(imageReference.getImageName()).isEqualTo("redis");
}
@Test
void getImageNameWhenRegistryLibraryAndImage() {
ImageReference imageReference = ImageReference.of("docker.io/library/redis");
assertThat(imageReference.getImageName()).isEqualTo("redis");
}
@Test
void getImageNameWhenRegistryLibraryImageAndTag() {
ImageReference imageReference = ImageReference.of("docker.io/library/redis:5");
assertThat(imageReference.getImageName()).isEqualTo("redis");
}
@Test
void getImageNameWhenRegistryLibraryImageAndDigest() {
ImageReference imageReference = ImageReference
.of("docker.io/library/redis@sha256:0ed5d5928d4737458944eb604cc8509e245c3e19d02ad83935398bc4b991aac7");
assertThat(imageReference.getImageName()).isEqualTo("redis");
}
@Test
void getImageNameWhenRegistryWithPort() {
ImageReference imageReference = ImageReference.of("my_private.registry:5000/redis");
assertThat(imageReference.getImageName()).isEqualTo("redis");
}
@Test
void getImageNameWhenRegistryWithPortAndTag() {
ImageReference imageReference = ImageReference.of("my_private.registry:5000/redis:5");
assertThat(imageReference.getImageName()).isEqualTo("redis");
}
@Test
void toStringReturnsReferenceString() {
ImageReference imageReference = ImageReference.of("docker.io/library/redis");
assertThat(imageReference).hasToString("docker.io/library/redis");
}
@Test
void equalsAndHashCode() {
ImageReference imageReference1 = ImageReference.of("docker.io/library/redis");
ImageReference imageReference2 = ImageReference.of("docker.io/library/redis");
ImageReference imageReference3 = ImageReference.of("docker.io/library/other");
assertThat(imageReference1.hashCode()).isEqualTo(imageReference2.hashCode());
assertThat(imageReference1).isEqualTo(imageReference1).isEqualTo(imageReference2).isNotEqualTo(imageReference3);
}
}

View File

@@ -0,0 +1,61 @@
/*
* 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.core;
import org.junit.jupiter.api.Test;
import org.springframework.boot.testsupport.process.DisabledIfProcessUnavailable;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* Tests for {@link ProcessRunner}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
@DisabledIfProcessUnavailable("docker")
class ProcessRunnerTests {
private ProcessRunner processRunner = new ProcessRunner();
@Test
void run() {
String out = this.processRunner.run("docker", "--version");
assertThat(out).isNotEmpty();
}
@Test
void runWhenProcessDoesNotStart() {
assertThatExceptionOfType(ProcessStartException.class)
.isThrownBy(() -> this.processRunner.run("iverymuchdontexist", "--version"));
}
@Test
void runWhenProcessReturnsNonZeroExitCode() {
assertThatExceptionOfType(ProcessExitException.class)
.isThrownBy(() -> this.processRunner.run("docker", "-thisdoesntwork"))
.satisfies((ex) -> {
assertThat(ex.getExitCode()).isGreaterThan(0);
assertThat(ex.getStdOut()).isEmpty();
assertThat(ex.getStdErr()).isNotEmpty();
});
}
}

View File

@@ -0,0 +1,373 @@
/*
* 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.lifecycle;
import java.io.File;
import java.io.IOException;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.springframework.boot.SpringApplicationShutdownHandlers;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.docker.compose.core.DockerCompose;
import org.springframework.boot.docker.compose.core.DockerComposeFile;
import org.springframework.boot.docker.compose.core.RunningService;
import org.springframework.boot.docker.compose.readiness.ServiceReadinessChecks;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.util.FileCopyUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.isA;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
/**
* Tests for {@link DockerComposeLifecycleManager}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class DockerComposeLifecycleManagerTests {
@TempDir
File temp;
private DockerComposeFile dockerComposeFile;
private DockerCompose dockerCompose;
private Set<String> activeProfiles;
private GenericApplicationContext applicationContext;
private TestSpringApplicationShutdownHandlers shutdownHandlers;
private ServiceReadinessChecks serviceReadinessChecks;
private List<RunningService> runningServices;
private DockerComposeProperties properties;
private LinkedHashSet<ApplicationListener<?>> eventListeners;
private DockerComposeLifecycleManager lifecycleManager;
private DockerComposeSkipCheck skipCheck;
@BeforeEach
void setup() throws IOException {
File file = new File(this.temp, "compose.yml");
FileCopyUtils.copy(new byte[0], file);
this.dockerComposeFile = DockerComposeFile.of(file);
this.dockerCompose = mock(DockerCompose.class);
File workingDirectory = new File(".");
this.applicationContext = new GenericApplicationContext();
this.applicationContext.refresh();
Binder binder = Binder.get(this.applicationContext.getEnvironment());
this.shutdownHandlers = new TestSpringApplicationShutdownHandlers();
this.properties = DockerComposeProperties.get(binder);
this.eventListeners = new LinkedHashSet<>();
this.skipCheck = mock(DockerComposeSkipCheck.class);
this.serviceReadinessChecks = mock(ServiceReadinessChecks.class);
this.lifecycleManager = new TestDockerComposeLifecycleManager(workingDirectory, this.applicationContext, binder,
this.shutdownHandlers, this.properties, this.eventListeners, this.skipCheck,
this.serviceReadinessChecks);
}
@Test
void startupWhenEnabledFalseDoesNotStart() {
this.properties.setEnabled(false);
EventCapturingListener listener = new EventCapturingListener();
this.eventListeners.add(listener);
setupRunningServices();
this.lifecycleManager.startup();
assertThat(listener.getEvent()).isNull();
then(this.dockerCompose).should(never()).hasDefinedServices();
}
@Test
void startupWhenInTestDoesNotStart() {
given(this.skipCheck.shouldSkip(any(), any(), any())).willReturn(true);
EventCapturingListener listener = new EventCapturingListener();
this.eventListeners.add(listener);
setupRunningServices();
this.lifecycleManager.startup();
assertThat(listener.getEvent()).isNull();
then(this.dockerCompose).should(never()).hasDefinedServices();
}
@Test
void startupWhenHasNoDefinedServicesDoesNothing() {
EventCapturingListener listener = new EventCapturingListener();
this.eventListeners.add(listener);
this.lifecycleManager.startup();
assertThat(listener.getEvent()).isNull();
then(this.dockerCompose).should().hasDefinedServices();
then(this.dockerCompose).should(never()).up();
then(this.dockerCompose).should(never()).start();
then(this.dockerCompose).should(never()).down(isA(Duration.class));
then(this.dockerCompose).should(never()).stop(isA(Duration.class));
}
@Test
void startupWhenLifecycleStartAndStopAndHasNoRunningServicesDoesStartupAndShutdown() {
this.properties.setLifecycleManagement(LifecycleManagement.START_AND_STOP);
EventCapturingListener listener = new EventCapturingListener();
this.eventListeners.add(listener);
given(this.dockerCompose.hasDefinedServices()).willReturn(true);
this.lifecycleManager.startup();
this.shutdownHandlers.run();
assertThat(listener.getEvent()).isNotNull();
then(this.dockerCompose).should().up();
then(this.dockerCompose).should(never()).start();
then(this.dockerCompose).should().down(isA(Duration.class));
then(this.dockerCompose).should(never()).stop(isA(Duration.class));
}
@Test
void startupWhenLifecycleStartAndStopAndHasRunningServicesDoesNoStartupOrShutdown() {
this.properties.setLifecycleManagement(LifecycleManagement.START_AND_STOP);
EventCapturingListener listener = new EventCapturingListener();
this.eventListeners.add(listener);
setupRunningServices();
this.lifecycleManager.startup();
this.shutdownHandlers.run();
assertThat(listener.getEvent()).isNotNull();
then(this.dockerCompose).should(never()).up();
then(this.dockerCompose).should(never()).start();
then(this.dockerCompose).should(never()).down(isA(Duration.class));
then(this.dockerCompose).should(never()).stop(isA(Duration.class));
}
@Test
void startupWhenLifecycleNoneDoesNoStartupOrShutdown() {
this.properties.setLifecycleManagement(LifecycleManagement.NONE);
EventCapturingListener listener = new EventCapturingListener();
this.eventListeners.add(listener);
setupRunningServices();
this.lifecycleManager.startup();
this.shutdownHandlers.run();
assertThat(listener.getEvent()).isNotNull();
then(this.dockerCompose).should(never()).up();
then(this.dockerCompose).should(never()).start();
then(this.dockerCompose).should(never()).down(isA(Duration.class));
then(this.dockerCompose).should(never()).stop(isA(Duration.class));
}
@Test
void startupWhenLifecycleStartOnlyDoesStartupAndNoShutdown() {
this.properties.setLifecycleManagement(LifecycleManagement.START_ONLY);
EventCapturingListener listener = new EventCapturingListener();
this.eventListeners.add(listener);
given(this.dockerCompose.hasDefinedServices()).willReturn(true);
this.lifecycleManager.startup();
this.shutdownHandlers.run();
assertThat(listener.getEvent()).isNotNull();
then(this.dockerCompose).should().up();
then(this.dockerCompose).should(never()).start();
then(this.dockerCompose).should(never()).down(isA(Duration.class));
then(this.dockerCompose).should(never()).stop(isA(Duration.class));
this.shutdownHandlers.assertNoneAdded();
}
@Test
void startupWhenStartupCommandStartDoesStartupUsingStartAndShutdown() {
this.properties.setLifecycleManagement(LifecycleManagement.START_AND_STOP);
this.properties.getStartup().setCommand(StartupCommand.START);
EventCapturingListener listener = new EventCapturingListener();
this.eventListeners.add(listener);
given(this.dockerCompose.hasDefinedServices()).willReturn(true);
this.lifecycleManager.startup();
this.shutdownHandlers.run();
assertThat(listener.getEvent()).isNotNull();
then(this.dockerCompose).should(never()).up();
then(this.dockerCompose).should().start();
then(this.dockerCompose).should().down(isA(Duration.class));
then(this.dockerCompose).should(never()).stop(isA(Duration.class));
}
@Test
void startupWhenShutdownCommandStopDoesStartupAndShutdownUsingStop() {
this.properties.setLifecycleManagement(LifecycleManagement.START_AND_STOP);
this.properties.getShutdown().setCommand(ShutdownCommand.STOP);
EventCapturingListener listener = new EventCapturingListener();
this.eventListeners.add(listener);
given(this.dockerCompose.hasDefinedServices()).willReturn(true);
this.lifecycleManager.startup();
this.shutdownHandlers.run();
assertThat(listener.getEvent()).isNotNull();
then(this.dockerCompose).should().up();
then(this.dockerCompose).should(never()).start();
then(this.dockerCompose).should(never()).down(isA(Duration.class));
then(this.dockerCompose).should().stop(isA(Duration.class));
}
@Test
void startupWhenHasShutdownTimeoutUsesDuration() {
this.properties.setLifecycleManagement(LifecycleManagement.START_AND_STOP);
Duration timeout = Duration.ofDays(1);
this.properties.getShutdown().setTimeout(timeout);
EventCapturingListener listener = new EventCapturingListener();
this.eventListeners.add(listener);
given(this.dockerCompose.hasDefinedServices()).willReturn(true);
this.lifecycleManager.startup();
this.shutdownHandlers.run();
assertThat(listener.getEvent()).isNotNull();
then(this.dockerCompose).should().down(timeout);
}
@Test
void startupWhenHasIgnoreLabelIgnoresService() {
EventCapturingListener listener = new EventCapturingListener();
this.eventListeners.add(listener);
setupRunningServices(Map.of("org.springframework.boot.ignore", "true"));
this.lifecycleManager.startup();
this.shutdownHandlers.run();
assertThat(listener.getEvent()).isNotNull();
assertThat(listener.getEvent().getRunningServices()).isEmpty();
}
@Test
void startupWaitsUntilReady() {
EventCapturingListener listener = new EventCapturingListener();
this.eventListeners.add(listener);
setupRunningServices();
this.lifecycleManager.startup();
this.shutdownHandlers.run();
then(this.serviceReadinessChecks).should().waitUntilReady(this.runningServices);
}
@Test
void startupGetsDockerComposeWithActiveProfiles() {
this.properties.getProfiles().setActive(Set.of("my-profile"));
setupRunningServices();
this.lifecycleManager.startup();
assertThat(this.activeProfiles).containsExactly("my-profile");
}
@Test
void startupPublishesEvent() {
EventCapturingListener listener = new EventCapturingListener();
this.eventListeners.add(listener);
setupRunningServices();
this.lifecycleManager.startup();
DockerComposeServicesReadyEvent event = listener.getEvent();
assertThat(event).isNotNull();
assertThat(event.getSource()).isEqualTo(this.applicationContext);
assertThat(event.getRunningServices()).isEqualTo(this.runningServices);
}
private void setupRunningServices() {
setupRunningServices(Collections.emptyMap());
}
private void setupRunningServices(Map<String, String> labels) {
given(this.dockerCompose.hasDefinedServices()).willReturn(true);
given(this.dockerCompose.hasRunningServices()).willReturn(true);
RunningService runningService = mock(RunningService.class);
given(runningService.labels()).willReturn(labels);
this.runningServices = List.of(runningService);
given(this.dockerCompose.getRunningServices()).willReturn(this.runningServices);
}
/**
* Testable {@link SpringApplicationShutdownHandlers}.
*/
static class TestSpringApplicationShutdownHandlers implements SpringApplicationShutdownHandlers {
private final List<Runnable> actions = new ArrayList<>();
@Override
public void add(Runnable action) {
this.actions.add(action);
}
@Override
public void remove(Runnable action) {
this.actions.remove(action);
}
void run() {
this.actions.forEach(Runnable::run);
}
void assertNoneAdded() {
assertThat(this.actions).isEmpty();
}
}
/**
* {@link ApplicationListener} to capture the {@link DockerComposeServicesReadyEvent}.
*/
static class EventCapturingListener implements ApplicationListener<DockerComposeServicesReadyEvent> {
private DockerComposeServicesReadyEvent event;
@Override
public void onApplicationEvent(DockerComposeServicesReadyEvent event) {
this.event = event;
}
DockerComposeServicesReadyEvent getEvent() {
return this.event;
}
}
/**
* Testable {@link DockerComposeLifecycleManager}.
*/
class TestDockerComposeLifecycleManager extends DockerComposeLifecycleManager {
TestDockerComposeLifecycleManager(File workingDirectory, ApplicationContext applicationContext, Binder binder,
SpringApplicationShutdownHandlers shutdownHandlers, DockerComposeProperties properties,
Set<ApplicationListener<?>> eventListeners, DockerComposeSkipCheck skipCheck,
ServiceReadinessChecks serviceReadinessChecks) {
super(workingDirectory, applicationContext, binder, shutdownHandlers, properties, eventListeners, skipCheck,
serviceReadinessChecks);
}
@Override
protected DockerComposeFile getComposeFile() {
return DockerComposeLifecycleManagerTests.this.dockerComposeFile;
}
@Override
protected DockerCompose getDockerCompose(DockerComposeFile composeFile, Set<String> activeProfiles) {
DockerComposeLifecycleManagerTests.this.activeProfiles = activeProfiles;
return DockerComposeLifecycleManagerTests.this.dockerCompose;
}
}
}

View File

@@ -0,0 +1,88 @@
/*
* 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.lifecycle;
import java.util.Set;
import org.junit.jupiter.api.Test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationShutdownHandlers;
import org.springframework.boot.context.event.ApplicationPreparedEvent;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.mock.env.MockEnvironment;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link DockerComposeListener}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class DockerComposeListenerTests {
@Test
void onApplicationPreparedEventCreatesAndStartsDockerComposeLifecycleManager() {
SpringApplicationShutdownHandlers shutdownHandlers = mock(SpringApplicationShutdownHandlers.class);
SpringApplication application = mock(SpringApplication.class);
ConfigurableApplicationContext context = mock(ConfigurableApplicationContext.class);
MockEnvironment environment = new MockEnvironment();
given(context.getEnvironment()).willReturn(environment);
TestDockerComposeListener listener = new TestDockerComposeListener(shutdownHandlers, context);
ApplicationPreparedEvent event = new ApplicationPreparedEvent(application, new String[0], context);
listener.onApplicationEvent(event);
assertThat(listener.getManager()).isNotNull();
then(listener.getManager()).should().startup();
}
class TestDockerComposeListener extends DockerComposeListener {
private final ConfigurableApplicationContext context;
private DockerComposeLifecycleManager manager;
TestDockerComposeListener(SpringApplicationShutdownHandlers shutdownHandlers,
ConfigurableApplicationContext context) {
super(shutdownHandlers);
this.context = context;
}
@Override
protected DockerComposeLifecycleManager createDockerComposeLifecycleManager(
ConfigurableApplicationContext applicationContext, Binder binder, DockerComposeProperties properties,
Set<ApplicationListener<?>> eventListeners) {
this.manager = mock(DockerComposeLifecycleManager.class);
assertThat(applicationContext).isSameAs(this.context);
assertThat(binder).isNotNull();
assertThat(properties).isNotNull();
return this.manager;
}
DockerComposeLifecycleManager getManager() {
return this.manager;
}
}
}

View File

@@ -0,0 +1,74 @@
/*
* 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.lifecycle;
import java.io.File;
import java.time.Duration;
import java.util.LinkedHashMap;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.context.properties.source.MapConfigurationPropertySource;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link DockerComposeProperties}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class DockerComposePropertiesTests {
@Test
void getWhenNoPropertiesReturnsNew() {
Binder binder = new Binder(new MapConfigurationPropertySource());
DockerComposeProperties properties = DockerComposeProperties.get(binder);
assertThat(properties.getFile()).isNull();
assertThat(properties.getLifecycleManagement()).isEqualTo(LifecycleManagement.START_AND_STOP);
assertThat(properties.getHost()).isNull();
assertThat(properties.getStartup().getCommand()).isEqualTo(StartupCommand.UP);
assertThat(properties.getShutdown().getCommand()).isEqualTo(ShutdownCommand.DOWN);
assertThat(properties.getShutdown().getTimeout()).isEqualTo(Duration.ofSeconds(10));
assertThat(properties.getProfiles().getActive()).isEmpty();
}
@Test
void getWhenPropertiesReturnsBound() {
Map<String, String> source = new LinkedHashMap<>();
source.put("spring.docker.compose.file", "my-compose.yml");
source.put("spring.docker.compose.lifecycle-management", "start-only");
source.put("spring.docker.compose.host", "myhost");
source.put("spring.docker.compose.startup.command", "start");
source.put("spring.docker.compose.shutdown.command", "stop");
source.put("spring.docker.compose.shutdown.timeout", "5s");
source.put("spring.docker.compose.profiles.active", "myprofile");
Binder binder = new Binder(new MapConfigurationPropertySource(source));
DockerComposeProperties properties = DockerComposeProperties.get(binder);
assertThat(properties.getFile()).isEqualTo(new File("my-compose.yml"));
assertThat(properties.getLifecycleManagement()).isEqualTo(LifecycleManagement.START_ONLY);
assertThat(properties.getHost()).isEqualTo("myhost");
assertThat(properties.getStartup().getCommand()).isEqualTo(StartupCommand.START);
assertThat(properties.getShutdown().getCommand()).isEqualTo(ShutdownCommand.STOP);
assertThat(properties.getShutdown().getTimeout()).isEqualTo(Duration.ofSeconds(5));
assertThat(properties.getProfiles().getActive()).containsExactly("myprofile");
}
}

View File

@@ -0,0 +1,55 @@
/*
* 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.lifecycle;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.springframework.boot.docker.compose.core.RunningService;
import org.springframework.context.ApplicationContext;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link DockerComposeServicesReadyEvent}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class DockerComposeServicesReadyEventTests {
private ApplicationContext applicationContext = mock(ApplicationContext.class);
private List<RunningService> runningServices = List.of(mock(RunningService.class));
private DockerComposeServicesReadyEvent event = new DockerComposeServicesReadyEvent(this.applicationContext,
this.runningServices);
@Test
void getSourceReturnsSource() {
assertThat(this.event.getSource()).isSameAs(this.applicationContext);
}
@Test
void getRunningServicesReturnsRunningServices() {
assertThat(this.event.getRunningServices()).isSameAs(this.runningServices);
}
}

View File

@@ -0,0 +1,62 @@
/*
* 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.lifecycle;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link LifecycleManagement}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class LifecycleManagementTests {
@Test
void shouldStartupWhenNone() {
assertThat(LifecycleManagement.NONE.shouldStartup()).isFalse();
}
@Test
void shouldShutdownWhenNone() {
assertThat(LifecycleManagement.NONE.shouldShutdown()).isFalse();
}
@Test
void shouldStartupWhenStartOnly() {
assertThat(LifecycleManagement.START_ONLY.shouldStartup()).isTrue();
}
@Test
void shouldShutdownWhenStartOnly() {
assertThat(LifecycleManagement.START_ONLY.shouldShutdown()).isFalse();
}
@Test
void shouldStartupWhenStartAndStop() {
assertThat(LifecycleManagement.START_AND_STOP.shouldStartup()).isTrue();
}
@Test
void shouldShutdownWhenStartAndStop() {
assertThat(LifecycleManagement.START_AND_STOP.shouldShutdown()).isTrue();
}
}

View File

@@ -0,0 +1,53 @@
/*
* 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.lifecycle;
import java.time.Duration;
import org.junit.jupiter.api.Test;
import org.springframework.boot.docker.compose.core.DockerCompose;
import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link ShutdownCommand}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class ShutdownCommandTests {
private DockerCompose dockerCompose = mock(DockerCompose.class);
private Duration duration = Duration.ofSeconds(10);
@Test
void applyToWhenDown() {
ShutdownCommand.DOWN.applyTo(this.dockerCompose, this.duration);
then(this.dockerCompose).should().down(this.duration);
}
@Test
void applyToWhenStart() {
ShutdownCommand.STOP.applyTo(this.dockerCompose, this.duration);
then(this.dockerCompose).should().stop(this.duration);
}
}

View File

@@ -0,0 +1,49 @@
/*
* 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.lifecycle;
import org.junit.jupiter.api.Test;
import org.springframework.boot.docker.compose.core.DockerCompose;
import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link StartupCommand}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class StartupCommandTests {
private DockerCompose dockerCompose = mock(DockerCompose.class);
@Test
void applyToWhenUp() {
StartupCommand.UP.applyTo(this.dockerCompose);
then(this.dockerCompose).should().up();
}
@Test
void applyToWhenStart() {
StartupCommand.START.applyTo(this.dockerCompose);
then(this.dockerCompose).should().start();
}
}

View File

@@ -0,0 +1,62 @@
/*
* 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.readiness;
import java.time.Duration;
import java.util.LinkedHashMap;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.context.properties.source.MapConfigurationPropertySource;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link ReadinessProperties}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class ReadinessPropertiesTests {
@Test
void getWhenNoPropertiesReturnsNewInstance() {
Binder binder = new Binder(new MapConfigurationPropertySource());
ReadinessProperties properties = ReadinessProperties.get(binder);
assertThat(properties.getTimeout()).isEqualTo(Duration.ofMinutes(2));
assertThat(properties.getTcp().getConnectTimeout()).isEqualTo(Duration.ofMillis(200));
assertThat(properties.getTcp().getReadTimeout()).isEqualTo(Duration.ofMillis(200));
}
@Test
void getWhenPropertiesReturnsBoundInstance() {
Map<String, String> source = new LinkedHashMap<>();
source.put("spring.docker.compose.readiness.timeout", "10s");
source.put("spring.docker.compose.readiness.tcp.connect-timeout", "400ms");
source.put("spring.docker.compose.readiness.tcp.read-timeout", "500ms");
Binder binder = new Binder(new MapConfigurationPropertySource(source));
ReadinessProperties properties = ReadinessProperties.get(binder);
assertThat(properties.getTimeout()).isEqualTo(Duration.ofSeconds(10));
assertThat(properties.getTcp().getConnectTimeout()).isEqualTo(Duration.ofMillis(400));
assertThat(properties.getTcp().getReadTimeout()).isEqualTo(Duration.ofMillis(500));
}
}

View File

@@ -0,0 +1,55 @@
/*
* 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.readiness;
import java.time.Duration;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.springframework.boot.docker.compose.core.RunningService;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link ReadinessTimeoutException}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class ReadinessTimeoutExceptionTests {
@Test
void createCreatesException() {
Duration timeout = Duration.ofSeconds(10);
RunningService s1 = mock(RunningService.class);
given(s1.name()).willReturn("s1");
RunningService s2 = mock(RunningService.class);
given(s2.name()).willReturn("s2");
ServiceNotReadyException cause1 = new ServiceNotReadyException(s1, "1 not ready");
ServiceNotReadyException cause2 = new ServiceNotReadyException(s2, "2 not ready");
List<ServiceNotReadyException> exceptions = List.of(cause1, cause2);
ReadinessTimeoutException exception = new ReadinessTimeoutException(timeout, exceptions);
assertThat(exception).hasMessage("Readiness timeout of PT10S reached while waiting for services [s1, s2]");
assertThat(exception).hasSuppressedException(cause1).hasSuppressedException(cause2);
assertThat(exception.getTimeout()).isEqualTo(timeout);
}
}

View File

@@ -0,0 +1,42 @@
/*
* 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.readiness;
import org.junit.jupiter.api.Test;
import org.springframework.boot.docker.compose.core.RunningService;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link ServiceNotReadyException}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class ServiceNotReadyExceptionTests {
@Test
void getServiceReturnsService() {
RunningService service = mock(RunningService.class);
ServiceNotReadyException exception = new ServiceNotReadyException(service, "fail");
assertThat(exception.getService()).isEqualTo(service);
}
}

View File

@@ -0,0 +1,174 @@
/*
* 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.readiness;
import java.time.Clock;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.docker.compose.core.RunningService;
import org.springframework.core.env.Environment;
import org.springframework.core.io.support.SpringFactoriesLoader.ArgumentResolver;
import org.springframework.core.test.io.support.MockSpringFactoriesLoader;
import org.springframework.mock.env.MockEnvironment;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
/**
* Tests for {@link ServiceReadinessChecks}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class ServiceReadinessChecksTests {
private Clock clock;
Instant now = Instant.now();
private MockSpringFactoriesLoader loader;
private ClassLoader classLoader;
private MockEnvironment environment;
private Binder binder;
private RunningService runningService;
private List<RunningService> runningServices;
private MockServiceReadinessCheck mockTcpCheck = new MockServiceReadinessCheck();
@BeforeEach
void setup() {
this.clock = mock(Clock.class);
given(this.clock.instant()).willAnswer((args) -> this.now);
this.loader = new MockSpringFactoriesLoader();
this.classLoader = getClass().getClassLoader();
this.environment = new MockEnvironment();
this.binder = Binder.get(this.environment);
this.runningService = mock(RunningService.class);
this.runningServices = List.of(this.runningService);
}
@Test
void loadCanResolveArguments() {
this.loader = spy(MockSpringFactoriesLoader.class);
createChecks();
ArgumentCaptor<ArgumentResolver> captor = ArgumentCaptor.forClass(ArgumentResolver.class);
then(this.loader).should().load(eq(ServiceReadinessCheck.class), captor.capture());
ArgumentResolver argumentResolver = captor.getValue();
assertThat(argumentResolver.resolve(ClassLoader.class)).isEqualTo(this.classLoader);
assertThat(argumentResolver.resolve(Environment.class)).isEqualTo(this.environment);
assertThat(argumentResolver.resolve(Binder.class)).isEqualTo(this.binder);
}
@Test
void waitUntilReadyWhenImmediatelyReady() {
MockServiceReadinessCheck check = new MockServiceReadinessCheck();
this.loader.addInstance(ServiceReadinessCheck.class, check);
createChecks().waitUntilReady(this.runningServices);
assertThat(check.getChecked()).contains(this.runningService);
assertThat(this.mockTcpCheck.getChecked()).contains(this.runningService);
}
@Test
void waitUntilReadyWhenTakesTimeToBeReady() {
MockServiceReadinessCheck check = new MockServiceReadinessCheck(2);
this.loader.addInstance(ServiceReadinessCheck.class, check);
createChecks().waitUntilReady(this.runningServices);
assertThat(check.getChecked()).hasSize(2).contains(this.runningService);
assertThat(this.mockTcpCheck.getChecked()).contains(this.runningService);
}
@Test
void waitUntilReadyWhenTimeout() {
MockServiceReadinessCheck check = new MockServiceReadinessCheck(Integer.MAX_VALUE);
this.loader.addInstance(ServiceReadinessCheck.class, check);
assertThatExceptionOfType(ReadinessTimeoutException.class)
.isThrownBy(() -> createChecks().waitUntilReady(this.runningServices))
.satisfies((ex) -> assertThat(ex.getSuppressed()).hasSize(1));
assertThat(check.getChecked()).hasSizeGreaterThan(10);
}
@Test
void waitForWhenServiceHasDisableLabelDoesNotCheck() {
given(this.runningService.labels()).willReturn(Map.of("org.springframework.boot.readiness-check.disable", ""));
MockServiceReadinessCheck check = new MockServiceReadinessCheck();
this.loader.addInstance(ServiceReadinessCheck.class, check);
createChecks().waitUntilReady(this.runningServices);
assertThat(check.getChecked()).isEmpty();
assertThat(this.mockTcpCheck.getChecked()).isEmpty();
}
void sleep(Duration duration) {
this.now = this.now.plus(duration);
}
private ServiceReadinessChecks createChecks() {
return new ServiceReadinessChecks(this.clock, this::sleep, this.loader, this.classLoader, this.environment,
this.binder, (properties) -> this.mockTcpCheck);
}
/**
* Mock {@link ServiceReadinessCheck}.
*/
static class MockServiceReadinessCheck implements ServiceReadinessCheck {
private final Integer failUntil;
private final List<RunningService> checked = new ArrayList<>();
MockServiceReadinessCheck() {
this(null);
}
MockServiceReadinessCheck(Integer failUntil) {
this.failUntil = failUntil;
}
@Override
public void check(RunningService service) throws ServiceNotReadyException {
this.checked.add(service);
if (this.failUntil != null && this.checked.size() < this.failUntil) {
throw new ServiceNotReadyException(service, "Waiting");
}
}
List<RunningService> getChecked() {
return this.checked;
}
}
}

View File

@@ -0,0 +1,126 @@
/*
* 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.readiness;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.time.Duration;
import java.util.List;
import org.assertj.core.api.ThrowingConsumer;
import org.junit.jupiter.api.BeforeEach;
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.assertThatExceptionOfType;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link TcpConnectServiceReadinessCheck}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class TcpConnectServiceReadinessCheckTests {
private static final int EPHEMERAL_PORT = 0;
private TcpConnectServiceReadinessCheck readinessCheck;
@BeforeEach
void setup() {
ReadinessProperties.Tcp tcpProperties = new ReadinessProperties.Tcp();
tcpProperties.setConnectTimeout(Duration.ofMillis(100));
tcpProperties.setReadTimeout(Duration.ofMillis(100));
this.readinessCheck = new TcpConnectServiceReadinessCheck(tcpProperties);
}
@Test
void checkWhenServerWritesData() throws Exception {
withServer((socket) -> socket.getOutputStream().write('!'), (port) -> check(port));
}
@Test
void checkWhenNoSocketOutput() throws Exception {
// Simulate waiting for traffic from client to server. The sleep duration must
// be longer than the read timeout of the ready check!
withServer((socket) -> sleep(Duration.ofSeconds(10)), (port) -> check(port));
}
@Test
void checkWhenImmediateDisconnect() throws IOException {
withServer(Socket::close,
(port) -> assertThatExceptionOfType(ServiceNotReadyException.class).isThrownBy(() -> check(port))
.withMessage("Immediate disconnect while connecting to port %d".formatted(port)));
}
@Test
void checkWhenNoServerListening() {
assertThatExceptionOfType(ServiceNotReadyException.class).isThrownBy(() -> check(12345))
.withMessage("IOException while connecting to port 12345");
}
private void withServer(ThrowingConsumer<Socket> socketAction, ThrowingConsumer<Integer> portAction)
throws IOException {
try (ServerSocket serverSocket = new ServerSocket()) {
serverSocket.bind(new InetSocketAddress("127.0.0.1", EPHEMERAL_PORT));
Thread thread = new Thread(() -> {
try (Socket socket = serverSocket.accept()) {
socketAction.accept(socket);
}
catch (IOException ex) {
throw new UncheckedIOException(ex);
}
});
thread.setName("Acceptor-%d".formatted(serverSocket.getLocalPort()));
thread.setUncaughtExceptionHandler((ignored, ex) -> ex.printStackTrace());
thread.setDaemon(true);
thread.start();
portAction.accept(serverSocket.getLocalPort());
}
}
private void check(Integer port) {
this.readinessCheck.check(mockRunningService(port));
}
private RunningService mockRunningService(Integer port) {
RunningService runningService = mock(RunningService.class);
ConnectionPorts ports = mock(ConnectionPorts.class);
given(ports.getAll("tcp")).willReturn(List.of(port));
given(runningService.host()).willReturn("localhost");
given(runningService.ports()).willReturn(ports);
return runningService;
}
private void sleep(Duration duration) {
try {
Thread.sleep(duration.toMillis());
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}

View File

@@ -0,0 +1,56 @@
/*
* 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.elasticsearch;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchConnectionDetails;
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchConnectionDetails.Node;
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchConnectionDetails.Node.Protocol;
import org.springframework.boot.docker.compose.service.connection.test.AbstractDockerComposeIntegrationTests;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration tests for {@link ElasticsearchDockerComposeConnectionDetailsFactory}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class ElasticsearchDockerComposeConnectionDetailsFactoryIntegrationTests extends AbstractDockerComposeIntegrationTests {
ElasticsearchDockerComposeConnectionDetailsFactoryIntegrationTests() {
super("elasticsearch-compose.yaml");
}
@Test
void runCreatesConnectionDetails() {
ElasticsearchConnectionDetails connectionDetails = run(ElasticsearchConnectionDetails.class);
assertThat(connectionDetails.getUsername()).isEqualTo("elastic");
assertThat(connectionDetails.getPassword()).isEqualTo("secret");
assertThat(connectionDetails.getPathPrefix()).isNull();
assertThat(connectionDetails.getNodes()).hasSize(1);
Node node = connectionDetails.getNodes().get(0);
assertThat(node.hostname()).isNotNull();
assertThat(node.port()).isGreaterThan(0);
assertThat(node.protocol()).isEqualTo(Protocol.HTTP);
assertThat(node.username()).isEqualTo("elastic");
assertThat(node.password()).isEqualTo("secret");
}
}

View File

@@ -0,0 +1,55 @@
/*
* 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.elasticsearch;
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 ElasticsearchEnvironment}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class ElasticsearchEnvironmentTests {
@Test
void createWhenHasElasticPasswordFileThrowsException() {
assertThatIllegalStateException()
.isThrownBy(() -> new ElasticsearchEnvironment(Map.of("ELASTIC_PASSWORD_FILE", "afile")))
.withMessage("ELASTIC_PASSWORD_FILE is not supported");
}
@Test
void getPasswordWhenNoPassword() {
ElasticsearchEnvironment environment = new ElasticsearchEnvironment(Collections.emptyMap());
assertThat(environment.getPassword()).isNull();
}
@Test
void getPasswordWhenHasPassword() {
ElasticsearchEnvironment environment = new ElasticsearchEnvironment(Map.of("ELASTIC_PASSWORD", "secret"));
assertThat(environment.getPassword()).isEqualTo("secret");
}
}

View File

@@ -0,0 +1,101 @@
/*
* 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.elasticsearch;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.fail;
/**
* Tests for {@link ElasticsearchDockerComposeConnectionDetailsFactory}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
@Disabled
class XElasticsearchDockerComposeConnectionDetailsFactoryTests {
@Test
void test() {
fail("Not yet implemented");
}
// @formatter:off
/*
@Test
void usernameIsElastic() {
RunningService service = createService(Collections.emptyMap());
ElasticsearchService elasticsearchService = new ElasticsearchService(service);
assertThat(elasticsearchService.getUsername()).isEqualTo("elastic");
}
@Test
void passwordUsesEnvVariable() {
RunningService service = createService(Map.of("ELASTIC_PASSWORD", "some-secret-password"));
ElasticsearchService elasticsearchService = new ElasticsearchService(service);
assertThat(elasticsearchService.getPassword()).isEqualTo("some-secret-password");
}
@Test
void passwordHasFallback() {
RunningService service = createService(Collections.emptyMap());
ElasticsearchService elasticsearchService = new ElasticsearchService(service);
assertThat(elasticsearchService.getPassword()).isNull();
}
@Test
void passwordDoesNotSupportFile() {
RunningService service = createService(Map.of("ELASTIC_PASSWORD_FILE", "/password.txt"));
ElasticsearchService elasticsearchService = new ElasticsearchService(service);
assertThatThrownBy(elasticsearchService::getPassword).isInstanceOf(IllegalStateException.class)
.hasMessageContaining("ELASTIC_PASSWORD_FILE");
}
@Test
void getPort() {
RunningService service = createService(Collections.emptyMap());
ElasticsearchService elasticsearchService = new ElasticsearchService(service);
assertThat(elasticsearchService.getPort()).isEqualTo(19200);
}
@Test
void matches() {
assertThat(ElasticsearchService.matches(createService(Collections.emptyMap()))).isTrue();
assertThat(
ElasticsearchService.matches(createService(ImageReference.parse("redis:7.1"), Collections.emptyMap())))
.isFalse();
}
private RunningService createService(Map<String, String> env) {
return createService(ImageReference.parse("elasticsearch:8.6.2"), env);
}
private RunningService createService(ImageReference image, Map<String, String> env) {
return RunningServiceBuilder.create("service-1", image).addTcpPort(9200, 19200).env(env).build();
}
*/
// @formatter:on
}

View File

@@ -0,0 +1,89 @@
/*
* 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.jdbc;
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 buildBuildsUrl() {
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 buildWhenServiceIsNullThrowsException() {
assertThatIllegalArgumentException().isThrownBy(() -> this.builder.build(null, "mydb"))
.withMessage("Service must not be null");
}
@Test
void buildWhenDatabaseIsNullThrowsException() {
assertThatIllegalArgumentException().isThrownBy(() -> this.builder.build(mockService(456), null))
.withMessage("Database 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,167 @@
/*
* 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.mariadb;
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
*/
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 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,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.docker.compose.service.connection.mariadb;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.jdbc.JdbcConnectionDetails;
import org.springframework.boot.docker.compose.service.connection.test.AbstractDockerComposeIntegrationTests;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration tests for {@link MariaDbJdbcDockerComposeConnectionDetailsFactory}
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class MariaDbJdbcDockerComposeConnectionDetailsFactoryIntegrationTests extends AbstractDockerComposeIntegrationTests {
MariaDbJdbcDockerComposeConnectionDetailsFactoryIntegrationTests() {
super("mariadb-compose.yaml");
}
@Test
void runCreatesConnectionDetails() {
JdbcConnectionDetails connectionDetails = run(JdbcConnectionDetails.class);
assertThat(connectionDetails.getUsername()).isEqualTo("myuser");
assertThat(connectionDetails.getPassword()).isEqualTo("secret");
assertThat(connectionDetails.getJdbcUrl()).startsWith("jdbc:mariadb://").endsWith("/mydatabase");
}
}

View File

@@ -0,0 +1,49 @@
/*
* 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.mariadb;
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 MariaDbR2dbcDockerComposeConnectionDetailsFactory}
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class MariaDbR2dbcDockerComposeConnectionDetailsFactoryIntegrationTests extends AbstractDockerComposeIntegrationTests {
MariaDbR2dbcDockerComposeConnectionDetailsFactoryIntegrationTests() {
super("mariadb-compose.yaml");
}
@Test
void runCreatesConnectionDetails() {
R2dbcConnectionDetails connectionDetails = run(R2dbcConnectionDetails.class);
ConnectionFactoryOptions connectionFactoryOptions = connectionDetails.getConnectionFactoryOptions();
assertThat(connectionFactoryOptions.toString()).contains("database=mydatabase", "driver=mariadb",
"password=REDACTED", "user=myuser");
assertThat(connectionFactoryOptions.getRequiredValue(ConnectionFactoryOptions.PASSWORD)).isEqualTo("secret");
}
}

View File

@@ -0,0 +1,190 @@
/*
* 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.mariadb;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.fail;
/**
* Tests for {@link XMariaDbDockerComposeConnectionDetailsFactoryTests}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
@Disabled
class XMariaDbDockerComposeConnectionDetailsFactoryTests {
@Test
void test() {
fail("Not yet implemented");
}
// @formatter:off
/*
@Test
void usernameUsesMariaDbVariables() {
RunningService service = createService(Map.of("MARIADB_USER", "user-1"));
MariaDbService mariaDbService = new MariaDbService(service);
assertThat(mariaDbService.getUsername()).isEqualTo("user-1");
}
@Test
void usernameUsesMysqlVariables() {
RunningService service = createService(Map.of("MYSQL_USER", "user-1"));
MariaDbService mariaDbService = new MariaDbService(service);
assertThat(mariaDbService.getUsername()).isEqualTo("user-1");
}
@Test
void usernameDefaultsToRoot() {
RunningService service = createService(Collections.emptyMap());
MariaDbService mariaDbService = new MariaDbService(service);
assertThat(mariaDbService.getUsername()).isEqualTo("root");
}
@Test
void passwordUsesMariaDbVariables() {
RunningService service = createService(Map.of("MARIADB_PASSWORD", "password-1"));
MariaDbService mariaDbService = new MariaDbService(service);
assertThat(mariaDbService.getPassword()).isEqualTo("password-1");
}
@Test
void passwordUsesMysqlVariables() {
RunningService service = createService(Map.of("MYSQL_PASSWORD", "password-1"));
MariaDbService mariaDbService = new MariaDbService(service);
assertThat(mariaDbService.getPassword()).isEqualTo("password-1");
}
@Test
void passwordUsesMariaDbRootVariables() {
RunningService service = createService(Map.of("MARIADB_ROOT_PASSWORD", "root-password-1"));
MariaDbService mariaDbService = new MariaDbService(service);
assertThat(mariaDbService.getPassword()).isEqualTo("root-password-1");
}
@Test
void passwordUsesMysqlRootVariables() {
RunningService service = createService(Map.of("MYSQL_ROOT_PASSWORD", "root-password-1"));
MariaDbService mariaDbService = new MariaDbService(service);
assertThat(mariaDbService.getPassword()).isEqualTo("root-password-1");
}
@Test
void passwordSupportsEmptyRootPasswordMariaDb() {
RunningService service = createService(Map.of("MARIADB_ALLOW_EMPTY_ROOT_PASSWORD", ""));
MariaDbService mariaDbService = new MariaDbService(service);
assertThat(mariaDbService.getPassword()).isEqualTo("");
}
@Test
void passwordDoesNotSupportRootPasswordHash() {
RunningService service = createService(Map.of("MARIADB_ROOT_PASSWORD_HASH", "true"));
MariaDbService mariaDbService = new MariaDbService(service);
assertThatThrownBy(mariaDbService::getPassword).isInstanceOf(IllegalStateException.class)
.hasMessageContaining("MARIADB_ROOT_PASSWORD_HASH");
}
@Test
void passwordDoesNotSupportRandomRootPasswordMariaDb() {
RunningService service = createService(Map.of("MARIADB_RANDOM_ROOT_PASSWORD", "true"));
MariaDbService mariaDbService = new MariaDbService(service);
assertThatThrownBy(mariaDbService::getPassword).isInstanceOf(IllegalStateException.class)
.hasMessageContaining("MARIADB_RANDOM_ROOT_PASSWORD");
}
@Test
void passwordDoesNotSupportRandomRootPasswordMysql() {
RunningService service = createService(Map.of("MYSQL_RANDOM_ROOT_PASSWORD", "true"));
MariaDbService mariaDbService = new MariaDbService(service);
assertThatThrownBy(mariaDbService::getPassword).isInstanceOf(IllegalStateException.class)
.hasMessageContaining("MYSQL_RANDOM_ROOT_PASSWORD");
}
@Test
void passwordHasNoFallback() {
RunningService service = createService(Collections.emptyMap());
MariaDbService mariaDbService = new MariaDbService(service);
assertThatThrownBy(mariaDbService::getPassword).isInstanceOf(IllegalStateException.class)
.hasMessage("Can't find password for user");
}
@Test
void passwordSupportsEmptyRootPasswordMysql() {
RunningService service = createService(Map.of("MYSQL_ALLOW_EMPTY_PASSWORD", ""));
MariaDbService mariaDbService = new MariaDbService(service);
assertThat(mariaDbService.getPassword()).isEqualTo("");
}
@Test
void databaseUsesMariaDbVariables() {
RunningService service = createService(Map.of("MARIADB_DATABASE", "database-1"));
MariaDbService mariaDbService = new MariaDbService(service);
assertThat(mariaDbService.getDatabase()).isEqualTo("database-1");
}
@Test
void databaseUsesMysqlVariables() {
RunningService service = createService(Map.of("MYSQL_DATABASE", "database-1"));
MariaDbService mariaDbService = new MariaDbService(service);
assertThat(mariaDbService.getDatabase()).isEqualTo("database-1");
}
@Test
void databaseHasNoFallback() {
RunningService service = createService(Collections.emptyMap());
MariaDbService mariaDbService = new MariaDbService(service);
assertThatThrownBy(mariaDbService::getDatabase).isInstanceOf(IllegalStateException.class)
.hasMessageContaining("MARIADB_DATABASE")
.hasMessageContaining("MYSQL_DATABASE");
}
@Test
void getPort() {
RunningService service = createService(Collections.emptyMap());
MariaDbService mariaDbService = new MariaDbService(service);
assertThat(mariaDbService.getPort()).isEqualTo(33060);
}
@Test
void matches() {
assertThat(MariaDbService.matches(createService(Collections.emptyMap()))).isTrue();
assertThat(MariaDbService.matches(createService(ImageReference.parse("redis:7.1"), Collections.emptyMap())))
.isFalse();
}
private RunningService createService(Map<String, String> env) {
return createService(ImageReference.parse("mariadb:10.10"), env);
}
private RunningService createService(ImageReference image, Map<String, String> env) {
return RunningServiceBuilder.create("service-1", image).addTcpPort(3306, 33060).env(env).build();
}
*/
// @formatter:on
}

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.docker.compose.service.connection.mongo;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.mongo.MongoConnectionDetails;
import org.springframework.boot.docker.compose.service.connection.test.AbstractDockerComposeIntegrationTests;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration tests for {@link MongoDockerComposeConnectionDetailsFactory}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class MongoDockerComposeConnectionDetailsFactoryIntegrationTests extends AbstractDockerComposeIntegrationTests {
MongoDockerComposeConnectionDetailsFactoryIntegrationTests() {
super("mongo-compose.yaml");
}
@Test
void runCreatesConnectionDetails() {
MongoConnectionDetails connectionDetails = run(MongoConnectionDetails.class);
assertThat(connectionDetails.getConnectionString().toString()).startsWith("mongodb://root:secret@")
.endsWith("/mydatabase");
assertThat(connectionDetails.getGridFs()).isNull();
}
}

View File

@@ -0,0 +1,86 @@
/*
* 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.mongo;
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 MongoEnvironment}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class MongoEnvironmentTests {
@Test
void createWhenMonoInitdbRootUsernameFileSetThrowsException() {
assertThatIllegalStateException()
.isThrownBy(() -> new MongoEnvironment(Map.of("MONGO_INITDB_ROOT_USERNAME_FILE", "file")))
.withMessage("MONGO_INITDB_ROOT_USERNAME_FILE is not supported");
}
@Test
void createWhenMonoInitdbRootPasswordFileSetThrowsException() {
assertThatIllegalStateException()
.isThrownBy(() -> new MongoEnvironment(Map.of("MONGO_INITDB_ROOT_PASSWORD_FILE", "file")))
.withMessage("MONGO_INITDB_ROOT_PASSWORD_FILE is not supported");
}
@Test
void getUsernameWhenHasNoMongoInitdbRootUsernameSet() {
MongoEnvironment environment = new MongoEnvironment(Collections.emptyMap());
assertThat(environment.getUsername()).isNull();
}
@Test
void getUsernameWhenHasMongoInitdbRootUsernameSet() {
MongoEnvironment environment = new MongoEnvironment(Map.of("MONGO_INITDB_ROOT_USERNAME", "user"));
assertThat(environment.getUsername()).isEqualTo("user");
}
@Test
void getPasswordWhenHasNoMongoInitdbRootPasswordSet() {
MongoEnvironment environment = new MongoEnvironment(Collections.emptyMap());
assertThat(environment.getPassword()).isNull();
}
@Test
void getPasswordWhenHasMongoInitdbRootPasswordSet() {
MongoEnvironment environment = new MongoEnvironment(Map.of("MONGO_INITDB_ROOT_PASSWORD", "secret"));
assertThat(environment.getPassword()).isEqualTo("secret");
}
@Test
void getDatabaseWhenHasNoMongoInitdbDatabaseSet() {
MongoEnvironment environment = new MongoEnvironment(Collections.emptyMap());
assertThat(environment.getDatabase()).isNull();
}
@Test
void getDatabaseWhenHasMongoInitdbDatabaseSet() {
MongoEnvironment environment = new MongoEnvironment(Map.of("MONGO_INITDB_DATABASE", "db"));
assertThat(environment.getDatabase()).isEqualTo("db");
}
}

View File

@@ -0,0 +1,130 @@
/*
* 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.mongo;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.fail;
/**
* Tests for {@link MongoDockerComposeConnectionDetailsFactory}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
@Disabled
class XMongoDockerComposeConnectionDetailsFactoryTests {
@Test
void test() {
fail("Not yet implemented");
}
// @formatter:off
/*
@Test
void usernameUsesEnvVariable() {
RunningService service = createService(Map.of("MONGO_INITDB_ROOT_USERNAME", "user-1"));
MongoService mongoService = new MongoService(service);
assertThat(mongoService.getUsername()).isEqualTo("user-1");
}
@Test
void doesNotSupportUsernameFile() {
RunningService service = createService(Map.of("MONGO_INITDB_ROOT_USERNAME_FILE", "/username.txt"));
MongoService mongoService = new MongoService(service);
assertThatThrownBy(mongoService::getUsername).isInstanceOf(IllegalStateException.class)
.hasMessage("MONGO_INITDB_ROOT_USERNAME_FILE is not supported");
}
@Test
void usernameHasDefault() {
RunningService service = createService(Collections.emptyMap());
MongoService mongoService = new MongoService(service);
assertThat(mongoService.getUsername()).isNull();
}
@Test
void passwordUsesEnvVariable() {
RunningService service = createService(Map.of("MONGO_INITDB_ROOT_PASSWORD", "some-secret-1"));
MongoService mongoService = new MongoService(service);
assertThat(mongoService.getPassword()).isEqualTo("some-secret-1");
}
@Test
void doesNotSupportPasswordFile() {
RunningService service = createService(Map.of("MONGO_INITDB_ROOT_PASSWORD_FILE", "/username.txt"));
MongoService mongoService = new MongoService(service);
assertThatThrownBy(mongoService::getPassword).isInstanceOf(IllegalStateException.class)
.hasMessage("MONGO_INITDB_ROOT_PASSWORD_FILE is not supported");
}
@Test
void passwordHasDefault() {
RunningService service = createService(Collections.emptyMap());
MongoService mongoService = new MongoService(service);
assertThat(mongoService.getPassword()).isNull();
}
@Test
void databaseUsesEnvVariable() {
RunningService service = createService(Map.of("MONGO_INITDB_DATABASE", "database-1"));
MongoService mongoService = new MongoService(service);
assertThat(mongoService.getDatabase()).isEqualTo("database-1");
}
@Test
void databaseHasDefault() {
RunningService service = createService(Collections.emptyMap());
MongoService mongoService = new MongoService(service);
assertThat(mongoService.getDatabase()).isNull();
}
@Test
void getPort() {
RunningService service = createService(Collections.emptyMap());
MongoService mongoService = new MongoService(service);
assertThat(mongoService.getPort()).isEqualTo(12345);
}
@Test
void matches() {
assertThat(MongoService.matches(createService(Collections.emptyMap()))).isTrue();
assertThat(MongoService.matches(createService(ImageReference.parse("redis:7.1"), Collections.emptyMap())))
.isFalse();
}
private RunningService createService(Map<String, String> env) {
return createService(ImageReference.parse("mongo:6.0"), env);
}
private RunningService createService(ImageReference image, Map<String, String> env) {
return RunningServiceBuilder.create("service-1", image).addTcpPort(27017, 12345).env(env).build();
}
*/
// @formatter:on
}

View File

@@ -0,0 +1,95 @@
/*
* 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.mysql;
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
*/
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 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,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.docker.compose.service.connection.mysql;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.jdbc.JdbcConnectionDetails;
import org.springframework.boot.docker.compose.service.connection.test.AbstractDockerComposeIntegrationTests;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration tests for {@link MySqlJdbcDockerComposeConnectionDetailsFactory}
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class MySqlJdbcDockerComposeConnectionDetailsFactoryIntegrationTests extends AbstractDockerComposeIntegrationTests {
MySqlJdbcDockerComposeConnectionDetailsFactoryIntegrationTests() {
super("mysql-compose.yaml");
}
@Test
void runCreatesConnectionDetails() {
JdbcConnectionDetails connectionDetails = run(JdbcConnectionDetails.class);
assertThat(connectionDetails.getUsername()).isEqualTo("myuser");
assertThat(connectionDetails.getPassword()).isEqualTo("secret");
assertThat(connectionDetails.getJdbcUrl()).startsWith("jdbc:mysql://").endsWith("/mydatabase");
}
}

View File

@@ -0,0 +1,49 @@
/*
* 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.mysql;
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 MySqlR2dbcDockerComposeConnectionDetailsFactory}
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class MySqlR2dbcDockerComposeConnectionDetailsFactoryIntegrationTests extends AbstractDockerComposeIntegrationTests {
MySqlR2dbcDockerComposeConnectionDetailsFactoryIntegrationTests() {
super("mysql-compose.yaml");
}
@Test
void runCreatesConnectionDetails() {
R2dbcConnectionDetails connectionDetails = run(R2dbcConnectionDetails.class);
ConnectionFactoryOptions connectionFactoryOptions = connectionDetails.getConnectionFactoryOptions();
assertThat(connectionFactoryOptions.toString()).contains("database=mydatabase", "driver=mysql",
"password=REDACTED", "user=myuser");
assertThat(connectionFactoryOptions.getRequiredValue(ConnectionFactoryOptions.PASSWORD)).isEqualTo("secret");
}
}

View File

@@ -0,0 +1,137 @@
/*
* 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.mysql;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.fail;
/**
* Test for {@link MySqlR2dbcDockerComposeConnectionDetailsFactory}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
@Disabled
class XMySqlDbR2dbcDockerComposeConnectionDetailsFactoryTests {
@Test
void test() {
fail("Not yet implemented");
}
// @formatter:off
/*
@Test
void usernameUsesMysqlVariables() {
RunningService service = createService(Map.of("MYSQL_USER", "user-1"));
MySqlService mysqlService = new MySqlService(service);
assertThat(mysqlService.getUsername()).isEqualTo("user-1");
}
@Test
void usernameDefaultsToRoot() {
RunningService service = createService(Collections.emptyMap());
MySqlService mysqlService = new MySqlService(service);
assertThat(mysqlService.getUsername()).isEqualTo("root");
}
@Test
void passwordUsesMysqlVariables() {
RunningService service = createService(Map.of("MYSQL_PASSWORD", "password-1"));
MySqlService mysqlService = new MySqlService(service);
assertThat(mysqlService.getPassword()).isEqualTo("password-1");
}
@Test
void passwordUsesMysqlRootVariables() {
RunningService service = createService(Map.of("MYSQL_ROOT_PASSWORD", "root-password-1"));
MySqlService mysqlService = new MySqlService(service);
assertThat(mysqlService.getPassword()).isEqualTo("root-password-1");
}
@Test
void passwordDoesNotSupportRandomRootPasswordMysql() {
RunningService service = createService(Map.of("MYSQL_RANDOM_ROOT_PASSWORD", "true"));
MySqlService mysqlService = new MySqlService(service);
assertThatThrownBy(mysqlService::getPassword).isInstanceOf(IllegalStateException.class)
.hasMessageContaining("MYSQL_RANDOM_ROOT_PASSWORD");
}
@Test
void passwordHasNoFallback() {
RunningService service = createService(Collections.emptyMap());
MySqlService mysqlService = new MySqlService(service);
assertThatThrownBy(mysqlService::getPassword).isInstanceOf(IllegalStateException.class)
.hasMessage("Can't find password for user");
}
@Test
void passwordSupportsEmptyRootPasswordMysql() {
RunningService service = createService(Map.of("MYSQL_ALLOW_EMPTY_PASSWORD", ""));
MySqlService mysqlService = new MySqlService(service);
assertThat(mysqlService.getPassword()).isEqualTo("");
}
@Test
void databaseUsesMysqlVariables() {
RunningService service = createService(Map.of("MYSQL_DATABASE", "database-1"));
MySqlService mysqlService = new MySqlService(service);
assertThat(mysqlService.getDatabase()).isEqualTo("database-1");
}
@Test
void databaseHasNoFallback() {
RunningService service = createService(Collections.emptyMap());
MySqlService mysqlService = new MySqlService(service);
assertThatThrownBy(mysqlService::getDatabase).isInstanceOf(IllegalStateException.class)
.hasMessageContaining("MYSQL_DATABASE");
}
@Test
void getPort() {
RunningService service = createService(Collections.emptyMap());
MySqlService mysqlService = new MySqlService(service);
assertThat(mysqlService.getPort()).isEqualTo(33060);
}
@Test
void matches() {
assertThat(MySqlService.matches(createService(Collections.emptyMap()))).isTrue();
assertThat(MySqlService.matches(createService(ImageReference.parse("redis:7.1"), Collections.emptyMap())))
.isFalse();
}
private RunningService createService(Map<String, String> env) {
return createService(ImageReference.parse("mysql:8.0"), env);
}
private RunningService createService(ImageReference image, Map<String, String> env) {
return RunningServiceBuilder.create("service-1", image).addTcpPort(3306, 33060).env(env).build();
}
*/
// @formatter:on
}

View File

@@ -0,0 +1,137 @@
/*
* 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.mysql;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.fail;
/**
* Test for {@link MySqlJdbcDockerComposeConnectionDetailsFactory}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
@Disabled
class XMySqlJdbcDockerComposeConnectionDetailsFactoryTests {
@Test
void test() {
fail("Not yet implemented");
}
// @formatter:off
/*
@Test
void usernameUsesMysqlVariables() {
RunningService service = createService(Map.of("MYSQL_USER", "user-1"));
MySqlService mysqlService = new MySqlService(service);
assertThat(mysqlService.getUsername()).isEqualTo("user-1");
}
@Test
void usernameDefaultsToRoot() {
RunningService service = createService(Collections.emptyMap());
MySqlService mysqlService = new MySqlService(service);
assertThat(mysqlService.getUsername()).isEqualTo("root");
}
@Test
void passwordUsesMysqlVariables() {
RunningService service = createService(Map.of("MYSQL_PASSWORD", "password-1"));
MySqlService mysqlService = new MySqlService(service);
assertThat(mysqlService.getPassword()).isEqualTo("password-1");
}
@Test
void passwordUsesMysqlRootVariables() {
RunningService service = createService(Map.of("MYSQL_ROOT_PASSWORD", "root-password-1"));
MySqlService mysqlService = new MySqlService(service);
assertThat(mysqlService.getPassword()).isEqualTo("root-password-1");
}
@Test
void passwordDoesNotSupportRandomRootPasswordMysql() {
RunningService service = createService(Map.of("MYSQL_RANDOM_ROOT_PASSWORD", "true"));
MySqlService mysqlService = new MySqlService(service);
assertThatThrownBy(mysqlService::getPassword).isInstanceOf(IllegalStateException.class)
.hasMessageContaining("MYSQL_RANDOM_ROOT_PASSWORD");
}
@Test
void passwordHasNoFallback() {
RunningService service = createService(Collections.emptyMap());
MySqlService mysqlService = new MySqlService(service);
assertThatThrownBy(mysqlService::getPassword).isInstanceOf(IllegalStateException.class)
.hasMessage("Can't find password for user");
}
@Test
void passwordSupportsEmptyRootPasswordMysql() {
RunningService service = createService(Map.of("MYSQL_ALLOW_EMPTY_PASSWORD", ""));
MySqlService mysqlService = new MySqlService(service);
assertThat(mysqlService.getPassword()).isEqualTo("");
}
@Test
void databaseUsesMysqlVariables() {
RunningService service = createService(Map.of("MYSQL_DATABASE", "database-1"));
MySqlService mysqlService = new MySqlService(service);
assertThat(mysqlService.getDatabase()).isEqualTo("database-1");
}
@Test
void databaseHasNoFallback() {
RunningService service = createService(Collections.emptyMap());
MySqlService mysqlService = new MySqlService(service);
assertThatThrownBy(mysqlService::getDatabase).isInstanceOf(IllegalStateException.class)
.hasMessageContaining("MYSQL_DATABASE");
}
@Test
void getPort() {
RunningService service = createService(Collections.emptyMap());
MySqlService mysqlService = new MySqlService(service);
assertThat(mysqlService.getPort()).isEqualTo(33060);
}
@Test
void matches() {
assertThat(MySqlService.matches(createService(Collections.emptyMap()))).isTrue();
assertThat(MySqlService.matches(createService(ImageReference.parse("redis:7.1"), Collections.emptyMap())))
.isFalse();
}
private RunningService createService(Map<String, String> env) {
return createService(ImageReference.parse("mysql:8.0"), env);
}
private RunningService createService(ImageReference image, Map<String, String> env) {
return RunningServiceBuilder.create("service-1", image).addTcpPort(3306, 33060).env(env).build();
}
*/
// @formatter:on
}

View File

@@ -0,0 +1,83 @@
/*
* 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.postgres;
import java.util.Collections;
import java.util.Map;
import org.junit.jupiter.api.Disabled;
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
*/
@Disabled
class PostgresEnvironmentTests {
@Test
void createWhenNoPostgresPasswordThrowsException() {
assertThatIllegalStateException().isThrownBy(() -> new PostgresEnvironment(Collections.emptyMap()))
.withMessage("No POSTGRES_PASSWORD defined");
}
@Test
void getUsernameWhenNoPostgresUser() {
PostgresEnvironment environment = new PostgresEnvironment(Map.of("POSTGRES_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 getPasswordWhenHasPostgresPassword() {
PostgresEnvironment environment = new PostgresEnvironment(Map.of("POSTGRES_PASSWORD", "secret"));
assertThat(environment.getPassword()).isEqualTo("secret");
}
@Test
void getDatabaseWhenNoPostgresDbOrPostgressUser() {
PostgresEnvironment environment = new PostgresEnvironment(Map.of("POSTGRES_PASSWORD", "secret"));
assertThat(environment.getDatabase()).isEqualTo("postgress");
}
@Test
void getDatabaseWhenNoPostgresDbAndPostgressUser() {
PostgresEnvironment environment = new PostgresEnvironment(
Map.of("POSTGRES_USER", "me", "POSTGRES_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");
}
}

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.docker.compose.service.connection.postgres;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.jdbc.JdbcConnectionDetails;
import org.springframework.boot.docker.compose.service.connection.test.AbstractDockerComposeIntegrationTests;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration tests for {@link PostgresJdbcDockerComposeConnectionDetailsFactory}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class PostgresJdbcDockerComposeConnectionDetailsFactoryIntegrationTests extends AbstractDockerComposeIntegrationTests {
PostgresJdbcDockerComposeConnectionDetailsFactoryIntegrationTests() {
super("postgres-compose.yaml");
}
@Test
void runCreatesConnectionDetails() {
JdbcConnectionDetails connectionDetails = run(JdbcConnectionDetails.class);
assertThat(connectionDetails.getUsername()).isEqualTo("myuser");
assertThat(connectionDetails.getPassword()).isEqualTo("secret");
assertThat(connectionDetails.getJdbcUrl()).startsWith("jdbc:postgresql://").endsWith("/mydatabase");
}
}

View File

@@ -0,0 +1,49 @@
/*
* 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.postgres;
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 PostgresR2dbcDockerComposeConnectionDetailsFactory}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class PostgresR2dbcDockerComposeConnectionDetailsFactoryIntegrationTests extends AbstractDockerComposeIntegrationTests {
PostgresR2dbcDockerComposeConnectionDetailsFactoryIntegrationTests() {
super("postgres-compose.yaml");
}
@Test
void runCreatesConnectionDetails() {
R2dbcConnectionDetails connectionDetails = run(R2dbcConnectionDetails.class);
ConnectionFactoryOptions connectionFactoryOptions = connectionDetails.getConnectionFactoryOptions();
assertThat(connectionFactoryOptions.toString()).contains("database=mydatabase", "driver=postgresql",
"password=REDACTED", "user=myuser");
assertThat(connectionFactoryOptions.getRequiredValue(ConnectionFactoryOptions.PASSWORD)).isEqualTo("secret");
}
}

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.docker.compose.service.connection.postgres;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.fail;
/**
* Tests for {@link PostgresR2dbcDockerComposeConnectionDetailsFactory}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
@Disabled
class XPostgresDbR2dbcDockerComposeConnectionDetailsFactoryTests {
@Test
void test() {
fail("Not yet implemented");
}
// @formatter:off
/*
@Test
void usernameUsesEnvVariable() {
RunningService service = createService(Map.of("POSTGRES_USER", "user-1"));
PostgresService postgresService = new PostgresService(service);
assertThat(postgresService.getUsername()).isEqualTo("user-1");
}
@Test
void usernameHasFallback() {
RunningService service = createService(Collections.emptyMap());
PostgresService postgresService = new PostgresService(service);
assertThat(postgresService.getUsername()).isEqualTo("postgres");
}
@Test
void passwordUsesEnvVariable() {
RunningService service = createService(Map.of("POSTGRES_PASSWORD", "password-1"));
PostgresService postgresService = new PostgresService(service);
assertThat(postgresService.getPassword()).isEqualTo("password-1");
}
@Test
void passwordHasNoFallback() {
RunningService service = createService(Collections.emptyMap());
PostgresService postgresService = new PostgresService(service);
assertThatThrownBy(postgresService::getPassword).isInstanceOf(IllegalStateException.class)
.hasMessageContaining("POSTGRES_PASSWORD");
}
@Test
void databaseUsesEnvVariable() {
RunningService service = createService(Map.of("POSTGRES_DB", "database-1"));
PostgresService postgresService = new PostgresService(service);
assertThat(postgresService.getDatabase()).isEqualTo("database-1");
}
@Test
void databaseFallsBackToUsername() {
RunningService service = createService(Map.of("POSTGRES_USER", "user-1"));
PostgresService postgresService = new PostgresService(service);
assertThat(postgresService.getDatabase()).isEqualTo("user-1");
}
@Test
void getPort() {
RunningService service = createService(Collections.emptyMap());
PostgresService postgresService = new PostgresService(service);
assertThat(postgresService.getPort()).isEqualTo(54320);
}
@Test
void matches() {
assertThat(PostgresService.matches(createService(Collections.emptyMap()))).isTrue();
assertThat(PostgresService.matches(createService(ImageReference.parse("redis:7.1"), Collections.emptyMap())))
.isFalse();
}
private RunningService createService(Map<String, String> env) {
return createService(ImageReference.parse("postgres:15.2"), env);
}
private RunningService createService(ImageReference image, Map<String, String> env) {
return RunningServiceBuilder.create("service-1", image).addTcpPort(5432, 54320).env(env).build();
}
*/
// @formatter:on
}

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.docker.compose.service.connection.postgres;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.fail;
/**
* Tests for {@link PostgresJdbcDockerComposeConnectionDetailsFactory}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
@Disabled
class XPostgresJdbcDockerComposeConnectionDetailsFactoryTests {
@Test
void test() {
fail("Not yet implemented");
}
// @formatter:off
/*
@Test
void usernameUsesEnvVariable() {
RunningService service = createService(Map.of("POSTGRES_USER", "user-1"));
PostgresService postgresService = new PostgresService(service);
assertThat(postgresService.getUsername()).isEqualTo("user-1");
}
@Test
void usernameHasFallback() {
RunningService service = createService(Collections.emptyMap());
PostgresService postgresService = new PostgresService(service);
assertThat(postgresService.getUsername()).isEqualTo("postgres");
}
@Test
void passwordUsesEnvVariable() {
RunningService service = createService(Map.of("POSTGRES_PASSWORD", "password-1"));
PostgresService postgresService = new PostgresService(service);
assertThat(postgresService.getPassword()).isEqualTo("password-1");
}
@Test
void passwordHasNoFallback() {
RunningService service = createService(Collections.emptyMap());
PostgresService postgresService = new PostgresService(service);
assertThatThrownBy(postgresService::getPassword).isInstanceOf(IllegalStateException.class)
.hasMessageContaining("POSTGRES_PASSWORD");
}
@Test
void databaseUsesEnvVariable() {
RunningService service = createService(Map.of("POSTGRES_DB", "database-1"));
PostgresService postgresService = new PostgresService(service);
assertThat(postgresService.getDatabase()).isEqualTo("database-1");
}
@Test
void databaseFallsBackToUsername() {
RunningService service = createService(Map.of("POSTGRES_USER", "user-1"));
PostgresService postgresService = new PostgresService(service);
assertThat(postgresService.getDatabase()).isEqualTo("user-1");
}
@Test
void getPort() {
RunningService service = createService(Collections.emptyMap());
PostgresService postgresService = new PostgresService(service);
assertThat(postgresService.getPort()).isEqualTo(54320);
}
@Test
void matches() {
assertThat(PostgresService.matches(createService(Collections.emptyMap()))).isTrue();
assertThat(PostgresService.matches(createService(ImageReference.parse("redis:7.1"), Collections.emptyMap())))
.isFalse();
}
private RunningService createService(Map<String, String> env) {
return createService(ImageReference.parse("postgres:15.2"), env);
}
private RunningService createService(ImageReference image, Map<String, String> env) {
return RunningServiceBuilder.create("service-1", image).addTcpPort(5432, 54320).env(env).build();
}
*/
// @formatter:on
}

View File

@@ -0,0 +1,94 @@
/*
* 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.r2dbc;
import java.util.Collections;
import java.util.Map;
import io.r2dbc.spi.ConnectionFactoryOptions;
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.docker.compose.service.connection.jdbc.JdbcUrlBuilder;
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 ConnectionFactoryOptionsBuilder}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class ConnectionFactoryOptionsBuilderTests {
private ConnectionFactoryOptionsBuilder builder = new ConnectionFactoryOptionsBuilder("mydb", 1234);
@Test
void createWhenDriverProtocolIsNullThrowsException() {
assertThatIllegalArgumentException().isThrownBy(() -> new JdbcUrlBuilder(null, 123))
.withMessage("DriverProtocol must not be null");
}
@Test
void buildBuildsOptions() {
RunningService service = mockService(456);
ConnectionFactoryOptions options = this.builder.build(service, "mydb", "user", "pass");
assertThat(options).hasToString(
"ConnectionFactoryOptions{options={database=mydb, host=myhost, driver=mydb, password=REDACTED, port=456, user=user}}");
}
@Test
void buildWhenHasParamsLabelBuildsOptions() {
RunningService service = mockService(456, Map.of("org.springframework.boot.r2dbc.parameters", "foo=bar"));
ConnectionFactoryOptions options = this.builder.build(service, "mydb", "user", "pass");
assertThat(options).hasToString(
"ConnectionFactoryOptions{options={foo=bar, database=mydb, host=myhost, driver=mydb, password=REDACTED, port=456, user=user}}");
}
@Test
void buildWhenServiceIsNullThrowsException() {
assertThatIllegalArgumentException().isThrownBy(() -> this.builder.build(null, "mydb", "user", "pass"))
.withMessage("Service must not be null");
}
@Test
void buildWhenDatabaseIsNullThrowsException() {
assertThatIllegalArgumentException()
.isThrownBy(() -> this.builder.build(mockService(456), null, "user", "pass"))
.withMessage("Database 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,52 @@
/*
* 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.rabbit;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.amqp.RabbitConnectionDetails;
import org.springframework.boot.autoconfigure.amqp.RabbitConnectionDetails.Address;
import org.springframework.boot.docker.compose.service.connection.test.AbstractDockerComposeIntegrationTests;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration tests for {@link RabbitDockerComposeConnectionDetailsFactory}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class RabbitDockerComposeConnectionDetailsFactoryIntegrationTests extends AbstractDockerComposeIntegrationTests {
RabbitDockerComposeConnectionDetailsFactoryIntegrationTests() {
super("rabbit-compose.yaml");
}
@Test
void runCreatesConnectionDetails() {
RabbitConnectionDetails connectionDetails = run(RabbitConnectionDetails.class);
assertThat(connectionDetails.getUsername()).isEqualTo("myuser");
assertThat(connectionDetails.getPassword()).isEqualTo("secret");
assertThat(connectionDetails.getVirtualHost()).isEqualTo("/");
assertThat(connectionDetails.getAddresses()).hasSize(1);
Address address = connectionDetails.getFirstAddress();
assertThat(address.host()).isNotNull();
assertThat(address.port()).isGreaterThan(0);
}
}

View File

@@ -0,0 +1,61 @@
/*
* 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.rabbit;
import java.util.Collections;
import java.util.Map;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link RabbitEnvironment}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
@Disabled
class RabbitEnvironmentTests {
@Test
void getUsernameWhenNoRabbitmqDefaultUser() {
RabbitEnvironment environment = new RabbitEnvironment(Collections.emptyMap());
assertThat(environment.getUsername()).isEqualTo("guest");
}
@Test
void getUsernameWhenHasRabbitmqDefaultUser() {
RabbitEnvironment environment = new RabbitEnvironment(Map.of("RABBITMQ_DEFAULT_USER", "me"));
assertThat(environment.getUsername()).isEqualTo("me");
}
@Test
void getUsernameWhenNoRabbitmqDefaultPass() {
RabbitEnvironment environment = new RabbitEnvironment(Collections.emptyMap());
assertThat(environment.getPassword()).isEqualTo("guest");
}
@Test
void getUsernameWhenHasRabbitmqDefaultPass() {
RabbitEnvironment environment = new RabbitEnvironment(Map.of("RABBITMQ_DEFAULT_PASS", "secret"));
assertThat(environment.getPassword()).isEqualTo("secret");
}
}

View File

@@ -0,0 +1,99 @@
/*
* 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.rabbit;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.fail;
/**
* Tests for {@link RabbitDockerComposeConnectionDetailsFactory}
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
@Disabled
class XRabbitDockerComposeConnectionDetailsFactoryTests {
@Test
void test() {
fail("Not yet implemented");
}
// @formatter:off
/*
@Test
void usernameUsesEnvVariable() {
RunningService service = createService(Map.of("RABBITMQ_DEFAULT_USER", "user-1"));
RabbitService rabbitService = new RabbitService(service);
assertThat(rabbitService.getUsername()).isEqualTo("user-1");
}
@Test
void usernameHasDefault() {
RunningService service = createService(Collections.emptyMap());
RabbitService rabbitService = new RabbitService(service);
assertThat(rabbitService.getUsername()).isEqualTo("guest");
}
@Test
void passwordUsesEnvVariable() {
RunningService service = createService(Map.of("RABBITMQ_DEFAULT_PASS", "secret-1"));
RabbitService rabbitService = new RabbitService(service);
assertThat(rabbitService.getPassword()).isEqualTo("secret-1");
}
@Test
void passwordHasDefault() {
RunningService service = createService(Collections.emptyMap());
RabbitService rabbitService = new RabbitService(service);
assertThat(rabbitService.getPassword()).isEqualTo("guest");
}
@Test
void getPort() {
RunningService service = createService(Collections.emptyMap());
RabbitService rabbitService = new RabbitService(service);
assertThat(rabbitService.getPort()).isEqualTo(15672);
}
@Test
void matches() {
assertThat(RabbitService.matches(createService(Collections.emptyMap()))).isTrue();
assertThat(RabbitService.matches(createService(ImageReference.parse("redis:7.1"), Collections.emptyMap())))
.isFalse();
}
private RunningService createService(Map<String, String> env) {
return createService(ImageReference.parse("rabbitmq:3.11"), env);
}
private RunningService createService(ImageReference image, Map<String, String> env) {
return RunningServiceBuilder.create("service-1", image).addTcpPort(5672, 15672).env(env).build();
}
*/
// @formatter:on
}

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.docker.compose.service.connection.redis;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.data.redis.RedisConnectionDetails;
import org.springframework.boot.autoconfigure.data.redis.RedisConnectionDetails.Standalone;
import org.springframework.boot.docker.compose.service.connection.test.AbstractDockerComposeIntegrationTests;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration test for {@link RedisDockerComposeConnectionDetailsFactory}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class RedisDockerComposeConnectionDetailsFactoryIntegrationTests extends AbstractDockerComposeIntegrationTests {
RedisDockerComposeConnectionDetailsFactoryIntegrationTests() {
super("redis-compose.yaml");
}
@Test
void runCreatesConnectionDetails() {
RedisConnectionDetails connectionDetails = run(RedisConnectionDetails.class);
Standalone standalone = connectionDetails.getStandalone();
assertThat(connectionDetails.getUsername()).isNull();
assertThat(connectionDetails.getPassword()).isNull();
assertThat(connectionDetails.getCluster()).isNull();
assertThat(connectionDetails.getSentinel()).isNull();
assertThat(standalone).isNotNull();
assertThat(standalone.getDatabase()).isZero();
assertThat(standalone.getPort()).isGreaterThan(0);
assertThat(standalone.getHost()).isNotNull();
}
}

View File

@@ -0,0 +1,71 @@
/*
* 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.redis;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.fail;
/**
* Tests for {@link RedisDockerComposeConnectionDetailsFactory}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
@Disabled
class RedisDockerComposeConnectionDetailsFactoryTests {
@Test
void test() {
fail("Not yet implemented");
}
// @formatter:off
/*
@Test
void getPort() {
RunningService service = createService(Collections.emptyMap());
RedisService redisService = new RedisService(service);
assertThat(redisService.getPort()).isEqualTo(16379);
}
@Test
void matches() {
assertThat(RedisService.matches(createService(Collections.emptyMap()))).isTrue();
assertThat(RedisService.matches(createService(ImageReference.parse("postgres:15.2"), Collections.emptyMap())))
.isFalse();
}
private RunningService createService(Map<String, String> env) {
return createService(ImageReference.parse("redis:7.0"), env);
}
private RunningService createService(ImageReference image, Map<String, String> env) {
return RunningServiceBuilder.create("service-1", image).addTcpPort(6379, 16379).env(env).build();
}
*/
// @formatter:on
}

View File

@@ -0,0 +1,69 @@
/*
* 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.test;
import java.util.LinkedHashMap;
import java.util.Map;
import org.junit.jupiter.api.AfterAll;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationShutdownHandlers;
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;
import org.springframework.boot.testsupport.process.DisabledIfProcessUnavailable;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.util.function.ThrowingSupplier;
/**
* Abstract base class for integration tests.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
*/
@DisabledIfProcessUnavailable({ "docker", "compose" })
public abstract class AbstractDockerComposeIntegrationTests {
private final Resource composeResource;
@AfterAll
static void shutdown() {
SpringApplicationShutdownHandlers shutdownHandlers = SpringApplication.getShutdownHandlers();
((Runnable) shutdownHandlers).run();
}
protected AbstractDockerComposeIntegrationTests(String composeResource) {
this.composeResource = new ClassPathResource(composeResource, getClass());
}
protected final <T extends ConnectionDetails> T run(Class<T> type) {
SpringApplication application = new SpringApplication(Config.class);
Map<String, Object> properties = new LinkedHashMap<>();
properties.put("spring.docker.compose.skip.in-tests", "false");
properties.put("spring.docker.compose.file",
ThrowingSupplier.of(this.composeResource::getFile).get().getAbsolutePath());
application.setDefaultProperties(properties);
return application.run().getBean(type);
}
@Configuration(proxyBeanMethods = false)
static class Config {
}
}

View File

@@ -0,0 +1,102 @@
/*
* 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.test;
import org.springframework.boot.testsupport.testcontainers.DisabledIfDockerUnavailable;
/**
* Abstract base class for integration tests.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
*/
@DisabledIfDockerUnavailable
public abstract class AbstractIntegrationTests {
//// @formatter:off
/*
@TempDir
static Path tempDir;
private static List<Runnable> shutdownHandler;
@BeforeAll
static void beforeAll() {
shutdownHandler = new ArrayList<>();
}
@AfterAll
static void afterAll() {
for (Runnable runnable : shutdownHandler) {
runnable.run();
}
}
@BeforeEach
void setUp() throws IOException {
createComposeYaml();
}
protected abstract InputStream getComposeContent();
protected final <T extends ConnectionDetails> T runProvider(Class<T> serviceConnectionClass) {
return runProvider(new MockEnvironment(), serviceConnectionClass);
}
protected final <T extends ConnectionDetails> T runProvider(MockEnvironment environment,
Class<T> serviceConnectionClass) {
environment.setProperty("spring.dev-services.docker-compose.stop-mode", "down");
DockerComposeListener dockerComposeListener = createProvider(environment);
GenericApplicationContext context = new GenericApplicationContext();
context.setEnvironment(environment);
dockerComposeListener
.onApplicationEvent(new ApplicationPreparedEvent(new SpringApplication(), new String[0], context));
context.refresh();
T serviceConnection = context.getBean(serviceConnectionClass);
assertThat(serviceConnection.getOrigin()).isInstanceOf(DockerComposeOrigin.class);
return serviceConnection;
}
private DockerComposeListener createProvider(Environment environment) {
return new DockerComposeListener(getClass().getClassLoader(), environment, null, null, null, tempDir,
new SpringApplicationShutdownHandlers() {
@Override
public void add(Runnable action) {
shutdownHandler.add(action);
}
@Override
public void remove(Runnable action) {
}
});
}
private void createComposeYaml() throws IOException {
try (InputStream stream = getComposeContent()) {
byte[] content = stream.readAllBytes();
Files.write(tempDir.resolve("compose.yaml"), content);
}
}
*/
// @formatter:on
}

View File

@@ -0,0 +1,71 @@
/*
* 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.zipkin;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.fail;
/**
* Tests for {@link ZipkinDockerComposeConnectionDetailsFactory}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
@Disabled
class XZipkinDockerComposeConnectionDetailsFactoryTests {
@Test
void test() {
fail("Not yet implemented");
}
// @formatter:off
/*
@Test
void getPort() {
RunningService service = createService(Collections.emptyMap());
ZipkinService zipkinService = new ZipkinService(service);
assertThat(zipkinService.getPort()).isEqualTo(19411);
}
@Test
void matches() {
assertThat(ZipkinService.matches(createService(Collections.emptyMap()))).isTrue();
assertThat(ZipkinService.matches(createService(ImageReference.parse("postgres:15.2"), Collections.emptyMap())))
.isFalse();
}
private RunningService createService(Map<String, String> env) {
return createService(ImageReference.parse("openzipkin/zipkin:2.24"), env);
}
private RunningService createService(ImageReference image, Map<String, String> env) {
return RunningServiceBuilder.create("service-1", image).addTcpPort(9411, 19411).env(env).build();
}
*/
// @formatter:on
}

View File

@@ -0,0 +1,45 @@
/*
* 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.zipkin;
import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.autoconfigure.tracing.zipkin.ZipkinConnectionDetails;
import org.springframework.boot.docker.compose.service.connection.test.AbstractDockerComposeIntegrationTests;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration tests for {@link ZipkinDockerComposeConnectionDetailsFactory}.
*
* @author Moritz Halbritter
* @author Andy Wilkinson
* @author Phillip Webb
*/
class ZipkinDockerComposeConnectionDetailsFactoryIntegrationTests extends AbstractDockerComposeIntegrationTests {
ZipkinDockerComposeConnectionDetailsFactoryIntegrationTests() {
super("zipkin-compose.yaml");
}
@Test
void runCreatesConnectionDetails() {
ZipkinConnectionDetails connectionDetails = run(ZipkinConnectionDetails.class);
assertThat(connectionDetails.getSpanEndpoint()).startsWith("http://").endsWith("/api/v2/spans");
}
}

View File

@@ -0,0 +1,29 @@
{
"name": "redis-docker",
"services": {
"redis": {
"command": null,
"entrypoint": null,
"image": "redis:7.0",
"networks": {
"default": null
},
"ports": [
{
"mode": "ingress",
"target": 6379,
"protocol": "tcp"
}
]
}
},
"networks": {
"default": {
"name": "redis-docker_default",
"ipam": {
},
"external": false
}
}
}

View File

@@ -0,0 +1,16 @@
{
"Command": "/command",
"CreatedAt": "2023-02-21 13:35:10 +0100 CET",
"ID": "f5af31dae7f6",
"Image": "redis:7.0",
"Labels": "com.docker.compose.project.config_files=/compose.yaml,com.docker.compose.project.working_dir=/,com.docker.compose.container-number=1,com.docker.compose.image=sha256:e79ba23ed43baa22054741136bf45bdb041824f41c5e16c0033ea044ca164b82,com.docker.compose.oneoff=False,com.docker.compose.project=redis-docker,com.docker.compose.config-hash=cfdc8e119d85a53c7d47edb37a3b160a8c83ba48b0428ebc07713befec991dd0,com.docker.compose.depends_on=,com.docker.compose.service=redis,com.docker.compose.version=2.16.0",
"LocalVolumes": "1",
"Mounts": "9edc7fa2fe6c9e…",
"Name": "redis-docker-redis-1",
"Networks": "redis-docker_default",
"Ports": "0.0.0.0:32770-\\u003e6379/tcp, :::32770-\\u003e6379/tcp",
"RunningFor": "2 days ago",
"Size": "0B",
"State": "running",
"Status": "Up 3 seconds"
}

View File

@@ -0,0 +1,8 @@
{
"Current": true,
"Description": "Current DOCKER_HOST based configuration",
"DockerEndpoint": "unix:///var/run/docker.sock",
"Error": "",
"KubernetesEndpoint": "",
"Name": "default"
}

View File

@@ -0,0 +1,250 @@
{
"Id": "f5af31dae7f665bd194ec7261bdc84e5df9c64753abb4a6cec6c33f7cf64c3fc",
"Created": "2023-02-21T12:35:10.468917704Z",
"Path": "docker-entrypoint.sh",
"Args": [
"redis-server"
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 38657,
"ExitCode": 0,
"Error": "",
"StartedAt": "2023-02-23T12:55:27.585705588Z",
"FinishedAt": "2023-02-23T12:46:42.013469854Z"
},
"Image": "sha256:e79ba23ed43baa22054741136bf45bdb041824f41c5e16c0033ea044ca164b82",
"ResolvConfPath": "/var/lib/docker/containers/f5af31dae7f665bd194ec7261bdc84e5df9c64753abb4a6cec6c33f7cf64c3fc/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/f5af31dae7f665bd194ec7261bdc84e5df9c64753abb4a6cec6c33f7cf64c3fc/hostname",
"HostsPath": "/var/lib/docker/containers/f5af31dae7f665bd194ec7261bdc84e5df9c64753abb4a6cec6c33f7cf64c3fc/hosts",
"LogPath": "/var/lib/docker/containers/f5af31dae7f665bd194ec7261bdc84e5df9c64753abb4a6cec6c33f7cf64c3fc/f5af31dae7f665bd194ec7261bdc84e5df9c64753abb4a6cec6c33f7cf64c3fc-json.log",
"Name": "/redis-docker-redis-1",
"RestartCount": 0,
"Driver": "btrfs",
"Platform": "linux",
"MountLabel": "",
"ProcessLabel": "",
"AppArmorProfile": "",
"ExecIDs": null,
"HostConfig": {
"Binds": null,
"ContainerIDFile": "",
"LogConfig": {
"Type": "json-file",
"Config": {
}
},
"NetworkMode": "redis-docker_default",
"PortBindings": {
"6379/tcp": [
{
"HostIp": "",
"HostPort": ""
}
]
},
"RestartPolicy": {
"Name": "",
"MaximumRetryCount": 0
},
"AutoRemove": false,
"VolumeDriver": "",
"VolumesFrom": null,
"ConsoleSize": [
0,
0
],
"CapAdd": null,
"CapDrop": null,
"CgroupnsMode": "private",
"Dns": [],
"DnsOptions": [],
"DnsSearch": [],
"ExtraHosts": [],
"GroupAdd": null,
"IpcMode": "private",
"Cgroup": "",
"Links": null,
"OomScoreAdj": 0,
"PidMode": "",
"Privileged": false,
"PublishAllPorts": false,
"ReadonlyRootfs": false,
"SecurityOpt": null,
"UTSMode": "",
"UsernsMode": "",
"ShmSize": 67108864,
"Runtime": "runc",
"Isolation": "",
"CpuShares": 0,
"Memory": 0,
"NanoCpus": 0,
"CgroupParent": "",
"BlkioWeight": 0,
"BlkioWeightDevice": null,
"BlkioDeviceReadBps": null,
"BlkioDeviceWriteBps": null,
"BlkioDeviceReadIOps": null,
"BlkioDeviceWriteIOps": null,
"CpuPeriod": 0,
"CpuQuota": 0,
"CpuRealtimePeriod": 0,
"CpuRealtimeRuntime": 0,
"CpusetCpus": "",
"CpusetMems": "",
"Devices": null,
"DeviceCgroupRules": null,
"DeviceRequests": null,
"MemoryReservation": 0,
"MemorySwap": 0,
"MemorySwappiness": null,
"OomKillDisable": null,
"PidsLimit": null,
"Ulimits": null,
"CpuCount": 0,
"CpuPercent": 0,
"IOMaximumIOps": 0,
"IOMaximumBandwidth": 0,
"MaskedPaths": [
"/proc/asound",
"/proc/acpi",
"/proc/kcore",
"/proc/keys",
"/proc/latency_stats",
"/proc/timer_list",
"/proc/timer_stats",
"/proc/sched_debug",
"/proc/scsi",
"/sys/firmware"
],
"ReadonlyPaths": [
"/proc/bus",
"/proc/fs",
"/proc/irq",
"/proc/sys",
"/proc/sysrq-trigger"
]
},
"GraphDriver": {
"Data": null,
"Name": "btrfs"
},
"Mounts": [
{
"Type": "volume",
"Name": "9edc7fa2fe6c9e8f67fd31a8649a4b5d7edbc9c1604462e04a5f35d6bfda87c3",
"Source": "/var/lib/docker/volumes/9edc7fa2fe6c9e8f67fd31a8649a4b5d7edbc9c1604462e04a5f35d6bfda87c3/_data",
"Destination": "/data",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
"Config": {
"Hostname": "f5af31dae7f6",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": true,
"AttachStderr": true,
"ExposedPorts": {
"6379/tcp": {
}
},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"GOSU_VERSION=1.16",
"REDIS_VERSION=7.0.8",
"REDIS_DOWNLOAD_URL=https://download.redis.io/releases/redis-7.0.8.tar.gz",
"REDIS_DOWNLOAD_SHA=06a339e491306783dcf55b97f15a5dbcbdc01ccbde6dc23027c475cab735e914"
],
"Cmd": [
"redis-server"
],
"Image": "redis:7.0",
"Volumes": {
"/data": {
}
},
"WorkingDir": "/data",
"Entrypoint": [
"docker-entrypoint.sh"
],
"OnBuild": null,
"Labels": {
"com.docker.compose.config-hash": "cfdc8e119d85a53c7d47edb37a3b160a8c83ba48b0428ebc07713befec991dd0",
"com.docker.compose.container-number": "1",
"com.docker.compose.depends_on": "",
"com.docker.compose.image": "sha256:e79ba23ed43baa22054741136bf45bdb041824f41c5e16c0033ea044ca164b82",
"com.docker.compose.oneoff": "False",
"com.docker.compose.project": "redis-docker",
"com.docker.compose.project.config_files": "/compose.yaml",
"com.docker.compose.project.working_dir": "/",
"com.docker.compose.service": "redis",
"com.docker.compose.version": "2.16.0"
}
},
"NetworkSettings": {
"Bridge": "",
"SandboxID": "3df878d8ed31b2686e41437f141bebba8afcf3bdf8c47ea07c34c2e0b365ec88",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {
"6379/tcp": [
{
"HostIp": "0.0.0.0",
"HostPort": "32770"
},
{
"HostIp": "::",
"HostPort": "32770"
}
]
},
"SandboxKey": "/var/run/docker/netns/3df878d8ed31",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "",
"Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "",
"IPPrefixLen": 0,
"IPv6Gateway": "",
"MacAddress": "",
"Networks": {
"redis-docker_default": {
"IPAMConfig": null,
"Links": null,
"Aliases": [
"redis-docker-redis-1",
"redis",
"f5af31dae7f6"
],
"NetworkID": "9cb2b8b6fb20703841b9337b48e65ed2a71e2da2e995e4782066d146c44fc205",
"EndpointID": "e155c61c1608b20ba7a0bd34790fc342ec576310f75ef4399e96bf3a67e8b3f6",
"Gateway": "192.168.32.1",
"IPAddress": "192.168.32.2",
"IPPrefixLen": 20,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:c0:a8:20:02",
"DriverOpts": null
}
}
}
}

View File

@@ -0,0 +1,237 @@
{
"Id": "111b22dba993f3282257cbafc87c77763cb4f8a8e534804ef1feae9c8ef282a1",
"Created": "2023-02-23T14:19:06.668158561Z",
"Path": "docker-entrypoint.sh",
"Args": [
"redis-server"
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 46377,
"ExitCode": 0,
"Error": "",
"StartedAt": "2023-02-23T14:19:07.001096801Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
"Image": "sha256:e79ba23ed43baa22054741136bf45bdb041824f41c5e16c0033ea044ca164b82",
"ResolvConfPath": "/var/lib/docker/containers/111b22dba993f3282257cbafc87c77763cb4f8a8e534804ef1feae9c8ef282a1/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/111b22dba993f3282257cbafc87c77763cb4f8a8e534804ef1feae9c8ef282a1/hostname",
"HostsPath": "/var/lib/docker/containers/111b22dba993f3282257cbafc87c77763cb4f8a8e534804ef1feae9c8ef282a1/hosts",
"LogPath": "/var/lib/docker/containers/111b22dba993f3282257cbafc87c77763cb4f8a8e534804ef1feae9c8ef282a1/111b22dba993f3282257cbafc87c77763cb4f8a8e534804ef1feae9c8ef282a1-json.log",
"Name": "/redis-docker-redis-1",
"RestartCount": 0,
"Driver": "btrfs",
"Platform": "linux",
"MountLabel": "",
"ProcessLabel": "",
"AppArmorProfile": "",
"ExecIDs": null,
"HostConfig": {
"Binds": null,
"ContainerIDFile": "",
"LogConfig": {
"Type": "json-file",
"Config": {
}
},
"NetworkMode": "host",
"PortBindings": {
"6379/tcp": [
{
"HostIp": "",
"HostPort": ""
}
]
},
"RestartPolicy": {
"Name": "",
"MaximumRetryCount": 0
},
"AutoRemove": false,
"VolumeDriver": "",
"VolumesFrom": null,
"ConsoleSize": [
0,
0
],
"CapAdd": null,
"CapDrop": null,
"CgroupnsMode": "private",
"Dns": null,
"DnsOptions": null,
"DnsSearch": null,
"ExtraHosts": [],
"GroupAdd": null,
"IpcMode": "private",
"Cgroup": "",
"Links": null,
"OomScoreAdj": 0,
"PidMode": "",
"Privileged": false,
"PublishAllPorts": false,
"ReadonlyRootfs": false,
"SecurityOpt": null,
"UTSMode": "",
"UsernsMode": "",
"ShmSize": 67108864,
"Runtime": "runc",
"Isolation": "",
"CpuShares": 0,
"Memory": 0,
"NanoCpus": 0,
"CgroupParent": "",
"BlkioWeight": 0,
"BlkioWeightDevice": null,
"BlkioDeviceReadBps": null,
"BlkioDeviceWriteBps": null,
"BlkioDeviceReadIOps": null,
"BlkioDeviceWriteIOps": null,
"CpuPeriod": 0,
"CpuQuota": 0,
"CpuRealtimePeriod": 0,
"CpuRealtimeRuntime": 0,
"CpusetCpus": "",
"CpusetMems": "",
"Devices": null,
"DeviceCgroupRules": null,
"DeviceRequests": null,
"MemoryReservation": 0,
"MemorySwap": 0,
"MemorySwappiness": null,
"OomKillDisable": null,
"PidsLimit": null,
"Ulimits": null,
"CpuCount": 0,
"CpuPercent": 0,
"IOMaximumIOps": 0,
"IOMaximumBandwidth": 0,
"MaskedPaths": [
"/proc/asound",
"/proc/acpi",
"/proc/kcore",
"/proc/keys",
"/proc/latency_stats",
"/proc/timer_list",
"/proc/timer_stats",
"/proc/sched_debug",
"/proc/scsi",
"/sys/firmware"
],
"ReadonlyPaths": [
"/proc/bus",
"/proc/fs",
"/proc/irq",
"/proc/sys",
"/proc/sysrq-trigger"
]
},
"GraphDriver": {
"Data": null,
"Name": "btrfs"
},
"Mounts": [
{
"Type": "volume",
"Name": "0ff245e74dc368da772d4d1139b2aafd423ca1ce1fbe502b4635d7d15f0faf8c",
"Source": "/var/lib/docker/volumes/0ff245e74dc368da772d4d1139b2aafd423ca1ce1fbe502b4635d7d15f0faf8c/_data",
"Destination": "/data",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
"Config": {
"Hostname": "fedora",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": true,
"AttachStderr": true,
"ExposedPorts": {
"6379/tcp": {
}
},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"GOSU_VERSION=1.16",
"REDIS_VERSION=7.0.8",
"REDIS_DOWNLOAD_URL=https://download.redis.io/releases/redis-7.0.8.tar.gz",
"REDIS_DOWNLOAD_SHA=06a339e491306783dcf55b97f15a5dbcbdc01ccbde6dc23027c475cab735e914"
],
"Cmd": [
"redis-server"
],
"Image": "redis:7.0",
"Volumes": {
"/data": {
}
},
"WorkingDir": "/data",
"Entrypoint": [
"docker-entrypoint.sh"
],
"OnBuild": null,
"Labels": {
"com.docker.compose.config-hash": "204d00fc2f8ffd749769e3f6c160b2a2366e76cf8980bb2984bc65674748b3ca",
"com.docker.compose.container-number": "1",
"com.docker.compose.depends_on": "",
"com.docker.compose.image": "sha256:e79ba23ed43baa22054741136bf45bdb041824f41c5e16c0033ea044ca164b82",
"com.docker.compose.oneoff": "False",
"com.docker.compose.project": "redis-docker",
"com.docker.compose.project.config_files": "/compose.yaml",
"com.docker.compose.project.working_dir": "/",
"com.docker.compose.service": "redis",
"com.docker.compose.version": "2.16.0"
}
},
"NetworkSettings": {
"Bridge": "",
"SandboxID": "6ec5c12e14078b424707534b8b64d0953ce9da21eaebd422daefff2d6a08f14d",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {
},
"SandboxKey": "/var/run/docker/netns/default",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "",
"Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "",
"IPPrefixLen": 0,
"IPv6Gateway": "",
"MacAddress": "",
"Networks": {
"host": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "c8fa8aac531ce4630465de4baf8d0310a2ff3243b3986e5251611c1a4ee6e1b3",
"EndpointID": "cfdc6016b0dd724f7714ae116c5fa33127401f5e6853f07c4c1db5e967871136",
"Gateway": "",
"IPAddress": "",
"IPPrefixLen": 0,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "",
"DriverOpts": null
}
}
}
}

View File

@@ -0,0 +1,248 @@
{
"Id": "f5af31dae7f665bd194ec7261bdc84e5df9c64753abb4a6cec6c33f7cf64c3fc",
"Created": "2023-02-21T12:35:10.468917704Z",
"Path": "docker-entrypoint.sh",
"Args": [
"redis-server"
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 38657,
"ExitCode": 0,
"Error": "",
"StartedAt": "2023-02-23T12:55:27.585705588Z",
"FinishedAt": "2023-02-23T12:46:42.013469854Z"
},
"Image": "sha256:e79ba23ed43baa22054741136bf45bdb041824f41c5e16c0033ea044ca164b82",
"ResolvConfPath": "/var/lib/docker/containers/f5af31dae7f665bd194ec7261bdc84e5df9c64753abb4a6cec6c33f7cf64c3fc/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/f5af31dae7f665bd194ec7261bdc84e5df9c64753abb4a6cec6c33f7cf64c3fc/hostname",
"HostsPath": "/var/lib/docker/containers/f5af31dae7f665bd194ec7261bdc84e5df9c64753abb4a6cec6c33f7cf64c3fc/hosts",
"LogPath": "/var/lib/docker/containers/f5af31dae7f665bd194ec7261bdc84e5df9c64753abb4a6cec6c33f7cf64c3fc/f5af31dae7f665bd194ec7261bdc84e5df9c64753abb4a6cec6c33f7cf64c3fc-json.log",
"Name": "/redis-docker-redis-1",
"RestartCount": 0,
"Driver": "btrfs",
"Platform": "linux",
"MountLabel": "",
"ProcessLabel": "",
"AppArmorProfile": "",
"ExecIDs": null,
"HostConfig": {
"Binds": null,
"ContainerIDFile": "",
"LogConfig": {
"Type": "json-file",
"Config": {
}
},
"NetworkMode": "redis-docker_default",
"PortBindings": {
"6379/tcp": [
{
"HostIp": "",
"HostPort": ""
}
]
},
"RestartPolicy": {
"Name": "",
"MaximumRetryCount": 0
},
"AutoRemove": false,
"VolumeDriver": "",
"VolumesFrom": null,
"ConsoleSize": [
0,
0
],
"CapAdd": null,
"CapDrop": null,
"CgroupnsMode": "private",
"Dns": [],
"DnsOptions": [],
"DnsSearch": [],
"ExtraHosts": [],
"GroupAdd": null,
"IpcMode": "private",
"Cgroup": "",
"Links": null,
"OomScoreAdj": 0,
"PidMode": "",
"Privileged": false,
"PublishAllPorts": false,
"ReadonlyRootfs": false,
"SecurityOpt": null,
"UTSMode": "",
"UsernsMode": "",
"ShmSize": 67108864,
"Runtime": "runc",
"Isolation": "",
"CpuShares": 0,
"Memory": 0,
"NanoCpus": 0,
"CgroupParent": "",
"BlkioWeight": 0,
"BlkioWeightDevice": null,
"BlkioDeviceReadBps": null,
"BlkioDeviceWriteBps": null,
"BlkioDeviceReadIOps": null,
"BlkioDeviceWriteIOps": null,
"CpuPeriod": 0,
"CpuQuota": 0,
"CpuRealtimePeriod": 0,
"CpuRealtimeRuntime": 0,
"CpusetCpus": "",
"CpusetMems": "",
"Devices": null,
"DeviceCgroupRules": null,
"DeviceRequests": null,
"MemoryReservation": 0,
"MemorySwap": 0,
"MemorySwappiness": null,
"OomKillDisable": null,
"PidsLimit": null,
"Ulimits": null,
"CpuCount": 0,
"CpuPercent": 0,
"IOMaximumIOps": 0,
"IOMaximumBandwidth": 0,
"MaskedPaths": [
"/proc/asound",
"/proc/acpi",
"/proc/kcore",
"/proc/keys",
"/proc/latency_stats",
"/proc/timer_list",
"/proc/timer_stats",
"/proc/sched_debug",
"/proc/scsi",
"/sys/firmware"
],
"ReadonlyPaths": [
"/proc/bus",
"/proc/fs",
"/proc/irq",
"/proc/sys",
"/proc/sysrq-trigger"
]
},
"GraphDriver": {
"Data": null,
"Name": "btrfs"
},
"Mounts": [
{
"Type": "volume",
"Name": "9edc7fa2fe6c9e8f67fd31a8649a4b5d7edbc9c1604462e04a5f35d6bfda87c3",
"Source": "/var/lib/docker/volumes/9edc7fa2fe6c9e8f67fd31a8649a4b5d7edbc9c1604462e04a5f35d6bfda87c3/_data",
"Destination": "/data",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
"Config": {
"Hostname": "f5af31dae7f6",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": true,
"AttachStderr": true,
"ExposedPorts": {
"6379/tcp": {
}
},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"GOSU_VERSION=1.16",
"REDIS_VERSION=7.0.8"
],
"Cmd": [
"redis-server"
],
"Image": "redis:7.0",
"Volumes": {
"/data": {
}
},
"WorkingDir": "/data",
"Entrypoint": [
"docker-entrypoint.sh"
],
"OnBuild": null,
"Labels": {
"com.docker.compose.config-hash": "cfdc8e119d85a53c7d47edb37a3b160a8c83ba48b0428ebc07713befec991dd0",
"com.docker.compose.container-number": "1",
"com.docker.compose.depends_on": "",
"com.docker.compose.image": "sha256:e79ba23ed43baa22054741136bf45bdb041824f41c5e16c0033ea044ca164b82",
"com.docker.compose.oneoff": "False",
"com.docker.compose.project": "redis-docker",
"com.docker.compose.project.config_files": "compose.yaml",
"com.docker.compose.project.working_dir": "/",
"com.docker.compose.service": "redis",
"com.docker.compose.version": "2.16.0"
}
},
"NetworkSettings": {
"Bridge": "",
"SandboxID": "3df878d8ed31b2686e41437f141bebba8afcf3bdf8c47ea07c34c2e0b365ec88",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {
"6379/tcp": [
{
"HostIp": "0.0.0.0",
"HostPort": "32770"
},
{
"HostIp": "::",
"HostPort": "32770"
}
]
},
"SandboxKey": "/var/run/docker/netns/3df878d8ed31",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "",
"Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "",
"IPPrefixLen": 0,
"IPv6Gateway": "",
"MacAddress": "",
"Networks": {
"redis-docker_default": {
"IPAMConfig": null,
"Links": null,
"Aliases": [
"redis-docker-redis-1",
"redis",
"f5af31dae7f6"
],
"NetworkID": "9cb2b8b6fb20703841b9337b48e65ed2a71e2da2e995e4782066d146c44fc205",
"EndpointID": "e155c61c1608b20ba7a0bd34790fc342ec576310f75ef4399e96bf3a67e8b3f6",
"Gateway": "192.168.32.1",
"IPAddress": "192.168.32.2",
"IPPrefixLen": 20,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:c0:a8:20:02",
"DriverOpts": null
}
}
}
}

View File

@@ -0,0 +1,11 @@
services:
elasticsearch:
image: 'elasticsearch:8.6.1'
environment:
- 'ELASTIC_PASSWORD=secret'
- 'ES_JAVA_OPTS=-Xmx512m'
- 'xpack.security.enabled=false'
- 'discovery.type=single-node'
ports:
- '9200'
- '9300'

View File

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

View File

@@ -0,0 +1,9 @@
services:
mongo:
image: 'mongo:6.0'
ports:
- '27017'
environment:
MONGO_INITDB_ROOT_USERNAME: 'root'
MONGO_INITDB_ROOT_PASSWORD: 'secret'
MONGO_INITDB_DATABASE: 'mydatabase'

View File

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

View File

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

View File

@@ -0,0 +1,8 @@
services:
rabbitmq:
image: 'rabbitmq:3.11'
environment:
- 'RABBITMQ_DEFAULT_USER=myuser'
- 'RABBITMQ_DEFAULT_PASS=secret'
ports:
- '5672'

View File

@@ -0,0 +1,5 @@
services:
zipkin:
image: 'openzipkin/zipkin:2.24'
ports:
- '9411'