diff --git a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/DockerComposeLifecycleManager.java b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/DockerComposeLifecycleManager.java index 4b5f0871ce4..72498b045c4 100644 --- a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/DockerComposeLifecycleManager.java +++ b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/DockerComposeLifecycleManager.java @@ -31,7 +31,6 @@ import org.springframework.boot.docker.compose.core.DockerComposeFile; import org.springframework.boot.docker.compose.core.RunningService; import org.springframework.boot.docker.compose.lifecycle.DockerComposeProperties.Start; import org.springframework.boot.docker.compose.lifecycle.DockerComposeProperties.Stop; -import org.springframework.boot.docker.compose.readiness.ServiceReadinessChecks; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationListener; import org.springframework.context.event.SimpleApplicationEventMulticaster; @@ -88,7 +87,7 @@ class DockerComposeLifecycleManager { this.eventListeners = eventListeners; this.skipCheck = skipCheck; this.serviceReadinessChecks = (serviceReadinessChecks != null) ? serviceReadinessChecks - : new ServiceReadinessChecks(this.classLoader, applicationContext.getEnvironment(), binder); + : new ServiceReadinessChecks(properties.getReadiness()); } void start() { diff --git a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/DockerComposeProperties.java b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/DockerComposeProperties.java index 8d335bb1989..26cea3ff04d 100644 --- a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/DockerComposeProperties.java +++ b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/DockerComposeProperties.java @@ -75,6 +75,8 @@ public class DockerComposeProperties { private final Skip skip = new Skip(); + private final Readiness readiness = new Readiness(); + public boolean isEnabled() { return this.enabled; } @@ -123,6 +125,10 @@ public class DockerComposeProperties { return this.skip; } + public Readiness getReadiness() { + return this.readiness; + } + static DockerComposeProperties get(Binder binder) { return binder.bind(NAME, DockerComposeProperties.class).orElseGet(DockerComposeProperties::new); } @@ -233,4 +239,66 @@ public class DockerComposeProperties { } + /** + * Readiness properties. + */ + public static class Readiness { + + /** + * Timeout of the readiness checks. + */ + private Duration timeout = Duration.ofMinutes(2); + + /** + * TCP properties. + */ + private final Tcp tcp = new Tcp(); + + public Duration getTimeout() { + return this.timeout; + } + + public void setTimeout(Duration timeout) { + this.timeout = timeout; + } + + public Tcp getTcp() { + return this.tcp; + } + + /** + * TCP properties. + */ + public static class Tcp { + + /** + * Timeout for connections. + */ + private Duration connectTimeout = Duration.ofMillis(200); + + /** + * Timeout for reads. + */ + private Duration readTimeout = Duration.ofMillis(200); + + public Duration getConnectTimeout() { + return this.connectTimeout; + } + + public void setConnectTimeout(Duration connectTimeout) { + this.connectTimeout = connectTimeout; + } + + public Duration getReadTimeout() { + return this.readTimeout; + } + + public void setReadTimeout(Duration readTimeout) { + this.readTimeout = readTimeout; + } + + } + + } + } diff --git a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/readiness/ReadinessTimeoutException.java b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/ReadinessTimeoutException.java similarity index 87% rename from spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/readiness/ReadinessTimeoutException.java rename to spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/ReadinessTimeoutException.java index 65da0515f63..7465730c108 100644 --- a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/readiness/ReadinessTimeoutException.java +++ b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/ReadinessTimeoutException.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.docker.compose.readiness; +package org.springframework.boot.docker.compose.lifecycle; import java.time.Duration; import java.util.List; @@ -23,9 +23,7 @@ import java.util.Objects; import org.springframework.boot.docker.compose.core.RunningService; /** - * Exception thrown if readiness checking has timed out. Related - * {@link ServiceNotReadyException ServiceNotReadyExceptions} are available from - * {@link #getSuppressed()}. + * Exception thrown if readiness checking has timed out. * * @author Moritz Halbritter * @author Andy Wilkinson diff --git a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/readiness/ServiceNotReadyException.java b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/ServiceNotReadyException.java similarity index 79% rename from spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/readiness/ServiceNotReadyException.java rename to spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/ServiceNotReadyException.java index af7cc4f22bd..dea78a9e9ff 100644 --- a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/readiness/ServiceNotReadyException.java +++ b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/ServiceNotReadyException.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.docker.compose.readiness; +package org.springframework.boot.docker.compose.lifecycle; import org.springframework.boot.docker.compose.core.RunningService; @@ -24,10 +24,8 @@ import org.springframework.boot.docker.compose.core.RunningService; * @author Moritz Halbritter * @author Andy Wilkinson * @author Phillip Webb - * @since 3.1.0 - * @see ServiceReadinessCheck */ -public class ServiceNotReadyException extends RuntimeException { +class ServiceNotReadyException extends RuntimeException { private final RunningService service; @@ -40,11 +38,7 @@ public class ServiceNotReadyException extends RuntimeException { this.service = service; } - /** - * Return the service that was not ready. - * @return the non-ready service - */ - public RunningService getService() { + RunningService getService() { return this.service; } diff --git a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/readiness/ServiceReadinessChecks.java b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/ServiceReadinessChecks.java similarity index 57% rename from spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/readiness/ServiceReadinessChecks.java rename to spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/ServiceReadinessChecks.java index 4d1ea225262..b08cb62d919 100644 --- a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/readiness/ServiceReadinessChecks.java +++ b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/ServiceReadinessChecks.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.docker.compose.readiness; +package org.springframework.boot.docker.compose.lifecycle; import java.time.Clock; import java.time.Duration; @@ -23,28 +23,21 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.function.Consumer; -import java.util.function.Function; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -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; -import org.springframework.core.io.support.SpringFactoriesLoader.ArgumentResolver; import org.springframework.core.log.LogMessage; /** - * A collection of {@link ServiceReadinessCheck} instances that can be used to - * {@link #wait() wait} for {@link RunningService services} to be ready. + * Utility used to {@link #wait() wait} for {@link RunningService services} to be ready. * * @author Moritz Halbritter * @author Andy Wilkinson * @author Phillip Webb - * @since 3.1.0 */ -public class ServiceReadinessChecks { +class ServiceReadinessChecks { private static final Log logger = LogFactory.getLog(ServiceReadinessChecks.class); @@ -56,34 +49,28 @@ public class ServiceReadinessChecks { private final Consumer sleep; - private final ReadinessProperties properties; + private final DockerComposeProperties.Readiness properties; - private final List checks; + private final TcpConnectServiceReadinessCheck check; - public ServiceReadinessChecks(ClassLoader classLoader, Environment environment, Binder binder) { - this(Clock.systemUTC(), ServiceReadinessChecks::sleep, - SpringFactoriesLoader.forDefaultResourceLocation(classLoader), classLoader, environment, binder, - TcpConnectServiceReadinessCheck::new); + ServiceReadinessChecks(DockerComposeProperties.Readiness properties) { + this(properties, Clock.systemUTC(), ServiceReadinessChecks::sleep, + new TcpConnectServiceReadinessCheck(properties.getTcp())); } - ServiceReadinessChecks(Clock clock, Consumer sleep, SpringFactoriesLoader loader, ClassLoader classLoader, - Environment environment, Binder binder, - Function tcpCheckFactory) { - ArgumentResolver argumentResolver = ArgumentResolver.of(ClassLoader.class, classLoader) - .and(Environment.class, environment) - .and(Binder.class, binder); + ServiceReadinessChecks(DockerComposeProperties.Readiness properties, Clock clock, Consumer sleep, + TcpConnectServiceReadinessCheck check) { this.clock = clock; this.sleep = sleep; - this.properties = ReadinessProperties.get(binder); - this.checks = new ArrayList<>(loader.load(ServiceReadinessCheck.class, argumentResolver)); - this.checks.add(tcpCheckFactory.apply(this.properties.getTcp())); + this.properties = properties; + this.check = check; } /** * Wait for the given services to be ready. * @param runningServices the services to wait for */ - public void waitUntilReady(List runningServices) { + void waitUntilReady(List runningServices) { Duration timeout = this.properties.getTimeout(); Instant start = this.clock.instant(); while (true) { @@ -106,16 +93,14 @@ public class ServiceReadinessChecks { continue; } logger.trace(LogMessage.format("Checking readiness of service '%s'", service)); - for (ServiceReadinessCheck check : this.checks) { - try { - check.check(service); - logger.trace(LogMessage.format("Service '%s' is ready", service)); - } - catch (ServiceNotReadyException ex) { - logger.trace(LogMessage.format("Service '%s' is not ready", service), ex); - exceptions = (exceptions != null) ? exceptions : new ArrayList<>(); - exceptions.add(ex); - } + try { + this.check.check(service); + logger.trace(LogMessage.format("Service '%s' is ready", service)); + } + catch (ServiceNotReadyException ex) { + logger.trace(LogMessage.format("Service '%s' is not ready", service), ex); + exceptions = (exceptions != null) ? exceptions : new ArrayList<>(); + exceptions.add(ex); } } return (exceptions != null) ? exceptions : Collections.emptyList(); diff --git a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/readiness/TcpConnectServiceReadinessCheck.java b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/TcpConnectServiceReadinessCheck.java similarity index 84% rename from spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/readiness/TcpConnectServiceReadinessCheck.java rename to spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/TcpConnectServiceReadinessCheck.java index c68e088a2a7..ee00bd9d1b0 100644 --- a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/readiness/TcpConnectServiceReadinessCheck.java +++ b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/TcpConnectServiceReadinessCheck.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.docker.compose.readiness; +package org.springframework.boot.docker.compose.lifecycle; import java.io.IOException; import java.net.InetSocketAddress; @@ -24,25 +24,23 @@ import java.net.SocketTimeoutException; import org.springframework.boot.docker.compose.core.RunningService; /** - * Default {@link ServiceReadinessCheck} that checks readiness by connecting to the - * exposed TCP ports. + * Checks readiness by connecting to the exposed TCP ports. * * @author Moritz Halbritter * @author Andy Wilkinson * @author Phillip Webb */ -class TcpConnectServiceReadinessCheck implements ServiceReadinessCheck { +class TcpConnectServiceReadinessCheck { private static final String DISABLE_LABEL = "org.springframework.boot.readiness-check.tcp.disable"; - private final ReadinessProperties.Tcp properties; + private final DockerComposeProperties.Readiness.Tcp properties; - TcpConnectServiceReadinessCheck(ReadinessProperties.Tcp properties) { + TcpConnectServiceReadinessCheck(DockerComposeProperties.Readiness.Tcp properties) { this.properties = properties; } - @Override - public void check(RunningService service) { + void check(RunningService service) { if (service.labels().containsKey(DISABLE_LABEL)) { return; } diff --git a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/readiness/ReadinessProperties.java b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/readiness/ReadinessProperties.java deleted file mode 100644 index 8e4a561df80..00000000000 --- a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/readiness/ReadinessProperties.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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 org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.boot.context.properties.bind.Binder; - -/** - * Readiness configuration properties. - * - * @author Moritz Halbritter - * @author Andy Wilkinson - * @author Phillip Webb - * @since 3.1.0 - */ -@ConfigurationProperties(ReadinessProperties.NAME) -public class ReadinessProperties { - - static final String NAME = "spring.docker.compose.readiness"; - - /** - * Timeout of the readiness checks. - */ - private Duration timeout = Duration.ofMinutes(2); - - /** - * TCP properties. - */ - private final Tcp tcp = new Tcp(); - - public Duration getTimeout() { - return this.timeout; - } - - public void setTimeout(Duration timeout) { - this.timeout = timeout; - } - - public Tcp getTcp() { - return this.tcp; - } - - /** - * Get the properties using the given binder. - * @param binder the binder used to get the properties - * @return a bound {@link ReadinessProperties} instance - */ - static ReadinessProperties get(Binder binder) { - return binder.bind(ReadinessProperties.NAME, ReadinessProperties.class).orElseGet(ReadinessProperties::new); - } - - /** - * TCP properties. - */ - public static class Tcp { - - /** - * Timeout for connections. - */ - private Duration connectTimeout = Duration.ofMillis(200); - - /** - * Timeout for reads. - */ - private Duration readTimeout = Duration.ofMillis(200); - - public Duration getConnectTimeout() { - return this.connectTimeout; - } - - public void setConnectTimeout(Duration connectTimeout) { - this.connectTimeout = connectTimeout; - } - - public Duration getReadTimeout() { - return this.readTimeout; - } - - public void setReadTimeout(Duration readTimeout) { - this.readTimeout = readTimeout; - } - - } - -} diff --git a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/readiness/ServiceReadinessCheck.java b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/readiness/ServiceReadinessCheck.java deleted file mode 100644 index 0f4c9d2f62a..00000000000 --- a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/readiness/ServiceReadinessCheck.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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.springframework.boot.context.properties.bind.Binder; -import org.springframework.boot.docker.compose.core.RunningService; -import org.springframework.core.env.Environment; - -/** - * Strategy used to check if a {@link RunningService} is ready. Implementations may be - * registered in {@code spring.factories}. The following constructor arguments types are - * supported: - *
    - *
  • {@link ClassLoader}
  • - *
  • {@link Environment}
  • - *
  • {@link Binder}
  • - *
- * - * @author Moritz Halbritter - * @author Andy Wilkinson - * @author Phillip Webb - * @since 3.1.0 - */ -public interface ServiceReadinessCheck { - - /** - * Checks whether the given {@code service} is ready. - * @param service service to check - * @throws ServiceNotReadyException if the service is not ready - */ - void check(RunningService service) throws ServiceNotReadyException; - -} diff --git a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/readiness/package-info.java b/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/readiness/package-info.java deleted file mode 100644 index 17542adf3ae..00000000000 --- a/spring-boot-project/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/readiness/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * 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. - */ - -/** - * Service readiness checks. - */ -package org.springframework.boot.docker.compose.readiness; diff --git a/spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/lifecycle/DockerComposeLifecycleManagerTests.java b/spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/lifecycle/DockerComposeLifecycleManagerTests.java index 81434a0fb66..89d67a19bd0 100644 --- a/spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/lifecycle/DockerComposeLifecycleManagerTests.java +++ b/spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/lifecycle/DockerComposeLifecycleManagerTests.java @@ -36,7 +36,6 @@ 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; diff --git a/spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/lifecycle/DockerComposePropertiesTests.java b/spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/lifecycle/DockerComposePropertiesTests.java index 23e6c39b894..03103c73fb2 100644 --- a/spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/lifecycle/DockerComposePropertiesTests.java +++ b/spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/lifecycle/DockerComposePropertiesTests.java @@ -48,6 +48,9 @@ class DockerComposePropertiesTests { assertThat(properties.getStop().getCommand()).isEqualTo(StopCommand.STOP); assertThat(properties.getStop().getTimeout()).isEqualTo(Duration.ofSeconds(10)); assertThat(properties.getProfiles().getActive()).isEmpty(); + assertThat(properties.getReadiness().getTimeout()).isEqualTo(Duration.ofMinutes(2)); + assertThat(properties.getReadiness().getTcp().getConnectTimeout()).isEqualTo(Duration.ofMillis(200)); + assertThat(properties.getReadiness().getTcp().getReadTimeout()).isEqualTo(Duration.ofMillis(200)); } @Test @@ -60,6 +63,9 @@ class DockerComposePropertiesTests { source.put("spring.docker.compose.stop.command", "down"); source.put("spring.docker.compose.stop.timeout", "5s"); source.put("spring.docker.compose.profiles.active", "myprofile"); + 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)); DockerComposeProperties properties = DockerComposeProperties.get(binder); assertThat(properties.getFile()).isEqualTo(new File("my-compose.yml")); @@ -69,6 +75,9 @@ class DockerComposePropertiesTests { assertThat(properties.getStop().getCommand()).isEqualTo(StopCommand.DOWN); assertThat(properties.getStop().getTimeout()).isEqualTo(Duration.ofSeconds(5)); assertThat(properties.getProfiles().getActive()).containsExactly("myprofile"); + assertThat(properties.getReadiness().getTimeout()).isEqualTo(Duration.ofSeconds(10)); + assertThat(properties.getReadiness().getTcp().getConnectTimeout()).isEqualTo(Duration.ofMillis(400)); + assertThat(properties.getReadiness().getTcp().getReadTimeout()).isEqualTo(Duration.ofMillis(500)); } } diff --git a/spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/readiness/ReadinessTimeoutExceptionTests.java b/spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/lifecycle/ReadinessTimeoutExceptionTests.java similarity index 97% rename from spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/readiness/ReadinessTimeoutExceptionTests.java rename to spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/lifecycle/ReadinessTimeoutExceptionTests.java index 8e6bbc0c925..c229da365b8 100644 --- a/spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/readiness/ReadinessTimeoutExceptionTests.java +++ b/spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/lifecycle/ReadinessTimeoutExceptionTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.docker.compose.readiness; +package org.springframework.boot.docker.compose.lifecycle; import java.time.Duration; import java.util.List; diff --git a/spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/readiness/ServiceNotReadyExceptionTests.java b/spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/lifecycle/ServiceNotReadyExceptionTests.java similarity index 95% rename from spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/readiness/ServiceNotReadyExceptionTests.java rename to spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/lifecycle/ServiceNotReadyExceptionTests.java index a6aad170755..6db005a1284 100644 --- a/spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/readiness/ServiceNotReadyExceptionTests.java +++ b/spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/lifecycle/ServiceNotReadyExceptionTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.docker.compose.readiness; +package org.springframework.boot.docker.compose.lifecycle; import org.junit.jupiter.api.Test; diff --git a/spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/readiness/ServiceReadinessChecksTests.java b/spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/lifecycle/ServiceReadinessChecksTests.java similarity index 57% rename from spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/readiness/ServiceReadinessChecksTests.java rename to spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/lifecycle/ServiceReadinessChecksTests.java index 237aefbf82b..fa1f350ba35 100644 --- a/spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/readiness/ServiceReadinessChecksTests.java +++ b/spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/lifecycle/ServiceReadinessChecksTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.docker.compose.readiness; +package org.springframework.boot.docker.compose.lifecycle; import java.time.Clock; import java.time.Duration; @@ -25,22 +25,13 @@ import java.util.Map; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.mockito.ArgumentMatchers; -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}. @@ -55,68 +46,37 @@ class ServiceReadinessChecksTests { Instant now = Instant.now(); - private MockSpringFactoriesLoader loader; - - private ClassLoader classLoader; - - private MockEnvironment environment; - - private Binder binder; - private RunningService runningService; private List runningServices; - private final 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(); - then(this.loader).should() - .load(eq(ServiceReadinessCheck.class), ArgumentMatchers.assertArg((argumentResolver) -> { - 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); + createChecks(check).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); + createChecks(check).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)) + .isThrownBy(() -> createChecks(check).waitUntilReady(this.runningServices)) .satisfies((ex) -> assertThat(ex.getSuppressed()).hasSize(1)); assertThat(check.getChecked()).hasSizeGreaterThan(10); } @@ -125,25 +85,23 @@ class ServiceReadinessChecksTests { 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); + createChecks(check).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); + private ServiceReadinessChecks createChecks(TcpConnectServiceReadinessCheck check) { + DockerComposeProperties properties = new DockerComposeProperties(); + return new ServiceReadinessChecks(properties.getReadiness(), this.clock, this::sleep, check); } /** - * Mock {@link ServiceReadinessCheck}. + * Mock {@link TcpConnectServiceReadinessCheck}. */ - static class MockServiceReadinessCheck implements ServiceReadinessCheck { + static class MockServiceReadinessCheck extends TcpConnectServiceReadinessCheck { private final Integer failUntil; @@ -154,6 +112,7 @@ class ServiceReadinessChecksTests { } MockServiceReadinessCheck(Integer failUntil) { + super(null); this.failUntil = failUntil; } diff --git a/spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/readiness/TcpConnectServiceReadinessCheckTests.java b/spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/lifecycle/TcpConnectServiceReadinessCheckTests.java similarity index 96% rename from spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/readiness/TcpConnectServiceReadinessCheckTests.java rename to spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/lifecycle/TcpConnectServiceReadinessCheckTests.java index 619afa0a223..3e81a2cef3d 100644 --- a/spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/readiness/TcpConnectServiceReadinessCheckTests.java +++ b/spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/lifecycle/TcpConnectServiceReadinessCheckTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.docker.compose.readiness; +package org.springframework.boot.docker.compose.lifecycle; import java.io.IOException; import java.io.UncheckedIOException; @@ -50,7 +50,7 @@ class TcpConnectServiceReadinessCheckTests { @BeforeEach void setup() { - ReadinessProperties.Tcp tcpProperties = new ReadinessProperties.Tcp(); + DockerComposeProperties.Readiness.Tcp tcpProperties = new DockerComposeProperties.Readiness.Tcp(); tcpProperties.setConnectTimeout(Duration.ofMillis(100)); tcpProperties.setReadTimeout(Duration.ofMillis(100)); this.readinessCheck = new TcpConnectServiceReadinessCheck(tcpProperties); diff --git a/spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/readiness/ReadinessPropertiesTests.java b/spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/readiness/ReadinessPropertiesTests.java deleted file mode 100644 index 374733179f6..00000000000 --- a/spring-boot-project/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/readiness/ReadinessPropertiesTests.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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 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)); - - } - -} diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/docker-compose.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/docker-compose.adoc index db2b531899e..6621b515769 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/docker-compose.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/docker-compose.adoc @@ -184,8 +184,6 @@ You can also change timeout values in your `application.properties` or `applicat The overall timeout can be configured using configprop:spring.docker.compose.readiness.timeout[]. -TIP: You can also provide your own `ServiceReadinessCheck` implementations and register them in the `spring.factories` file. - [[features.docker-compose.lifecycle]]