diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactoryTests.java index abf4bacc06d..4e36707c62a 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatServletWebServerFactoryTests.java @@ -288,7 +288,7 @@ public class TomcatServletWebServerFactoryTests extends AbstractServletWebServer } @Test - public void primaryConnectorPortClashThrowsWebServerException() throws IOException { + public void primaryConnectorPortClashThrowsWebServerException() throws Exception { doWithBlockedPort((port) -> { TomcatServletWebServerFactory factory = getFactory(); factory.setPort(port); @@ -300,7 +300,7 @@ public class TomcatServletWebServerFactoryTests extends AbstractServletWebServer } @Test - public void startupFailureDoesNotResultInUnstoppedThreadsBeingReported() throws IOException { + public void startupFailureDoesNotResultInUnstoppedThreadsBeingReported() throws Exception { super.portClashOfPrimaryConnectorResultsInPortInUseException(); String string = this.outputCapture.toString(); assertThat(string).doesNotContain("appears to have started a thread named [main]"); diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java index d23e9a3168d..c00003ef464 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/AbstractReactiveWebServerFactoryTests.java @@ -23,6 +23,7 @@ import java.nio.charset.StandardCharsets; import java.security.KeyStore; import java.time.Duration; import java.util.Arrays; +import java.util.concurrent.Callable; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLException; @@ -92,12 +93,15 @@ public abstract class AbstractReactiveWebServerFactoryTests { protected abstract AbstractReactiveWebServerFactory getFactory(); @Test - public void specificPort() { + public void specificPort() throws Exception { AbstractReactiveWebServerFactory factory = getFactory(); - int specificPort = SocketUtils.findAvailableTcpPort(41000); - factory.setPort(specificPort); - this.webServer = factory.getWebServer(new EchoHandler()); - this.webServer.start(); + int specificPort = doWithRetry(() -> { + int port = SocketUtils.findAvailableTcpPort(41000); + factory.setPort(port); + this.webServer = factory.getWebServer(new EchoHandler()); + this.webServer.start(); + return port; + }); Mono result = getWebClient().build().post().uri("/test").contentType(MediaType.TEXT_PLAIN) .body(BodyInserters.fromObject("Hello World")).exchange() .flatMap((response) -> response.bodyToMono(String.class)); @@ -113,6 +117,7 @@ public abstract class AbstractReactiveWebServerFactoryTests { @Test public void basicSslFromFileSystem() { testBasicSslWithKeyStore("src/test/resources/test.jks", "password"); + } protected final void testBasicSslWithKeyStore(String keyStore, String keyPassword) { @@ -335,6 +340,19 @@ public abstract class AbstractReactiveWebServerFactoryTests { assertThat(body).isEqualTo("https"); } + private T doWithRetry(Callable action) throws Exception { + Exception lastFailure = null; + for (int i = 0; i < 10; i++) { + try { + return action.call(); + } + catch (Exception ex) { + lastFailure = ex; + } + } + throw new IllegalStateException("Action was not successful in 10 attempts", lastFailure); + } + protected static class EchoHandler implements HttpHandler { public EchoHandler() { diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/server/AbstractServletWebServerFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/server/AbstractServletWebServerFactoryTests.java index 18fbb798903..8bbcd82b2b0 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/server/AbstractServletWebServerFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/server/AbstractServletWebServerFactoryTests.java @@ -44,6 +44,7 @@ import java.util.EnumSet; import java.util.HashMap; import java.util.Locale; import java.util.Map; +import java.util.concurrent.Callable; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import java.util.zip.GZIPInputStream; @@ -248,10 +249,13 @@ public abstract class AbstractServletWebServerFactoryTests { @Test public void specificPort() throws Exception { AbstractServletWebServerFactory factory = getFactory(); - int specificPort = SocketUtils.findAvailableTcpPort(41000); - factory.setPort(specificPort); - this.webServer = factory.getWebServer(exampleServletRegistration()); - this.webServer.start(); + int specificPort = doWithRetry(() -> { + int port = SocketUtils.findAvailableTcpPort(41000); + factory.setPort(port); + this.webServer = factory.getWebServer(exampleServletRegistration()); + this.webServer.start(); + return port; + }); assertThat(getResponse("http://localhost:" + specificPort + "/hello")).isEqualTo("Hello World"); assertThat(this.webServer.getPort()).isEqualTo(specificPort); } @@ -822,7 +826,7 @@ public abstract class AbstractServletWebServerFactoryTests { } @Test - public void portClashOfPrimaryConnectorResultsInPortInUseException() throws IOException { + public void portClashOfPrimaryConnectorResultsInPortInUseException() throws Exception { doWithBlockedPort((port) -> { assertThatExceptionOfType(RuntimeException.class).isThrownBy(() -> { AbstractServletWebServerFactory factory = getFactory(); @@ -834,7 +838,7 @@ public abstract class AbstractServletWebServerFactoryTests { } @Test - public void portClashOfSecondaryConnectorResultsInPortInUseException() throws IOException { + public void portClashOfSecondaryConnectorResultsInPortInUseException() throws Exception { doWithBlockedPort((port) -> { assertThatExceptionOfType(RuntimeException.class).isThrownBy(() -> { AbstractServletWebServerFactory factory = getFactory(); @@ -1128,19 +1132,28 @@ public abstract class AbstractServletWebServerFactoryTests { return bean; } - protected final void doWithBlockedPort(BlockedPortAction action) throws IOException { - int port = SocketUtils.findAvailableTcpPort(40000); - ServerSocket serverSocket = new ServerSocket(); + private T doWithRetry(Callable action) throws Exception { + Exception lastFailure = null; for (int i = 0; i < 10; i++) { try { - serverSocket.bind(new InetSocketAddress(port)); - break; + return action.call(); } catch (Exception ex) { + lastFailure = ex; } } + throw new IllegalStateException("Action was not successful in 10 attempts", lastFailure); + } + + protected final void doWithBlockedPort(BlockedPortAction action) throws Exception { + ServerSocket serverSocket = new ServerSocket(); + int blockedPort = doWithRetry(() -> { + int port = SocketUtils.findAvailableTcpPort(40000); + serverSocket.bind(new InetSocketAddress(port)); + return port; + }); try { - action.run(port); + action.run(blockedPort); } finally { serverSocket.close();