Skip to content

Commit

Permalink
Merge pull request #924 from Vlatombe/custom-prefix
Browse files Browse the repository at this point in the history
Add support for custom prefix
  • Loading branch information
jglick authored Feb 27, 2025
2 parents 7b34567 + 82aaf75 commit 1e79b0d
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 7 deletions.
33 changes: 30 additions & 3 deletions src/main/java/org/jvnet/hudson/test/RealJenkinsRule.java
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,9 @@ public final class RealJenkinsRule implements TestRule {
private SSLSocketFactory sslSocketFactory;
private X509Certificate rootCA;

@NonNull
private String prefix = "/jenkins";

public RealJenkinsRule() {
home = new AtomicReference<>();
}
Expand Down Expand Up @@ -390,6 +393,26 @@ public RealJenkinsRule withHost(String host) {
return this;
}

/**
* Sets a custom prefix for the Jenkins root URL.
* <p>
* By default, the prefix defaults to {@code /jenkins}.
* <p>
* If not empty, must start with '/' and not end with '/'.
*/
public RealJenkinsRule withPrefix(@NonNull String prefix) {
if (!prefix.isEmpty()) {
if (!prefix.startsWith("/")) {
throw new IllegalArgumentException("Prefix must start with a leading slash.");
}
if (prefix.endsWith("/")) {
throw new IllegalArgumentException("Prefix must not end with a trailing slash.");
}
}
this.prefix = prefix;
return this;
}

/**
* Sets a custom WAR file to be used by the rule instead of the one in the path or {@code war/target/jenkins.war} in case of core.
*/
Expand Down Expand Up @@ -820,12 +843,14 @@ public <T extends Serializable> T then(Step2<T> s) throws Throwable {

/**
* Similar to {@link JenkinsRule#getURL}. Requires Jenkins to be started before using {@link #startJenkins()}.
* <p>
* Always ends with a '/'.
*/
public URL getUrl() throws MalformedURLException {
if (port == 0) {
throw new IllegalStateException("This method must be called after calling #startJenkins.");
}
return new URL(https ? "https" : "http", host, port, "/jenkins/");
return new URL(https ? "https" : "http", host, port, prefix + "/");
}

/**
Expand Down Expand Up @@ -1008,8 +1033,10 @@ public void startJenkins() throws Throwable {
argv.addAll(List.of(
"-jar", war.getAbsolutePath(),
"--enable-future-java",
"--httpListenAddress=" + httpListenAddress,
"--prefix=/jenkins"));
"--httpListenAddress=" + httpListenAddress));
if (!prefix.isEmpty()) {
argv.add("--prefix=" + prefix);
}
argv.addAll(getPortOptions());
if (https) {
argv.add("--httpsKeyStore=" + keyStoreManager.getPath().toAbsolutePath());
Expand Down
36 changes: 32 additions & 4 deletions src/test/java/org/jvnet/hudson/test/RealJenkinsRuleTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.arrayContainingInAnyOrder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.emptyString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
Expand All @@ -36,6 +38,7 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
Expand Down Expand Up @@ -75,7 +78,6 @@
import javax.servlet.ServletResponse;
import jenkins.model.Jenkins;
import jenkins.model.JenkinsLocationConfiguration;
import static org.junit.Assume.assumeThat;
import org.junit.AssumptionViolatedException;
import org.junit.Ignore;
import org.junit.Rule;
Expand All @@ -100,15 +102,41 @@ private static void _smokes(JenkinsRule r) throws Throwable {

@Test public void testReturnObject() throws Throwable {
rr.startJenkins();
assertEquals(rr.getUrl().toExternalForm(), rr.runRemotely(RealJenkinsRuleTest::_getJenkinsUrlFromRemote));
assertThatLocalAndRemoteUrlEquals();
}

@Test public void customPrefix() throws Throwable {
rr.withPrefix("/foo").startJenkins();
assertThat(rr.getUrl().getPath(), equalTo("/foo/"));
assertThatLocalAndRemoteUrlEquals();
}

@Test public void complexPrefix() throws Throwable {
rr.withPrefix("/foo/bar").startJenkins();
assertThat(rr.getUrl().getPath(), equalTo("/foo/bar/"));
assertThatLocalAndRemoteUrlEquals();
}

@Test public void noPrefix() throws Throwable {
rr.withPrefix("").startJenkins();
assertThat(rr.getUrl().getPath(), equalTo("/"));
assertThatLocalAndRemoteUrlEquals();
}

@Test public void invalidPrefixes() {
assertThrows(IllegalArgumentException.class, () -> rr.withPrefix("foo"));
assertThrows(IllegalArgumentException.class, () -> rr.withPrefix("/foo/"));
}

@Test public void ipv6() throws Throwable {
// Use -Djava.net.preferIPv6Addresses=true if dualstack
assumeThat(InetAddress.getLoopbackAddress(), instanceOf(Inet6Address.class));
rr.withHost("::1").startJenkins();
var externalForm = rr.getUrl().toExternalForm();
assertEquals(externalForm, rr.runRemotely(RealJenkinsRuleTest::_getJenkinsUrlFromRemote));
assertThatLocalAndRemoteUrlEquals();
}

private void assertThatLocalAndRemoteUrlEquals() throws Throwable {
assertEquals(rr.getUrl().toExternalForm(), rr.runRemotely(RealJenkinsRuleTest::_getJenkinsUrlFromRemote));
}

@Test public void testThrowsException() {
Expand Down

0 comments on commit 1e79b0d

Please sign in to comment.