From f24f1b247584f0f652dad65e52b80b7f825d78c1 Mon Sep 17 00:00:00 2001 From: Basil Crow Date: Sun, 2 Jun 2019 16:01:52 -0700 Subject: [PATCH] Allow port reuse in RestartableJenkinsRule Testing the Swarm client requires having Jenkins run on the same port before and after restart. This change adds this functionality to RestartableJenkinsRule. The new functionality is opt-in to preserve existing behavior for tests which don't need this functionality. --- .../org/jvnet/hudson/test/JenkinsRule.java | 5 +- .../hudson/test/RestartableJenkinsRule.java | 45 ++++++++++++++- .../test/RestartableJenkinsRuleTest.java | 55 +++++++++++++++++++ 3 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 src/test/java/org/jvnet/hudson/test/RestartableJenkinsRuleTest.java diff --git a/src/main/java/org/jvnet/hudson/test/JenkinsRule.java b/src/main/java/org/jvnet/hudson/test/JenkinsRule.java index 193eeca52..739c838b9 100644 --- a/src/main/java/org/jvnet/hudson/test/JenkinsRule.java +++ b/src/main/java/org/jvnet/hudson/test/JenkinsRule.java @@ -693,8 +693,11 @@ public Thread newThread(Runnable r) { // use a bigger buffer as Stapler traces can get pretty large on deeply nested URL config.setRequestHeaderSize(12 * 1024); connector.setHost("localhost"); - if (System.getProperty("port")!=null) + if (System.getProperty("port") != null) { connector.setPort(Integer.parseInt(System.getProperty("port"))); + } else if (localPort != 0) { + connector.setPort(localPort); + } server.addConnector(connector); server.start(); diff --git a/src/main/java/org/jvnet/hudson/test/RestartableJenkinsRule.java b/src/main/java/org/jvnet/hudson/test/RestartableJenkinsRule.java index 8346a02b8..6dc2edee4 100644 --- a/src/main/java/org/jvnet/hudson/test/RestartableJenkinsRule.java +++ b/src/main/java/org/jvnet/hudson/test/RestartableJenkinsRule.java @@ -10,6 +10,8 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; +import java.io.UncheckedIOException; +import java.net.ServerSocket; import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.LinkOption; @@ -62,8 +64,38 @@ public class RestartableJenkinsRule implements MethodRule { */ public File home; + /** + * TCP/IP port that the server is listening on. + */ + private final int port; + private static final Logger LOGGER = Logger.getLogger(HudsonTestCase.class.getName()); + public static class Builder { + private int port; + + public Builder() { + this.port = 0; + } + + public Builder withReusedPort() { + this.port = getRandomPort(); + return this; + } + + public RestartableJenkinsRule build() { + return new RestartableJenkinsRule(this.port); + } + } + + public RestartableJenkinsRule() { + this.port = 0; + } + + private RestartableJenkinsRule(int port) { + this.port = port; + } + @Override public Statement apply(final Statement base, FrameworkMethod method, Object target) { this.description = Description.createTestDescription( @@ -279,7 +311,18 @@ private void run() throws Throwable { } protected JenkinsRule createJenkinsRule(Description description) { - return new JenkinsRule(); + JenkinsRule result = new JenkinsRule(); + if (port != 0) { + result.localPort = port; + } + return result; } + private static synchronized int getRandomPort() { + try (ServerSocket s = new ServerSocket(0)) { + return s.getLocalPort(); + } catch (IOException e) { + throw new UncheckedIOException("Unable to find free port", e); + } + } } diff --git a/src/test/java/org/jvnet/hudson/test/RestartableJenkinsRuleTest.java b/src/test/java/org/jvnet/hudson/test/RestartableJenkinsRuleTest.java new file mode 100644 index 000000000..2721b3c22 --- /dev/null +++ b/src/test/java/org/jvnet/hudson/test/RestartableJenkinsRuleTest.java @@ -0,0 +1,55 @@ +package org.jvnet.hudson.test; + +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assume.assumeThat; + +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.Rule; +import org.junit.Test; + +public class RestartableJenkinsRuleTest { + + @Rule public RestartableJenkinsRule noPortReuse = new RestartableJenkinsRule(); + + @Rule + public RestartableJenkinsRule portReuse = + new RestartableJenkinsRule.Builder().withReusedPort().build(); + + @Test + public void testNoPortReuse() throws Exception { + assumeThat( + "This test requires a custom port to not be set.", + System.getProperty("port"), + nullValue()); + + AtomicInteger port = new AtomicInteger(); + noPortReuse.then( + s -> { + port.set(noPortReuse.j.getURL().getPort()); + }); + noPortReuse.then( + s -> { + assertNotEquals(port.get(), noPortReuse.j.getURL().getPort()); + }); + } + + @Test + public void testPortReuse() throws Exception { + assumeThat( + "This test requires a custom port to not be set.", + System.getProperty("port"), + nullValue()); + + AtomicInteger port = new AtomicInteger(); + portReuse.then( + s -> { + port.set(portReuse.j.getURL().getPort()); + }); + portReuse.then( + s -> { + assertEquals(port.get(), portReuse.j.getURL().getPort()); + }); + } +}