Migrate tests to JUnit5 (#10895)
Changelog Drafter / update_draft_release (push) Waiting to run Details
Changelog Drafter / jenkins_io_draft (push) Waiting to run Details
Label conflicting PRs / main (push) Waiting to run Details

This commit is contained in:
Kris Stern 2025-08-03 08:53:53 +08:00 committed by GitHub
commit f036fa8e03
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
76 changed files with 3168 additions and 2386 deletions

View File

@ -442,7 +442,7 @@ THE SOFTWARE.
<artifactId>maven-surefire-plugin</artifactId> <artifactId>maven-surefire-plugin</artifactId>
<!-- Version specified in grandparent POM --> <!-- Version specified in grandparent POM -->
<configuration> <configuration>
<groups>org.jvnet.hudson.test.SmokeTest</groups> <groups>SmokeTest</groups>
</configuration> </configuration>
</plugin> </plugin>
</plugins> </plugins>

View File

@ -25,82 +25,67 @@
package hudson; package hudson;
import static org.junit.Assert.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.Assert.fail; import static org.junit.jupiter.api.Assertions.fail;
import hudson.model.Hudson; import hudson.model.Hudson;
import java.io.File; import java.io.File;
import java.lang.reflect.Method;
import java.net.URL; import java.net.URL;
import java.util.Collection; import java.util.Collection;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.Set; import java.util.Set;
import org.junit.Rule; import org.junit.jupiter.api.Tag;
import org.junit.Test; import org.junit.jupiter.api.Test;
import org.junit.experimental.categories.Category; import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRecipe; import org.jvnet.hudson.test.JenkinsRecipe;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.SmokeTest; import org.jvnet.hudson.test.junit.jupiter.JenkinsSessionExtension;
import org.jvnet.hudson.test.recipes.LocalData; import org.jvnet.hudson.test.recipes.LocalData;
/** /**
* @author Alan Harder * @author Alan Harder
*/ */
@Category(SmokeTest.class) @Tag("SmokeTest")
public class ClassicPluginStrategyTest { class ClassicPluginStrategyTest {
@Rule @RegisterExtension
public JenkinsRule j = new JenkinsRule() { private final JenkinsSessionExtension session = new CustomPluginManagerExtension();
@Override
protected Hudson newHudson() throws Exception {
File home = homeLoader.allocate();
for (JenkinsRecipe.Runner r : recipes) {
r.decorateHome(this, home);
}
LocalPluginManager pluginManager = new LocalPluginManager(home) {
@Override
protected Collection<String> loadBundledPlugins() {
// Overriding so we can force loading of the detached plugins for testing
Set<String> names = new LinkedHashSet<>();
names.addAll(loadPluginsFromWar("/WEB-INF/plugins"));
names.addAll(loadPluginsFromWar("/WEB-INF/detached-plugins"));
return names;
}
};
setPluginManager(pluginManager);
return new Hudson(home, createWebServer2(), pluginManager);
}
};
/** /**
* Test finding resources via DependencyClassLoader. * Test finding resources via DependencyClassLoader.
*/ */
@LocalData @LocalData
@Test @Test
public void testDependencyClassLoader() throws Exception { void testDependencyClassLoader() throws Throwable {
// Test data has: foo3 depends on foo2,foo1; foo2 depends on foo1 session.then(j -> {
// (thus findResources from foo3 can find foo1 resources via 2 dependency paths) // Test data has: foo3 depends on foo2,foo1; foo2 depends on foo1
PluginWrapper p = j.jenkins.getPluginManager().getPlugin("foo3"); // (thus findResources from foo3 can find foo1 resources via 2 dependency paths)
String res; PluginWrapper p = j.jenkins.getPluginManager().getPlugin("foo3");
String res;
// In the current impl, the dependencies are the parent ClassLoader so resources // In the current impl, the dependencies are the parent ClassLoader so resources
// are found there before checking the plugin itself. Adjust the expected results // are found there before checking the plugin itself. Adjust the expected results
// below if this is ever changed to check the plugin first. // below if this is ever changed to check the plugin first.
Enumeration<URL> en = p.classLoader.getResources("test-resource"); Enumeration<URL> en = p.classLoader.getResources("test-resource");
for (int i = 0; en.hasMoreElements(); i++) { for (int i = 0; en.hasMoreElements(); i++) {
res = en.nextElement().toString(); res = en.nextElement().toString();
if (i < 2) if (i < 2)
assertTrue("In current impl, " + res + "should be foo1 or foo2", assertTrue(res.contains("/foo1/") || res.contains("/foo2/"),
res.contains("/foo1/") || res.contains("/foo2/")); "In current impl, " + res + "should be foo1 or foo2");
else else
assertTrue("In current impl, " + res + "should be foo3", res.contains("/foo3/")); assertTrue(res.contains("/foo3/"), "In current impl, " + res + "should be foo3");
} }
res = p.classLoader.getResource("test-resource").toString(); res = p.classLoader.getResource("test-resource").toString();
assertTrue("In current impl, " + res + " should be foo1 or foo2", assertTrue(res.contains("/foo1/") || res.contains("/foo2/"),
res.contains("/foo1/") || res.contains("/foo2/")); "In current impl, " + res + " should be foo1 or foo2");
});
} }
/** /**
@ -110,17 +95,19 @@ public class ClassicPluginStrategyTest {
@LocalData @LocalData
@Issue("JENKINS-18654") @Issue("JENKINS-18654")
@Test @Test
public void testDisabledDependencyClassLoader() throws Exception { void testDisabledDependencyClassLoader() throws Throwable {
PluginWrapper p = j.jenkins.getPluginManager().getPlugin("foo4"); session.then(j -> {
PluginWrapper p = j.jenkins.getPluginManager().getPlugin("foo4");
Enumeration<URL> en = p.classLoader.getResources("test-resource"); Enumeration<URL> en = p.classLoader.getResources("test-resource");
for (int i = 0; en.hasMoreElements(); i++) { for (int i = 0; en.hasMoreElements(); i++) {
String res = en.nextElement().toString(); String res = en.nextElement().toString();
if (i == 0) if (i == 0)
assertTrue("expected foo4, found " + res, res.contains("/foo4/")); assertTrue(res.contains("/foo4/"), "expected foo4, found " + res);
else else
fail("disabled dependency should not be included"); fail("disabled dependency should not be included");
} }
});
} }
/** /**
@ -130,12 +117,77 @@ public class ClassicPluginStrategyTest {
@LocalData @LocalData
@Issue("JENKINS-27289") @Issue("JENKINS-27289")
@Test @Test
public void testMaskResourceClassLoader() throws Exception { void testMaskResourceClassLoader() throws Throwable {
PluginWrapper pw = j.jenkins.getPluginManager().getPlugin("foo1"); session.then(j -> {
Class<?> clazz = pw.classLoader.loadClass("org.apache.http.impl.io.SocketInputBuffer"); PluginWrapper pw = j.jenkins.getPluginManager().getPlugin("foo1");
ClassLoader cl = clazz.getClassLoader(); Class<?> clazz = pw.classLoader.loadClass("org.apache.http.impl.io.SocketInputBuffer");
URL url = cl.getResource("org/apache/http/impl/io/SocketInputBuffer.class"); ClassLoader cl = clazz.getClassLoader();
assertNotNull(url); URL url = cl.getResource("org/apache/http/impl/io/SocketInputBuffer.class");
assertTrue("expected to find the class from foo1 plugin", url.toString().contains("plugins/foo1")); assertNotNull(url);
assertTrue(url.toString().contains("plugins/foo1"), "expected to find the class from foo1 plugin");
});
}
private static final class CustomPluginManagerExtension extends JenkinsSessionExtension {
private int port;
private Description description;
@Override
public void beforeEach(ExtensionContext context) {
super.beforeEach(context);
description = Description.createTestDescription(
context.getTestClass().map(Class::getName).orElse(null),
context.getTestMethod().map(Method::getName).orElse(null),
context.getTestMethod().map(Method::getAnnotations).orElse(null));
}
@Override
public void then(Step s) throws Throwable {
CustomJenkinsRule r = new CustomJenkinsRule(getHome(), port);
r.apply(
new Statement() {
@Override
public void evaluate() throws Throwable {
port = r.getPort();
s.run(r);
}
},
description
).evaluate();
}
private static final class CustomJenkinsRule extends JenkinsRule {
CustomJenkinsRule(File home, int port) {
with(() -> home);
localPort = port;
}
int getPort() {
return localPort;
}
@Override
protected Hudson newHudson() throws Exception {
File home = homeLoader.allocate();
for (JenkinsRecipe.Runner r : recipes) {
r.decorateHome(this, home);
}
LocalPluginManager pluginManager = new LocalPluginManager(home) {
@Override
protected Collection<String> loadBundledPlugins() {
// Overriding so we can force loading of the detached plugins for testing
Set<String> names = new LinkedHashSet<>();
names.addAll(loadPluginsFromWar("/WEB-INF/plugins"));
names.addAll(loadPluginsFromWar("/WEB-INF/detached-plugins"));
return names;
}
};
setPluginManager(pluginManager);
return new Hudson(home, createWebServer2(), pluginManager);
}
}
} }
} }

View File

@ -29,26 +29,29 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import jakarta.servlet.ServletContext; import jakarta.servlet.ServletContext;
import java.io.File; import java.io.File;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import jenkins.model.Jenkins; import jenkins.model.Jenkins;
import org.junit.Rule; import org.junit.jupiter.api.Test;
import org.junit.Test; import org.junit.jupiter.api.extension.RegisterExtension;
import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRecipe; import org.jvnet.hudson.test.JenkinsRecipe;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.junit.jupiter.JenkinsSessionExtension;
import org.jvnet.hudson.test.recipes.WithPlugin; import org.jvnet.hudson.test.recipes.WithPlugin;
/** /**
* Tests for the use of a custom plugin manager in custom wars. * Tests for the use of a custom plugin manager in custom wars.
*/ */
public class CustomPluginManagerTest { class CustomPluginManagerTest {
@Rule public final JenkinsRule r = new JenkinsRule();
@RegisterExtension
private final JenkinsSessionExtension session = new JenkinsSessionExtension();
// TODO: Move to jenkins-test-harness // TODO: Move to jenkins-test-harness
@JenkinsRecipe(WithCustomLocalPluginManager.RuleRunnerImpl.class) @JenkinsRecipe(WithCustomLocalPluginManager.RuleRunnerImpl.class)
@ -65,7 +68,6 @@ public class CustomPluginManagerTest {
jenkinsRule.useLocalPluginManager = true; jenkinsRule.useLocalPluginManager = true;
oldValue = System.getProperty(PluginManager.CUSTOM_PLUGIN_MANAGER); oldValue = System.getProperty(PluginManager.CUSTOM_PLUGIN_MANAGER);
System.setProperty(PluginManager.CUSTOM_PLUGIN_MANAGER, recipe.value().getName()); System.setProperty(PluginManager.CUSTOM_PLUGIN_MANAGER, recipe.value().getName());
} }
@Override @Override
@ -79,9 +81,11 @@ public class CustomPluginManagerTest {
} }
} }
private void check(Class<? extends CustomPluginManager> klass) { private void check(Class<? extends CustomPluginManager> klass) throws Throwable {
assertTrue("Correct plugin manager installed", klass.isAssignableFrom(r.getPluginManager().getClass())); session.then(r -> {
assertNotNull("Plugin 'htmlpublisher' installed", r.jenkins.getPlugin("htmlpublisher")); assertTrue(klass.isAssignableFrom(r.getPluginManager().getClass()), "Correct plugin manager installed");
assertNotNull(r.jenkins.getPlugin("htmlpublisher"), "Plugin 'htmlpublisher' installed");
});
} }
// An interface not to override every constructor. // An interface not to override every constructor.
@ -91,11 +95,13 @@ public class CustomPluginManagerTest {
@Issue("JENKINS-34681") @Issue("JENKINS-34681")
@WithPlugin("htmlpublisher.jpi") @WithPlugin("htmlpublisher.jpi")
@WithCustomLocalPluginManager(CustomPluginManager1.class) @WithCustomLocalPluginManager(CustomPluginManager1.class)
@Test public void customPluginManager1() { @Test
void customPluginManager1() throws Throwable {
check(CustomPluginManager1.class); check(CustomPluginManager1.class);
} }
public static class CustomPluginManager1 extends LocalPluginManager implements CustomPluginManager { public static class CustomPluginManager1 extends LocalPluginManager implements CustomPluginManager {
@SuppressWarnings("checkstyle:redundantmodifier")
public CustomPluginManager1(Jenkins jenkins) { public CustomPluginManager1(Jenkins jenkins) {
super(jenkins); super(jenkins);
} }
@ -104,11 +110,13 @@ public class CustomPluginManagerTest {
@Issue("JENKINS-34681") @Issue("JENKINS-34681")
@WithPlugin("htmlpublisher.jpi") @WithPlugin("htmlpublisher.jpi")
@WithCustomLocalPluginManager(CustomPluginManager2.class) @WithCustomLocalPluginManager(CustomPluginManager2.class)
@Test public void customPluginManager2() { @Test
void customPluginManager2() throws Throwable {
check(CustomPluginManager2.class); check(CustomPluginManager2.class);
} }
public static class CustomPluginManager2 extends LocalPluginManager implements CustomPluginManager { public static class CustomPluginManager2 extends LocalPluginManager implements CustomPluginManager {
@SuppressWarnings("checkstyle:redundantmodifier")
public CustomPluginManager2(ServletContext ctx, File root) { public CustomPluginManager2(ServletContext ctx, File root) {
super(ctx, root); super(ctx, root);
} }
@ -117,11 +125,13 @@ public class CustomPluginManagerTest {
@Issue("JENKINS-34681") @Issue("JENKINS-34681")
@WithPlugin("htmlpublisher.jpi") @WithPlugin("htmlpublisher.jpi")
@WithCustomLocalPluginManager(CustomPluginManager3.class) @WithCustomLocalPluginManager(CustomPluginManager3.class)
@Test public void customPluginManager3() { @Test
void customPluginManager3() throws Throwable {
check(CustomPluginManager3.class); check(CustomPluginManager3.class);
} }
public static class CustomPluginManager3 extends LocalPluginManager implements CustomPluginManager { public static class CustomPluginManager3 extends LocalPluginManager implements CustomPluginManager {
@SuppressWarnings("checkstyle:redundantmodifier")
public CustomPluginManager3(File root) { public CustomPluginManager3(File root) {
super(root); super(root);
} }
@ -130,11 +140,15 @@ public class CustomPluginManagerTest {
@Issue("JENKINS-34681") @Issue("JENKINS-34681")
@WithPlugin("htmlpublisher.jpi") @WithPlugin("htmlpublisher.jpi")
@WithCustomLocalPluginManager(BadCustomPluginManager.class) @WithCustomLocalPluginManager(BadCustomPluginManager.class)
@Test public void badCustomPluginManager() { @Test
assertThat("Custom plugin manager not installed", r.getPluginManager(), not(instanceOf(CustomPluginManager.class))); void badCustomPluginManager() throws Throwable {
session.then(r ->
assertThat("Custom plugin manager not installed", r.getPluginManager(), not(instanceOf(CustomPluginManager.class)))
);
} }
public static class BadCustomPluginManager extends LocalPluginManager implements CustomPluginManager { public static class BadCustomPluginManager extends LocalPluginManager implements CustomPluginManager {
@SuppressWarnings("checkstyle:redundantmodifier")
public BadCustomPluginManager(File root, ServletContext ctx) { public BadCustomPluginManager(File root, ServletContext ctx) {
super(ctx, root); super(ctx, root);
} }

View File

@ -24,37 +24,40 @@
package hudson; package hudson;
import static org.junit.jupiter.api.Assertions.assertEquals;
import jenkins.model.TransientActionFactory; import jenkins.model.TransientActionFactory;
import org.junit.Assert; import org.junit.jupiter.api.Test;
import org.junit.Rule; import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.Test; import org.jvnet.hudson.test.junit.jupiter.JenkinsSessionExtension;
import org.jvnet.hudson.test.JenkinsRule;
/** /**
* @author <a href="mailto:tom.fennelly@gmail.com">tom.fennelly@gmail.com</a> * @author <a href="mailto:tom.fennelly@gmail.com">tom.fennelly@gmail.com</a>
*/ */
public class ExtensionListListenerTest { class ExtensionListListenerTest {
@Rule @RegisterExtension
public JenkinsRule r = PluginManagerUtil.newJenkinsRule(); public JenkinsSessionExtension session = PluginManagerUtil.newJenkinsSessionExtension();
@Test @Test
public void test_onChange() throws Exception { void test_onChange() throws Throwable {
ExtensionList<TransientActionFactory> extensionList = ExtensionList.lookup(TransientActionFactory.class); session.then(r -> {
ExtensionList<TransientActionFactory> extensionList = ExtensionList.lookup(TransientActionFactory.class);
// force ExtensionList.ensureLoaded, otherwise the refresh will be ignored because // force ExtensionList.ensureLoaded, otherwise the refresh will be ignored because
// the extension list will not be initialised. // the extension list will not be initialised.
extensionList.size(); extensionList.size();
// Add the listener // Add the listener
MyExtensionListListener listListener = new MyExtensionListListener(); MyExtensionListListener listListener = new MyExtensionListListener();
extensionList.addListener(listListener); extensionList.addListener(listListener);
// magiext.hpi has a TransientActionFactory @Extension impl in it. The loading of that // magiext.hpi has a TransientActionFactory @Extension impl in it. The loading of that
// plugin should trigger onChange in the MyExtensionListListener instance. // plugin should trigger onChange in the MyExtensionListListener instance.
PluginManagerUtil.dynamicLoad("magicext.hpi", r.jenkins); PluginManagerUtil.dynamicLoad("magicext.hpi", r.jenkins);
Assert.assertEquals(1, listListener.onChangeCallCount); assertEquals(1, listListener.onChangeCallCount);
});
} }
private static class MyExtensionListListener extends ExtensionListListener { private static class MyExtensionListListener extends ExtensionListListener {

View File

@ -3,7 +3,7 @@ package hudson;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.hasSize;
import static org.junit.Assert.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import java.util.Collection; import java.util.Collection;
import jenkins.plugins.dependee.Dependee; import jenkins.plugins.dependee.Dependee;
@ -12,16 +12,17 @@ import jenkins.plugins.dynamic_extension_loading.CustomExtensionLoadedViaConstru
import jenkins.plugins.dynamic_extension_loading.CustomExtensionLoadedViaListener; import jenkins.plugins.dynamic_extension_loading.CustomExtensionLoadedViaListener;
import jenkins.plugins.dynamic_extension_loading.CustomPeriodicWork; import jenkins.plugins.dynamic_extension_loading.CustomPeriodicWork;
import jenkins.plugins.optional_depender.OptionalDepender; import jenkins.plugins.optional_depender.OptionalDepender;
import org.junit.Rule; import org.junit.jupiter.api.Test;
import org.junit.Test; import org.junit.jupiter.api.extension.RegisterExtension;
import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.RealJenkinsRule; import org.jvnet.hudson.test.junit.jupiter.RealJenkinsExtension;
import org.jvnet.hudson.test.RealJenkinsRule.SyntheticPlugin; import org.jvnet.hudson.test.junit.jupiter.RealJenkinsExtension.SyntheticPlugin;
public class ExtensionListRjrTest { class ExtensionListRjrTest {
@Rule
public RealJenkinsRule rjr = new RealJenkinsRule(); @RegisterExtension
public RealJenkinsExtension rjr = new RealJenkinsExtension();
/** /**
* Check that dynamically loading a plugin does not lead to extension lists with duplicate entries. * Check that dynamically loading a plugin does not lead to extension lists with duplicate entries.
@ -30,7 +31,7 @@ public class ExtensionListRjrTest {
*/ */
@Test @Test
@Issue("JENKINS-75232") @Issue("JENKINS-75232")
public void checkDynamicLoad_singleRegistration() throws Throwable { void checkDynamicLoad_singleRegistration() throws Throwable {
var pluginJpi = rjr.createSyntheticPlugin(new SyntheticPlugin(CustomPeriodicWork.class.getPackage()) var pluginJpi = rjr.createSyntheticPlugin(new SyntheticPlugin(CustomPeriodicWork.class.getPackage())
.shortName("dynamic-extension-loading") .shortName("dynamic-extension-loading")
.header("Plugin-Dependencies", "variant:0")); .header("Plugin-Dependencies", "variant:0"));
@ -57,8 +58,8 @@ public class ExtensionListRjrTest {
} }
@Test @Test
@Issue({ "JENKINS-50336", "JENKINS-60449" }) @Issue({"JENKINS-50336", "JENKINS-60449"})
public void installDependedOptionalPluginWithoutRestart() throws Throwable { void installDependedOptionalPluginWithoutRestart() throws Throwable {
var optionalDependerJpi = rjr.createSyntheticPlugin(new SyntheticPlugin(OptionalDepender.class.getPackage()) var optionalDependerJpi = rjr.createSyntheticPlugin(new SyntheticPlugin(OptionalDepender.class.getPackage())
.header("Plugin-Dependencies", "variant:0,dependee:0;resolution:=optional")); .header("Plugin-Dependencies", "variant:0,dependee:0;resolution:=optional"));
var dependeeJpi = rjr.createSyntheticPlugin(new SyntheticPlugin(Dependee.class.getPackage()).shortName("dependee")); var dependeeJpi = rjr.createSyntheticPlugin(new SyntheticPlugin(Dependee.class.getPackage()).shortName("dependee"));

View File

@ -24,7 +24,13 @@
package hudson; package hudson;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
@ -37,116 +43,99 @@ import org.htmlunit.html.HtmlElementUtil;
import org.htmlunit.html.HtmlInput; import org.htmlunit.html.HtmlInput;
import org.htmlunit.html.HtmlPage; import org.htmlunit.html.HtmlPage;
import org.htmlunit.html.HtmlTableRow; import org.htmlunit.html.HtmlTableRow;
import org.junit.Assert; import org.junit.jupiter.api.Test;
import org.junit.Rule; import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.Test; import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.TestPluginManager; import org.jvnet.hudson.test.TestPluginManager;
import org.jvnet.hudson.test.junit.jupiter.JenkinsSessionExtension;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
/** /**
* @author <a href="mailto:tom.fennelly@gmail.com">tom.fennelly@gmail.com</a> * @author <a href="mailto:tom.fennelly@gmail.com">tom.fennelly@gmail.com</a>
*/ */
public class PluginManagerInstalledGUITest { class PluginManagerInstalledGUITest {
@Rule @RegisterExtension
public JenkinsRule jenkinsRule = new JenkinsRule() { private final JenkinsSessionExtension session = new CustomPluginManagerExtension();
@Override
public PluginManager getPluginManager() {
try {
return new TestPluginManager() {
@Override
protected Collection<String> loadBundledPlugins() throws Exception {
try {
return super.loadBundledPlugins();
} finally {
copyBundledPlugin(PluginManagerInstalledGUITest.class.getResource("/WEB-INF/detached-plugins/matrix-auth.hpi"), "matrix-auth.jpi"); // cannot use installDetachedPlugin at this point
copyBundledPlugin(PluginManagerInstalledGUITest.class.getResource("/plugins/dependee-0.0.2.hpi"), "dependee.jpi");
copyBundledPlugin(PluginManagerInstalledGUITest.class.getResource("/plugins/depender-0.0.2.hpi"), "depender.jpi");
copyBundledPlugin(PluginManagerInstalledGUITest.class.getResource("/plugins/mandatory-depender-0.0.2.hpi"), "mandatory-depender.jpi");
}
}
};
} catch (IOException e) {
Assert.fail(e.getMessage());
return null;
}
}
};
@Issue("JENKINS-33843") @Issue("JENKINS-33843")
@Test @Test
public void test_enable_disable_uninstall() throws IOException, SAXException { void test_enable_disable_uninstall() throws Throwable {
InstalledPlugins installedPlugins = new InstalledPlugins(); session.then(j -> {
InstalledPlugins installedPlugins = new InstalledPlugins(j);
InstalledPlugin matrixAuthPlugin = installedPlugins.get("matrix-auth"); InstalledPlugin matrixAuthPlugin = installedPlugins.get("matrix-auth");
InstalledPlugin dependeePlugin = installedPlugins.get("dependee"); InstalledPlugin dependeePlugin = installedPlugins.get("dependee");
InstalledPlugin dependerPlugin = installedPlugins.get("depender"); InstalledPlugin dependerPlugin = installedPlugins.get("depender");
InstalledPlugin mandatoryDependerPlugin = installedPlugins.get("mandatory-depender"); InstalledPlugin mandatoryDependerPlugin = installedPlugins.get("mandatory-depender");
// As a detached plugin, it is an optional dependency of others built against a newer baseline. // As a detached plugin, it is an optional dependency of others built against a newer baseline.
matrixAuthPlugin.assertHasNoDependents(); matrixAuthPlugin.assertHasNoDependents();
// Has a mandatory dependency: // Has a mandatory dependency:
dependeePlugin.assertHasDependents(); dependeePlugin.assertHasDependents();
// Leaf plugins: // Leaf plugins:
dependerPlugin.assertHasNoDependents(); dependerPlugin.assertHasNoDependents();
mandatoryDependerPlugin.assertHasNoDependents(); mandatoryDependerPlugin.assertHasNoDependents();
// This plugin should be enabled and it should be possible to disable it // This plugin should be enabled and it should be possible to disable it
// because no other plugins depend on it. // because no other plugins depend on it.
mandatoryDependerPlugin.assertEnabled(); mandatoryDependerPlugin.assertEnabled();
mandatoryDependerPlugin.assertEnabledStateChangeable(); mandatoryDependerPlugin.assertEnabledStateChangeable();
mandatoryDependerPlugin.assertUninstallable(); mandatoryDependerPlugin.assertUninstallable();
// This plugin should be enabled, but it should not be possible to disable or uninstall it // This plugin should be enabled, but it should not be possible to disable or uninstall it
// because another plugin depends on it. // because another plugin depends on it.
dependeePlugin.assertEnabled(); dependeePlugin.assertEnabled();
dependeePlugin.assertEnabledStateNotChangeable(); dependeePlugin.assertEnabledStateNotChangeable();
dependeePlugin.assertNotUninstallable(); dependeePlugin.assertNotUninstallable();
// Disable one plugin // Disable one plugin
mandatoryDependerPlugin.clickEnabledWidget(); mandatoryDependerPlugin.clickEnabledWidget();
// Now that plugin should be disabled, but it should be possible to re-enable it // Now that plugin should be disabled, but it should be possible to re-enable it
// and it should still be uninstallable. // and it should still be uninstallable.
mandatoryDependerPlugin.assertNotEnabled(); // this is different to earlier mandatoryDependerPlugin.assertNotEnabled(); // this is different to earlier
mandatoryDependerPlugin.assertEnabledStateChangeable(); mandatoryDependerPlugin.assertEnabledStateChangeable();
mandatoryDependerPlugin.assertUninstallable(); mandatoryDependerPlugin.assertUninstallable();
// The dependee plugin should still be enabled, but it should now be possible to disable it because // The dependee plugin should still be enabled, but it should now be possible to disable it because
// the mandatory depender plugin is no longer enabled. Should still not be possible to uninstall it. // the mandatory depender plugin is no longer enabled. Should still not be possible to uninstall it.
// Note that the depender plugin does not block its disablement. // Note that the depender plugin does not block its disablement.
dependeePlugin.assertEnabled(); dependeePlugin.assertEnabled();
dependeePlugin.assertEnabledStateChangeable(); // this is different to earlier dependeePlugin.assertEnabledStateChangeable(); // this is different to earlier
dependeePlugin.assertNotUninstallable(); dependeePlugin.assertNotUninstallable();
dependerPlugin.assertEnabled(); dependerPlugin.assertEnabled();
// Disable the dependee plugin // Disable the dependee plugin
dependeePlugin.clickEnabledWidget(); dependeePlugin.clickEnabledWidget();
// Now it should NOT be possible to change the enable state of the depender plugin because one // Now it should NOT be possible to change the enable state of the depender plugin because one
// of the plugins it depends on is not enabled. // of the plugins it depends on is not enabled.
mandatoryDependerPlugin.assertNotEnabled(); mandatoryDependerPlugin.assertNotEnabled();
mandatoryDependerPlugin.assertEnabledStateNotChangeable(); // this is different to earlier mandatoryDependerPlugin.assertEnabledStateNotChangeable(); // this is different to earlier
mandatoryDependerPlugin.assertUninstallable(); mandatoryDependerPlugin.assertUninstallable();
dependerPlugin.assertEnabled(); dependerPlugin.assertEnabled();
// You can disable a detached plugin if there is no explicit dependency on it. // You can disable a detached plugin if there is no explicit dependency on it.
matrixAuthPlugin.assertEnabled(); matrixAuthPlugin.assertEnabled();
matrixAuthPlugin.assertEnabledStateChangeable(); matrixAuthPlugin.assertEnabledStateChangeable();
matrixAuthPlugin.assertUninstallable(); matrixAuthPlugin.assertUninstallable();
matrixAuthPlugin.clickEnabledWidget(); matrixAuthPlugin.clickEnabledWidget();
matrixAuthPlugin.assertNotEnabled(); matrixAuthPlugin.assertNotEnabled();
matrixAuthPlugin.assertEnabledStateChangeable(); matrixAuthPlugin.assertEnabledStateChangeable();
matrixAuthPlugin.assertUninstallable(); matrixAuthPlugin.assertUninstallable();
});
} }
private class InstalledPlugins { private static class InstalledPlugins {
private final List<InstalledPlugin> installedPlugins; private final List<InstalledPlugin> installedPlugins;
private InstalledPlugins() throws IOException, SAXException { private InstalledPlugins(JenkinsRule jenkinsRule) throws IOException, SAXException {
JenkinsRule.WebClient webClient = jenkinsRule.createWebClient(); JenkinsRule.WebClient webClient = jenkinsRule.createWebClient();
HtmlPage installedPage = webClient.goTo("pluginManager/installed"); HtmlPage installedPage = webClient.goTo("pluginManager/installed");
final boolean healthScoresAvailable = jenkinsRule.jenkins.getUpdateCenter().isHealthScoresAvailable(); final boolean healthScoresAvailable = jenkinsRule.jenkins.getUpdateCenter().isHealthScoresAvailable();
@ -170,13 +159,13 @@ public class PluginManagerInstalledGUITest {
return plugin; return plugin;
} }
} }
Assert.fail("No pluginManager/installed row for plugin " + pluginId); fail("No pluginManager/installed row for plugin " + pluginId);
return null; return null;
} }
} }
private class InstalledPlugin { private static class InstalledPlugin {
private final HtmlTableRow pluginRow; private final HtmlTableRow pluginRow;
private final boolean hasHealth; private final boolean hasHealth;
@ -201,12 +190,12 @@ public class PluginManagerInstalledGUITest {
public void assertEnabled() { public void assertEnabled() {
HtmlInput enableWidget = getEnableWidget(); HtmlInput enableWidget = getEnableWidget();
Assert.assertTrue("Plugin '" + getId() + "' is expected to be enabled.", enableWidget.isChecked()); assertTrue(enableWidget.isChecked(), "Plugin '" + getId() + "' is expected to be enabled.");
} }
public void assertNotEnabled() { public void assertNotEnabled() {
HtmlInput enableWidget = getEnableWidget(); HtmlInput enableWidget = getEnableWidget();
Assert.assertFalse("Plugin '" + getId() + "' is not expected to be enabled.", enableWidget.isChecked()); assertFalse(enableWidget.isChecked(), "Plugin '" + getId() + "' is not expected to be enabled.");
} }
public void clickEnabledWidget() throws IOException { public void clickEnabledWidget() throws IOException {
@ -222,7 +211,7 @@ public class PluginManagerInstalledGUITest {
return; return;
} }
Assert.fail("The enable/disable state of plugin '" + getId() + "' cannot be changed."); fail("The enable/disable state of plugin '" + getId() + "' cannot be changed.");
} }
public void assertEnabledStateNotChangeable() { public void assertEnabledStateNotChangeable() {
@ -233,23 +222,23 @@ public class PluginManagerInstalledGUITest {
return; return;
} }
Assert.fail("The enable/disable state of plugin '" + getId() + "' cannot be changed."); fail("The enable/disable state of plugin '" + getId() + "' cannot be changed.");
} }
public void assertUninstallable() { public void assertUninstallable() {
Assert.assertFalse("Plugin '" + getId() + "' cannot be uninstalled.", hasDependents()); assertFalse(hasDependents(), "Plugin '" + getId() + "' cannot be uninstalled.");
} }
public void assertNotUninstallable() { public void assertNotUninstallable() {
Assert.assertTrue("Plugin '" + getId() + "' can be uninstalled.", hasDependents()); assertTrue(hasDependents(), "Plugin '" + getId() + "' can be uninstalled.");
} }
public void assertHasDependents() { public void assertHasDependents() {
Assert.assertTrue("Plugin '" + getId() + "' is expected to have dependents.", hasDependents()); assertTrue(hasDependents(), "Plugin '" + getId() + "' is expected to have dependents.");
} }
public void assertHasNoDependents() { public void assertHasNoDependents() {
Assert.assertFalse("Plugin '" + getId() + "' is expected to have no dependents.", hasDependents()); assertFalse(hasDependents(), "Plugin '" + getId() + "' is expected to have no dependents.");
} }
private boolean hasClassName(String className) { private boolean hasClassName(String className) {
@ -270,4 +259,67 @@ public class PluginManagerInstalledGUITest {
return hasClassName("has-dependents"); return hasClassName("has-dependents");
} }
} }
private static final class CustomPluginManagerExtension extends JenkinsSessionExtension {
private int port;
private Description description;
@Override
public void beforeEach(ExtensionContext context) {
super.beforeEach(context);
description = Description.createTestDescription(
context.getTestClass().map(Class::getName).orElse(null),
context.getTestMethod().map(Method::getName).orElse(null),
context.getTestMethod().map(Method::getAnnotations).orElse(null));
}
@Override
public void then(Step s) throws Throwable {
CustomJenkinsRule r = new CustomJenkinsRule(getHome(), port);
r.apply(
new Statement() {
@Override
public void evaluate() throws Throwable {
port = r.getPort();
s.run(r);
}
},
description
).evaluate();
}
private static final class CustomJenkinsRule extends JenkinsRule {
CustomJenkinsRule(File home, int port) {
with(() -> home);
localPort = port;
}
int getPort() {
return localPort;
}
@Override
public PluginManager getPluginManager() {
try {
return new TestPluginManager() {
@Override
protected Collection<String> loadBundledPlugins() throws Exception {
try {
return super.loadBundledPlugins();
} finally {
copyBundledPlugin(PluginManagerInstalledGUITest.class.getResource("/WEB-INF/detached-plugins/matrix-auth.hpi"), "matrix-auth.jpi"); // cannot use installDetachedPlugin at this point
copyBundledPlugin(PluginManagerInstalledGUITest.class.getResource("/plugins/dependee-0.0.2.hpi"), "dependee.jpi");
copyBundledPlugin(PluginManagerInstalledGUITest.class.getResource("/plugins/depender-0.0.2.hpi"), "depender.jpi");
copyBundledPlugin(PluginManagerInstalledGUITest.class.getResource("/plugins/mandatory-depender-0.0.2.hpi"), "mandatory-depender.jpi");
}
}
};
} catch (IOException e) {
return fail(e.getMessage());
}
}
}
}
} }

File diff suppressed because it is too large Load Diff

View File

@ -26,36 +26,63 @@ package hudson;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URL; import java.net.URL;
import jenkins.RestartRequiredException; import jenkins.RestartRequiredException;
import jenkins.model.Jenkins; import jenkins.model.Jenkins;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.htmlunit.html.DomElement; import org.htmlunit.html.DomElement;
import org.htmlunit.html.HtmlPage; import org.htmlunit.html.HtmlPage;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.runner.Description; import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.RestartableJenkinsRule; import org.jvnet.hudson.test.junit.jupiter.JenkinsSessionExtension;
/** /**
* @author <a href="mailto:tom.fennelly@gmail.com">tom.fennelly@gmail.com</a> * @author <a href="mailto:tom.fennelly@gmail.com">tom.fennelly@gmail.com</a>
*/ */
public class PluginManagerUtil { public class PluginManagerUtil {
public static JenkinsRule newJenkinsRule() { public static JenkinsSessionExtension newJenkinsSessionExtension() {
return new JenkinsRule() { return new JenkinsSessionExtension() {
@Override private int port;
public void before() throws Throwable { private Description description;
setPluginManager(null);
super.before();
}
};
}
public static RestartableJenkinsRule newRestartableJenkinsRule() {
return new RestartableJenkinsRule() {
@Override @Override
public JenkinsRule createJenkinsRule(Description description) { public void beforeEach(ExtensionContext context) {
return newJenkinsRule(); super.beforeEach(context);
description = Description.createTestDescription(
context.getTestClass().map(Class::getName).orElse(null),
context.getTestMethod().map(Method::getName).orElse(null),
context.getTestMethod().map(Method::getAnnotations).orElse(null));
}
@Override
public void then(Step s) throws Throwable {
CustomJenkinsRule r = new CustomJenkinsRule(getHome(), port);
r.apply(
new Statement() {
@Override
public void evaluate() throws Throwable {
port = r.getPort();
s.run(r);
}
},
description
).evaluate();
}
private static final class CustomJenkinsRule extends JenkinsRule {
CustomJenkinsRule(File home, int port) {
setPluginManager(null);
with(() -> home);
localPort = port;
}
int getPort() {
return localPort;
}
} }
}; };
} }

View File

@ -24,22 +24,24 @@
package hudson; package hudson;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.Assert.assertNull; import static org.junit.jupiter.api.Assertions.assertNull;
import hudson.util.Secret; import hudson.util.Secret;
import java.io.File; import java.io.File;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.junit.Rule; import org.junit.jupiter.api.Test;
import org.junit.Test; import org.junit.jupiter.api.extension.RegisterExtension;
import org.jvnet.hudson.test.JenkinsSessionRule; import org.jvnet.hudson.test.junit.jupiter.JenkinsSessionExtension;
public final class ProxyConfigurationManagerGUITest { class ProxyConfigurationManagerGUITest {
@Rule public JenkinsSessionRule rr = new JenkinsSessionRule(); @RegisterExtension
public JenkinsSessionExtension rr = new JenkinsSessionExtension();
@Test public void configRoundtrip() throws Throwable { @Test
void configRoundtrip() throws Throwable {
rr.then(r -> { rr.then(r -> {
assertNull(r.jenkins.proxy); assertNull(r.jenkins.proxy);
r.jenkins.proxy = new ProxyConfiguration("proxy.mycorp", 80); r.jenkins.proxy = new ProxyConfiguration("proxy.mycorp", 80);

View File

@ -24,8 +24,8 @@
package hudson.bugs; package hudson.bugs;
import static org.junit.Assert.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import hudson.model.Slave; import hudson.model.Slave;
import hudson.model.User; import hudson.model.User;
@ -34,6 +34,7 @@ import java.io.File;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.URL; import java.net.URL;
import java.util.Locale; import java.util.Locale;
import jenkins.model.Jenkins;
import jenkins.security.s2m.AdminWhitelistRule; import jenkins.security.s2m.AdminWhitelistRule;
import org.dom4j.Document; import org.dom4j.Document;
import org.dom4j.Element; import org.dom4j.Element;
@ -41,32 +42,42 @@ import org.dom4j.io.DOMReader;
import org.htmlunit.Page; import org.htmlunit.Page;
import org.htmlunit.html.HtmlPage; import org.htmlunit.html.HtmlPage;
import org.htmlunit.xml.XmlPage; import org.htmlunit.xml.XmlPage;
import org.junit.Rule; import org.junit.jupiter.api.BeforeEach;
import org.junit.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.jvnet.hudson.test.Email; import org.jvnet.hudson.test.Email;
import org.jvnet.hudson.test.InboundAgentRule;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.recipes.PresetData; import org.jvnet.hudson.test.MockAuthorizationStrategy;
import org.jvnet.hudson.test.recipes.PresetData.DataSet; import org.jvnet.hudson.test.junit.jupiter.InboundAgentExtension;
import org.jvnet.hudson.test.junit.jupiter.WithJenkins;
/** /**
* Makes sure that the jars that web start needs are readable, even when the anonymous user doesn't have any read access. * Makes sure that the jars that web start needs are readable, even when the anonymous user doesn't have any read access.
* *
* @author Kohsuke Kawaguchi * @author Kohsuke Kawaguchi
*/ */
public class JnlpAccessWithSecuredHudsonTest { @WithJenkins
class JnlpAccessWithSecuredHudsonTest {
@Rule @RegisterExtension
public JenkinsRule r = new JenkinsRule(); private final InboundAgentExtension inboundAgents = new InboundAgentExtension();
@Rule private JenkinsRule r;
public InboundAgentRule inboundAgents = new InboundAgentRule();
@BeforeEach
void setUp(JenkinsRule rule) {
r = rule;
}
@PresetData(DataSet.NO_ANONYMOUS_READACCESS)
@Email("http://markmail.org/message/on4wkjdaldwi2atx") @Email("http://markmail.org/message/on4wkjdaldwi2atx")
@Test @Test
public void anonymousCanAlwaysLoadJARs() throws Exception { void anonymousCanAlwaysLoadJARs() throws Exception {
inboundAgents.createAgent(r, InboundAgentRule.Options.newBuilder().name("test").skipStart().build()); JenkinsRule.DummySecurityRealm realm = r.createDummySecurityRealm();
r.jenkins.setSecurityRealm(realm);
r.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy()
.grant(Jenkins.ADMINISTER).everywhere().toAuthenticated());
inboundAgents.createAgent(r, InboundAgentExtension.Options.newBuilder().name("test").skipStart().build());
JenkinsRule.WebClient wc = r.createWebClient(); JenkinsRule.WebClient wc = r.createWebClient();
HtmlPage p = wc.withBasicApiToken(User.getById("alice", true)).goTo("computer/test/"); HtmlPage p = wc.withBasicApiToken(User.getById("alice", true)).goTo("computer/test/");
@ -87,21 +98,30 @@ public class JnlpAccessWithSecuredHudsonTest {
} }
} }
@PresetData(DataSet.ANONYMOUS_READONLY)
@Test @Test
public void anonymousCannotGetSecrets() throws Exception { void anonymousCannotGetSecrets() throws Exception {
inboundAgents.createAgent(r, InboundAgentRule.Options.newBuilder().name("test").skipStart().build()); JenkinsRule.DummySecurityRealm realm = r.createDummySecurityRealm();
r.jenkins.setSecurityRealm(realm);
r.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy()
.grant(Jenkins.READ).everywhere().toEveryone()
.grant(Jenkins.ADMINISTER).everywhere().toAuthenticated());
inboundAgents.createAgent(r, InboundAgentExtension.Options.newBuilder().name("test").skipStart().build());
r.createWebClient().assertFails("computer/test/jenkins-agent.jnlp", HttpURLConnection.HTTP_FORBIDDEN); r.createWebClient().assertFails("computer/test/jenkins-agent.jnlp", HttpURLConnection.HTTP_FORBIDDEN);
} }
@PresetData(DataSet.NO_ANONYMOUS_READACCESS)
@Test @Test
public void serviceUsingDirectSecret() throws Exception { void serviceUsingDirectSecret() throws Exception {
Slave slave = inboundAgents.createAgent(r, InboundAgentRule.Options.newBuilder().name("test").secret().build()); JenkinsRule.DummySecurityRealm realm = r.createDummySecurityRealm();
r.jenkins.setSecurityRealm(realm);
r.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy()
.grant(Jenkins.ADMINISTER).everywhere().toAuthenticated());
Slave slave = inboundAgents.createAgent(r, InboundAgentExtension.Options.newBuilder().name("test").build());
try { try {
r.createWebClient().goTo("computer/test/jenkins-agent.jnlp?encrypt=true", "application/octet-stream"); r.createWebClient().goTo("computer/test/jenkins-agent.jnlp?encrypt=true", "application/octet-stream");
Channel channel = slave.getComputer().getChannel(); Channel channel = slave.getComputer().getChannel();
assertFalse("SECURITY-206", channel.isRemoteClassLoadingAllowed()); assertFalse(channel.isRemoteClassLoadingAllowed(), "SECURITY-206");
r.jenkins.getExtensionList(AdminWhitelistRule.class).get(AdminWhitelistRule.class).setMasterKillSwitch(false); r.jenkins.getExtensionList(AdminWhitelistRule.class).get(AdminWhitelistRule.class).setMasterKillSwitch(false);
final File f = new File(r.jenkins.getRootDir(), "config.xml"); final File f = new File(r.jenkins.getRootDir(), "config.xml");
assertTrue(f.exists()); assertTrue(f.exists());

View File

@ -65,13 +65,12 @@ import java.nio.charset.Charset;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import net.sf.json.JSONObject; import net.sf.json.JSONObject;
import org.junit.experimental.categories.Category;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.jvnet.hudson.test.CaptureEnvironmentBuilder; import org.jvnet.hudson.test.CaptureEnvironmentBuilder;
import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.SmokeTest;
import org.jvnet.hudson.test.TestBuilder; import org.jvnet.hudson.test.TestBuilder;
import org.jvnet.hudson.test.TestExtension; import org.jvnet.hudson.test.TestExtension;
import org.jvnet.hudson.test.junit.jupiter.WithJenkins; import org.jvnet.hudson.test.junit.jupiter.WithJenkins;
@ -118,7 +117,7 @@ class BuildCommandTest {
* Tests synchronous execution. * Tests synchronous execution.
*/ */
@Test @Test
@Category(SmokeTest.class) @Tag("SmokeTest")
void sync() throws Exception { void sync() throws Exception {
FreeStyleProject p = j.createFreeStyleProject(); FreeStyleProject p = j.createFreeStyleProject();
p.getBuildersList().add(Functions.isWindows() ? new BatchFile("ping 127.0.0.1") : new Shell("sleep 3")); p.getBuildersList().add(Functions.isWindows() ? new BatchFile("ping 127.0.0.1") : new Shell("sleep 3"));

View File

@ -33,27 +33,33 @@ import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.emptyOrNullString; import static org.hamcrest.Matchers.emptyOrNullString;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.notNullValue;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import hudson.Functions; import hudson.Functions;
import hudson.PluginWrapper; import hudson.PluginWrapper;
import java.io.IOException; import java.io.IOException;
import java.util.function.BiPredicate; import java.util.function.BiPredicate;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.junit.Assume; import org.junit.jupiter.api.Assumptions;
import org.junit.Ignore; import org.junit.jupiter.api.BeforeEach;
import org.junit.Rule; import org.junit.jupiter.api.Disabled;
import org.junit.Test; import org.junit.jupiter.api.Test;
import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.junit.jupiter.WithJenkins;
import org.jvnet.hudson.test.recipes.WithPlugin; import org.jvnet.hudson.test.recipes.WithPlugin;
public class DisablePluginCommandTest { @WithJenkins
class DisablePluginCommandTest {
@Rule private JenkinsRule j;
public JenkinsRule j = new JenkinsRule();
@BeforeEach
void setUp(JenkinsRule rule) {
j = rule;
}
/** /**
* Can disable a plugin with an optional dependent plugin. * Can disable a plugin with an optional dependent plugin.
@ -62,7 +68,7 @@ public class DisablePluginCommandTest {
@Test @Test
@Issue("JENKINS-27177") @Issue("JENKINS-27177")
@WithPlugin({"depender-0.0.2.hpi", "dependee-0.0.2.hpi"}) @WithPlugin({"depender-0.0.2.hpi", "dependee-0.0.2.hpi"})
public void canDisablePluginWithOptionalDependerStrategyNone() { void canDisablePluginWithOptionalDependerStrategyNone() {
assertThat(disablePluginsCLiCommand("-strategy", "NONE", "dependee"), succeeded()); assertThat(disablePluginsCLiCommand("-strategy", "NONE", "dependee"), succeeded());
assertPluginDisabled("dependee"); assertPluginDisabled("dependee");
} }
@ -70,12 +76,12 @@ public class DisablePluginCommandTest {
@Test @Test
@Issue("JENKINS-27177") @Issue("JENKINS-27177")
@WithPlugin({"depender-0.0.2.hpi", "dependee-0.0.2.hpi", "mandatory-depender-0.0.2.hpi"}) @WithPlugin({"depender-0.0.2.hpi", "dependee-0.0.2.hpi", "mandatory-depender-0.0.2.hpi"})
public void canDisablePluginWithDependentsDisabledStrategyNone() throws IOException { void canDisablePluginWithDependentsDisabledStrategyNone() throws IOException {
disablePlugin("mandatory-depender"); disablePlugin("mandatory-depender");
CLICommandInvoker.Result result = disablePluginsCLiCommand("-strategy", "NONE", "dependee"); CLICommandInvoker.Result result = disablePluginsCLiCommand("-strategy", "NONE", "dependee");
assertThat(result, succeeded()); assertThat(result, succeeded());
assertEquals("Disabling only dependee", 1, StringUtils.countMatches(result.stdout(), "Disabling")); assertEquals(1, StringUtils.countMatches(result.stdout(), "Disabling"), "Disabling only dependee");
assertPluginDisabled("dependee"); assertPluginDisabled("dependee");
} }
@ -86,7 +92,7 @@ public class DisablePluginCommandTest {
@Test @Test
@Issue("JENKINS-27177") @Issue("JENKINS-27177")
@WithPlugin({"mandatory-depender-0.0.2.hpi", "dependee-0.0.2.hpi"}) @WithPlugin({"mandatory-depender-0.0.2.hpi", "dependee-0.0.2.hpi"})
public void cannotDisablePluginWithMandatoryDependerStrategyNone() { void cannotDisablePluginWithMandatoryDependerStrategyNone() {
assertThat(disablePluginsCLiCommand("dependee"), failedWith(RETURN_CODE_NOT_DISABLED_DEPENDANTS)); assertThat(disablePluginsCLiCommand("dependee"), failedWith(RETURN_CODE_NOT_DISABLED_DEPENDANTS));
assertPluginEnabled("dependee"); assertPluginEnabled("dependee");
} }
@ -98,7 +104,7 @@ public class DisablePluginCommandTest {
@Test @Test
@Issue("JENKINS-27177") @Issue("JENKINS-27177")
@WithPlugin({"mandatory-depender-0.0.2.hpi", "dependee-0.0.2.hpi"}) @WithPlugin({"mandatory-depender-0.0.2.hpi", "dependee-0.0.2.hpi"})
public void cannotDisableDependentPluginWrongOrderStrategyNone() { void cannotDisableDependentPluginWrongOrderStrategyNone() {
assertThat(disablePluginsCLiCommand("dependee", "mandatory-depender"), failedWith(RETURN_CODE_NOT_DISABLED_DEPENDANTS)); assertThat(disablePluginsCLiCommand("dependee", "mandatory-depender"), failedWith(RETURN_CODE_NOT_DISABLED_DEPENDANTS));
assertPluginDisabled("mandatory-depender"); assertPluginDisabled("mandatory-depender");
assertPluginEnabled("dependee"); assertPluginEnabled("dependee");
@ -110,7 +116,7 @@ public class DisablePluginCommandTest {
@Test @Test
@Issue("JENKINS-27177") @Issue("JENKINS-27177")
@WithPlugin({"mandatory-depender-0.0.2.hpi", "dependee-0.0.2.hpi"}) @WithPlugin({"mandatory-depender-0.0.2.hpi", "dependee-0.0.2.hpi"})
public void canDisableDependentPluginWrongOrderStrategyAll() { void canDisableDependentPluginWrongOrderStrategyAll() {
assertThat(disablePluginsCLiCommand("dependee", "mandatory-depender", "-strategy", "all"), succeeded()); assertThat(disablePluginsCLiCommand("dependee", "mandatory-depender", "-strategy", "all"), succeeded());
assertPluginDisabled("mandatory-depender"); assertPluginDisabled("mandatory-depender");
assertPluginDisabled("dependee"); assertPluginDisabled("dependee");
@ -123,7 +129,7 @@ public class DisablePluginCommandTest {
@Test @Test
@Issue("JENKINS-27177") @Issue("JENKINS-27177")
@WithPlugin({"mandatory-depender-0.0.2.hpi", "dependee-0.0.2.hpi"}) @WithPlugin({"mandatory-depender-0.0.2.hpi", "dependee-0.0.2.hpi"})
public void canDisableDependentPluginsRightOrderStrategyNone() { void canDisableDependentPluginsRightOrderStrategyNone() {
assertThat(disablePluginsCLiCommand("mandatory-depender", "dependee"), succeeded()); assertThat(disablePluginsCLiCommand("mandatory-depender", "dependee"), succeeded());
assertPluginDisabled("dependee"); assertPluginDisabled("dependee");
assertPluginDisabled("mandatory-depender"); assertPluginDisabled("mandatory-depender");
@ -132,11 +138,11 @@ public class DisablePluginCommandTest {
/** /**
* Can disable a plugin without dependents plugins and Jenkins restart after it if -restart argument is passed. * Can disable a plugin without dependents plugins and Jenkins restart after it if -restart argument is passed.
*/ */
@Ignore("TODO calling restart seems to break Surefire") @Disabled("TODO calling restart seems to break Surefire")
@Test @Test
@Issue("JENKINS-27177") @Issue("JENKINS-27177")
@WithPlugin("dependee-0.0.2.hpi") @WithPlugin("dependee-0.0.2.hpi")
public void restartAfterDisable() { void restartAfterDisable() {
assumeNotWindows(); assumeNotWindows();
assertThat(disablePluginsCLiCommand("-restart", "dependee"), succeeded()); assertThat(disablePluginsCLiCommand("-restart", "dependee"), succeeded());
assertPluginDisabled("dependee"); assertPluginDisabled("dependee");
@ -149,7 +155,7 @@ public class DisablePluginCommandTest {
@Test @Test
@Issue("JENKINS-27177") @Issue("JENKINS-27177")
@WithPlugin("dependee-0.0.2.hpi") @WithPlugin("dependee-0.0.2.hpi")
public void notRestartAfterDisablePluginWithoutArgumentRestart() throws Exception { void notRestartAfterDisablePluginWithoutArgumentRestart() throws Exception {
assertThat(disablePluginsCLiCommand("dependee"), succeeded()); assertThat(disablePluginsCLiCommand("dependee"), succeeded());
assertPluginDisabled("dependee"); assertPluginDisabled("dependee");
assertJenkinsNotInQuietMode(); assertJenkinsNotInQuietMode();
@ -162,7 +168,7 @@ public class DisablePluginCommandTest {
@Test @Test
@Issue("JENKINS-27177") @Issue("JENKINS-27177")
@WithPlugin("dependee-0.0.2.hpi") @WithPlugin("dependee-0.0.2.hpi")
public void returnCodeDisableInvalidPlugin() { void returnCodeDisableInvalidPlugin() {
assertThat(disablePluginsCLiCommand("wrongname"), failedWith(RETURN_CODE_NO_SUCH_PLUGIN)); assertThat(disablePluginsCLiCommand("wrongname"), failedWith(RETURN_CODE_NO_SUCH_PLUGIN));
} }
@ -173,7 +179,7 @@ public class DisablePluginCommandTest {
@Test @Test
@Issue("JENKINS-27177") @Issue("JENKINS-27177")
@WithPlugin("dependee-0.0.2.hpi") @WithPlugin("dependee-0.0.2.hpi")
public void disableAlreadyDisabledPluginNotRestart() throws Exception { void disableAlreadyDisabledPluginNotRestart() throws Exception {
// Disable before the command call // Disable before the command call
disablePlugin("dependee"); disablePlugin("dependee");
@ -187,11 +193,11 @@ public class DisablePluginCommandTest {
/** /**
* If some plugins are disabled, Jenkins will restart even though the status code isn't 0 (is 16). * If some plugins are disabled, Jenkins will restart even though the status code isn't 0 (is 16).
*/ */
@Ignore("TODO calling restart seems to break Surefire") @Disabled("TODO calling restart seems to break Surefire")
@Test @Test
@Issue("JENKINS-27177") @Issue("JENKINS-27177")
@WithPlugin({"depender-0.0.2.hpi", "mandatory-depender-0.0.2.hpi", "plugin-first.hpi", "dependee-0.0.2.hpi"}) @WithPlugin({"depender-0.0.2.hpi", "mandatory-depender-0.0.2.hpi", "plugin-first.hpi", "dependee-0.0.2.hpi"})
public void restartAfterDisablePluginsAndErrors() { void restartAfterDisablePluginsAndErrors() {
assumeNotWindows(); assumeNotWindows();
assertThat(disablePluginsCLiCommand("-restart", "dependee", "depender", "plugin-first", "mandatory-depender"), failedWith(RETURN_CODE_NOT_DISABLED_DEPENDANTS)); assertThat(disablePluginsCLiCommand("-restart", "dependee", "depender", "plugin-first", "mandatory-depender"), failedWith(RETURN_CODE_NOT_DISABLED_DEPENDANTS));
assertPluginEnabled("dependee"); assertPluginEnabled("dependee");
@ -207,7 +213,7 @@ public class DisablePluginCommandTest {
@Test @Test
@Issue("JENKINS-27177") @Issue("JENKINS-27177")
@WithPlugin({"depender-0.0.2.hpi", "mandatory-depender-0.0.2.hpi", "plugin-first.hpi", "dependee-0.0.2.hpi"}) @WithPlugin({"depender-0.0.2.hpi", "mandatory-depender-0.0.2.hpi", "plugin-first.hpi", "dependee-0.0.2.hpi"})
public void disablePluginsStrategyAll() { void disablePluginsStrategyAll() {
assertPluginEnabled("dependee"); assertPluginEnabled("dependee");
assertPluginEnabled("depender"); assertPluginEnabled("depender");
assertPluginEnabled("mandatory-depender"); assertPluginEnabled("mandatory-depender");
@ -224,7 +230,7 @@ public class DisablePluginCommandTest {
@Test @Test
@Issue("JENKINS-27177") @Issue("JENKINS-27177")
@WithPlugin({"depender-0.0.2.hpi", "mandatory-depender-0.0.2.hpi", "plugin-first.hpi", "dependee-0.0.2.hpi"}) @WithPlugin({"depender-0.0.2.hpi", "mandatory-depender-0.0.2.hpi", "plugin-first.hpi", "dependee-0.0.2.hpi"})
public void disablePluginsStrategyMandatory() { void disablePluginsStrategyMandatory() {
assertThat(disablePluginsCLiCommand("-strategy", "mandatory", "dependee", "plugin-first"), succeeded()); assertThat(disablePluginsCLiCommand("-strategy", "mandatory", "dependee", "plugin-first"), succeeded());
assertPluginDisabled("dependee"); assertPluginDisabled("dependee");
assertPluginEnabled("depender"); assertPluginEnabled("depender");
@ -239,15 +245,15 @@ public class DisablePluginCommandTest {
@Test @Test
@Issue("JENKINS-27177") @Issue("JENKINS-27177")
@WithPlugin({"depender-0.0.2.hpi", "dependee-0.0.2.hpi"}) @WithPlugin({"depender-0.0.2.hpi", "dependee-0.0.2.hpi"})
public void disablePluginsMessageAlreadyDisabled() { void disablePluginsMessageAlreadyDisabled() {
CLICommandInvoker.Result result = disablePluginsCLiCommand("-strategy", "all", "dependee", "depender"); CLICommandInvoker.Result result = disablePluginsCLiCommand("-strategy", "all", "dependee", "depender");
assertThat(result, succeeded()); assertThat(result, succeeded());
assertPluginDisabled("dependee"); assertPluginDisabled("dependee");
assertPluginDisabled("depender"); assertPluginDisabled("depender");
assertTrue("An occurrence of the depender plugin in the log says it was successfully disabled", checkResultWith(result, StringUtils::contains, "depender", PluginWrapper.PluginDisableStatus.DISABLED)); assertTrue(checkResultWith(result, StringUtils::contains, "depender", PluginWrapper.PluginDisableStatus.DISABLED), "An occurrence of the depender plugin in the log says it was successfully disabled");
assertTrue("An occurrence of the depender plugin in the log says it was already disabled", checkResultWith(result, StringUtils::contains, "depender", PluginWrapper.PluginDisableStatus.ALREADY_DISABLED)); assertTrue(checkResultWith(result, StringUtils::contains, "depender", PluginWrapper.PluginDisableStatus.ALREADY_DISABLED), "An occurrence of the depender plugin in the log says it was already disabled");
} }
/** /**
@ -257,7 +263,7 @@ public class DisablePluginCommandTest {
@Test @Test
@Issue("JENKINS-27177") @Issue("JENKINS-27177")
@WithPlugin({"dependee-0.0.2.hpi", "mandatory-depender-0.0.2.hpi"}) @WithPlugin({"dependee-0.0.2.hpi", "mandatory-depender-0.0.2.hpi"})
public void returnCodeFirstErrorIsDependents() { void returnCodeFirstErrorIsDependents() {
CLICommandInvoker.Result result = disablePluginsCLiCommand("dependee", "badplugin"); CLICommandInvoker.Result result = disablePluginsCLiCommand("dependee", "badplugin");
assertThat(result, failedWith(RETURN_CODE_NOT_DISABLED_DEPENDANTS)); assertThat(result, failedWith(RETURN_CODE_NOT_DISABLED_DEPENDANTS));
@ -270,7 +276,7 @@ public class DisablePluginCommandTest {
@Test @Test
@Issue("JENKINS-27177") @Issue("JENKINS-27177")
@WithPlugin({"dependee-0.0.2.hpi", "mandatory-depender-0.0.2.hpi"}) @WithPlugin({"dependee-0.0.2.hpi", "mandatory-depender-0.0.2.hpi"})
public void returnCodeFirstErrorIsNoSuchPlugin() { void returnCodeFirstErrorIsNoSuchPlugin() {
CLICommandInvoker.Result result = disablePluginsCLiCommand("badplugin", "dependee"); CLICommandInvoker.Result result = disablePluginsCLiCommand("badplugin", "dependee");
assertThat(result, failedWith(RETURN_CODE_NO_SUCH_PLUGIN)); assertThat(result, failedWith(RETURN_CODE_NO_SUCH_PLUGIN));
@ -283,7 +289,7 @@ public class DisablePluginCommandTest {
@Test @Test
@Issue("JENKINS-27177") @Issue("JENKINS-27177")
@WithPlugin({"depender-0.0.2.hpi", "dependee-0.0.2.hpi", "mandatory-depender-0.0.2.hpi"}) @WithPlugin({"depender-0.0.2.hpi", "dependee-0.0.2.hpi", "mandatory-depender-0.0.2.hpi"})
public void quietModeEmptyOutputSucceed() { void quietModeEmptyOutputSucceed() {
CLICommandInvoker.Result result = disablePluginsCLiCommand("-strategy", "all", "-quiet", "dependee"); CLICommandInvoker.Result result = disablePluginsCLiCommand("-strategy", "all", "-quiet", "dependee");
assertThat(result, succeeded()); assertThat(result, succeeded());
@ -300,7 +306,7 @@ public class DisablePluginCommandTest {
@Test @Test
@Issue("JENKINS-27177") @Issue("JENKINS-27177")
@WithPlugin({"depender-0.0.2.hpi", "dependee-0.0.2.hpi", "mandatory-depender-0.0.2.hpi"}) @WithPlugin({"depender-0.0.2.hpi", "dependee-0.0.2.hpi", "mandatory-depender-0.0.2.hpi"})
public void quietModeWithErrorNoSuch() { void quietModeWithErrorNoSuch() {
CLICommandInvoker.Result result = disablePluginsCLiCommand("-quiet", "-strategy", "all", "dependee", "badplugin"); CLICommandInvoker.Result result = disablePluginsCLiCommand("-quiet", "-strategy", "all", "dependee", "badplugin");
assertThat(result, failedWith(RETURN_CODE_NO_SUCH_PLUGIN)); assertThat(result, failedWith(RETURN_CODE_NO_SUCH_PLUGIN));
@ -308,7 +314,7 @@ public class DisablePluginCommandTest {
assertPluginDisabled("depender"); assertPluginDisabled("depender");
assertPluginDisabled("mandatory-depender"); assertPluginDisabled("mandatory-depender");
assertTrue("Only error NO_SUCH_PLUGIN in quiet mode", checkResultWith(result, StringUtils::startsWith, "badplugin", PluginWrapper.PluginDisableStatus.NO_SUCH_PLUGIN)); assertTrue(checkResultWith(result, StringUtils::startsWith, "badplugin", PluginWrapper.PluginDisableStatus.NO_SUCH_PLUGIN), "Only error NO_SUCH_PLUGIN in quiet mode");
} }
/** /**
@ -317,7 +323,7 @@ public class DisablePluginCommandTest {
@Test @Test
@Issue("JENKINS-27177") @Issue("JENKINS-27177")
@WithPlugin({"depender-0.0.2.hpi", "dependee-0.0.2.hpi", "mandatory-depender-0.0.2.hpi"}) @WithPlugin({"depender-0.0.2.hpi", "dependee-0.0.2.hpi", "mandatory-depender-0.0.2.hpi"})
public void quietModeWithErrorDependents() { void quietModeWithErrorDependents() {
CLICommandInvoker.Result result = disablePluginsCLiCommand("-quiet", "-strategy", "none", "dependee"); CLICommandInvoker.Result result = disablePluginsCLiCommand("-quiet", "-strategy", "none", "dependee");
assertThat(result, failedWith(RETURN_CODE_NOT_DISABLED_DEPENDANTS)); assertThat(result, failedWith(RETURN_CODE_NOT_DISABLED_DEPENDANTS));
@ -325,7 +331,7 @@ public class DisablePluginCommandTest {
assertPluginEnabled("depender"); assertPluginEnabled("depender");
assertPluginEnabled("mandatory-depender"); assertPluginEnabled("mandatory-depender");
assertTrue("Only error NOT_DISABLED_DEPENDANTS in quiet mode", checkResultWith(result, StringUtils::startsWith, "dependee", PluginWrapper.PluginDisableStatus.NOT_DISABLED_DEPENDANTS)); assertTrue(checkResultWith(result, StringUtils::startsWith, "dependee", PluginWrapper.PluginDisableStatus.NOT_DISABLED_DEPENDANTS), "Only error NOT_DISABLED_DEPENDANTS in quiet mode");
} }
/** /**
@ -388,6 +394,6 @@ public class DisablePluginCommandTest {
} }
private void assumeNotWindows() { private void assumeNotWindows() {
Assume.assumeFalse(Functions.isWindows()); Assumptions.assumeFalse(Functions.isWindows());
} }
} }

View File

@ -41,37 +41,38 @@ import hudson.slaves.DumbSlave;
import hudson.slaves.OfflineCause; import hudson.slaves.OfflineCause;
import hudson.util.OneShotEvent; import hudson.util.OneShotEvent;
import jenkins.model.Jenkins; import jenkins.model.Jenkins;
import org.junit.Before; import org.junit.jupiter.api.BeforeEach;
import org.junit.ClassRule; import org.junit.jupiter.api.Test;
import org.junit.Rule; import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.Test;
import org.jvnet.hudson.test.BuildWatcher;
import org.jvnet.hudson.test.InboundAgentRule;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.junit.jupiter.BuildWatcherExtension;
import org.jvnet.hudson.test.junit.jupiter.InboundAgentExtension;
import org.jvnet.hudson.test.junit.jupiter.WithJenkins;
/** /**
* @author pjanouse * @author pjanouse
*/ */
public class OfflineNodeCommandTest { @WithJenkins
class OfflineNodeCommandTest {
private CLICommandInvoker command; private CLICommandInvoker command;
@ClassRule @RegisterExtension
public static final BuildWatcher buildWatcher = new BuildWatcher(); private static final BuildWatcherExtension buildWatcher = new BuildWatcherExtension();
@Rule @RegisterExtension
public final JenkinsRule j = new JenkinsRule(); private final InboundAgentExtension inboundAgents = new InboundAgentExtension();
@Rule private JenkinsRule j;
public InboundAgentRule inboundAgents = new InboundAgentRule();
@Before @BeforeEach
public void setUp() { void setUp(JenkinsRule rule) {
j = rule;
command = new CLICommandInvoker(j, "offline-node"); command = new CLICommandInvoker(j, "offline-node");
} }
@Test @Test
public void offlineNodeShouldFailWithoutComputerDisconnectPermission() throws Exception { void offlineNodeShouldFailWithoutComputerDisconnectPermission() throws Exception {
j.createSlave("aNode", "", null); j.createSlave("aNode", "", null);
final CLICommandInvoker.Result result = command final CLICommandInvoker.Result result = command
@ -84,7 +85,7 @@ public class OfflineNodeCommandTest {
} }
@Test @Test
public void offlineNodeShouldFailIfNodeDoesNotExist() { void offlineNodeShouldFailIfNodeDoesNotExist() {
final CLICommandInvoker.Result result = command final CLICommandInvoker.Result result = command
.authorizedTo(Computer.DISCONNECT, Jenkins.READ) .authorizedTo(Computer.DISCONNECT, Jenkins.READ)
.invokeWithArgs("never_created"); .invokeWithArgs("never_created");
@ -95,7 +96,7 @@ public class OfflineNodeCommandTest {
} }
@Test @Test
public void offlineNodeShouldSucceedOnOnlineNode() throws Exception { void offlineNodeShouldSucceedOnOnlineNode() throws Exception {
DumbSlave slave = j.createSlave("aNode", "", null); DumbSlave slave = j.createSlave("aNode", "", null);
slave.toComputer().waitUntilOnline(); slave.toComputer().waitUntilOnline();
assertThat(slave.toComputer().isOnline(), equalTo(true)); assertThat(slave.toComputer().isOnline(), equalTo(true));
@ -113,8 +114,8 @@ public class OfflineNodeCommandTest {
} }
@Test @Test
public void offlineNodeShouldSucceedOnOfflineNode() throws Exception { void offlineNodeShouldSucceedOnOfflineNode() throws Exception {
Slave slave = inboundAgents.createAgent(j, InboundAgentRule.Options.newBuilder().name("aNode").skipStart().build()); Slave slave = inboundAgents.createAgent(j, InboundAgentExtension.Options.newBuilder().name("aNode").skipStart().build());
slave.toComputer().setTemporarilyOffline(true, null); slave.toComputer().setTemporarilyOffline(true, null);
assertThat(slave.toComputer().isOffline(), equalTo(true)); assertThat(slave.toComputer().isOffline(), equalTo(true));
assertThat(slave.toComputer().isTemporarilyOffline(), equalTo(true)); assertThat(slave.toComputer().isTemporarilyOffline(), equalTo(true));
@ -131,7 +132,7 @@ public class OfflineNodeCommandTest {
} }
@Test @Test
public void offlineNodeShouldSucceedOnDisconnectedNode() throws Exception { void offlineNodeShouldSucceedOnDisconnectedNode() throws Exception {
DumbSlave slave = j.createSlave("aNode", "", null); DumbSlave slave = j.createSlave("aNode", "", null);
slave.toComputer().waitUntilOnline(); slave.toComputer().waitUntilOnline();
assertThat(slave.toComputer().isOnline(), equalTo(true)); assertThat(slave.toComputer().isOnline(), equalTo(true));
@ -154,7 +155,7 @@ public class OfflineNodeCommandTest {
} }
@Test @Test
public void offlineNodeShouldSucceedOnOnlineNodeWithCause() throws Exception { void offlineNodeShouldSucceedOnOnlineNodeWithCause() throws Exception {
DumbSlave slave = j.createSlave("aNode", "", null); DumbSlave slave = j.createSlave("aNode", "", null);
slave.toComputer().waitUntilOnline(); slave.toComputer().waitUntilOnline();
assertThat(slave.toComputer().isOnline(), equalTo(true)); assertThat(slave.toComputer().isOnline(), equalTo(true));
@ -172,8 +173,8 @@ public class OfflineNodeCommandTest {
} }
@Test @Test
public void offlineNodeShouldSucceedOnOfflineNodeWithCause() throws Exception { void offlineNodeShouldSucceedOnOfflineNodeWithCause() throws Exception {
Slave slave = inboundAgents.createAgent(j, InboundAgentRule.Options.newBuilder().name("aNode").skipStart().build()); Slave slave = inboundAgents.createAgent(j, InboundAgentExtension.Options.newBuilder().name("aNode").skipStart().build());
slave.toComputer().setTemporarilyOffline(true, null); slave.toComputer().setTemporarilyOffline(true, null);
assertThat(slave.toComputer().isOffline(), equalTo(true)); assertThat(slave.toComputer().isOffline(), equalTo(true));
assertThat(slave.toComputer().isTemporarilyOffline(), equalTo(true)); assertThat(slave.toComputer().isTemporarilyOffline(), equalTo(true));
@ -190,7 +191,7 @@ public class OfflineNodeCommandTest {
} }
@Test @Test
public void offlineNodeShouldSucceedOnDisconnectedNodeWithCause() throws Exception { void offlineNodeShouldSucceedOnDisconnectedNodeWithCause() throws Exception {
DumbSlave slave = j.createSlave("aNode", "", null); DumbSlave slave = j.createSlave("aNode", "", null);
slave.toComputer().waitUntilOnline(); slave.toComputer().waitUntilOnline();
assertThat(slave.toComputer().isOnline(), equalTo(true)); assertThat(slave.toComputer().isOnline(), equalTo(true));
@ -213,7 +214,7 @@ public class OfflineNodeCommandTest {
} }
@Test @Test
public void offlineNodeShouldSucceedOnBuildingNode() throws Exception { void offlineNodeShouldSucceedOnBuildingNode() throws Exception {
final OneShotEvent finish = new OneShotEvent(); final OneShotEvent finish = new OneShotEvent();
DumbSlave slave = j.createSlave("aNode", "", null); DumbSlave slave = j.createSlave("aNode", "", null);
slave.toComputer().waitUntilOnline(); slave.toComputer().waitUntilOnline();
@ -239,7 +240,7 @@ public class OfflineNodeCommandTest {
} }
@Test @Test
public void offlineNodeShouldSucceedOnBuildingNodeWithCause() throws Exception { void offlineNodeShouldSucceedOnBuildingNodeWithCause() throws Exception {
final OneShotEvent finish = new OneShotEvent(); final OneShotEvent finish = new OneShotEvent();
DumbSlave slave = j.createSlave("aNode", "", null); DumbSlave slave = j.createSlave("aNode", "", null);
slave.toComputer().waitUntilOnline(); slave.toComputer().waitUntilOnline();
@ -265,7 +266,7 @@ public class OfflineNodeCommandTest {
} }
@Test @Test
public void offlineNodeManyShouldSucceed() throws Exception { void offlineNodeManyShouldSucceed() throws Exception {
DumbSlave slave1 = j.createSlave("aNode1", "", null); DumbSlave slave1 = j.createSlave("aNode1", "", null);
DumbSlave slave2 = j.createSlave("aNode2", "", null); DumbSlave slave2 = j.createSlave("aNode2", "", null);
DumbSlave slave3 = j.createSlave("aNode3", "", null); DumbSlave slave3 = j.createSlave("aNode3", "", null);
@ -295,7 +296,7 @@ public class OfflineNodeCommandTest {
} }
@Test @Test
public void offlineNodeManyShouldSucceedWithCause() throws Exception { void offlineNodeManyShouldSucceedWithCause() throws Exception {
DumbSlave slave1 = j.createSlave("aNode1", "", null); DumbSlave slave1 = j.createSlave("aNode1", "", null);
DumbSlave slave2 = j.createSlave("aNode2", "", null); DumbSlave slave2 = j.createSlave("aNode2", "", null);
DumbSlave slave3 = j.createSlave("aNode3", "", null); DumbSlave slave3 = j.createSlave("aNode3", "", null);
@ -325,7 +326,7 @@ public class OfflineNodeCommandTest {
} }
@Test @Test
public void offlineNodeManyShouldFailIfANodeDoesNotExist() throws Exception { void offlineNodeManyShouldFailIfANodeDoesNotExist() throws Exception {
DumbSlave slave1 = j.createSlave("aNode1", "", null); DumbSlave slave1 = j.createSlave("aNode1", "", null);
DumbSlave slave2 = j.createSlave("aNode2", "", null); DumbSlave slave2 = j.createSlave("aNode2", "", null);
slave1.toComputer().waitUntilOnline(); slave1.toComputer().waitUntilOnline();
@ -351,7 +352,7 @@ public class OfflineNodeCommandTest {
} }
@Test @Test
public void offlineNodeManyShouldFailIfANodeDoesNotExistWithCause() throws Exception { void offlineNodeManyShouldFailIfANodeDoesNotExistWithCause() throws Exception {
DumbSlave slave1 = j.createSlave("aNode1", "", null); DumbSlave slave1 = j.createSlave("aNode1", "", null);
DumbSlave slave2 = j.createSlave("aNode2", "", null); DumbSlave slave2 = j.createSlave("aNode2", "", null);
slave1.toComputer().waitUntilOnline(); slave1.toComputer().waitUntilOnline();
@ -377,7 +378,7 @@ public class OfflineNodeCommandTest {
} }
@Test @Test
public void offlineNodeManyShouldSucceedEvenANodeIsSpecifiedTwice() throws Exception { void offlineNodeManyShouldSucceedEvenANodeIsSpecifiedTwice() throws Exception {
DumbSlave slave1 = j.createSlave("aNode1", "", null); DumbSlave slave1 = j.createSlave("aNode1", "", null);
DumbSlave slave2 = j.createSlave("aNode2", "", null); DumbSlave slave2 = j.createSlave("aNode2", "", null);
slave1.toComputer().waitUntilOnline(); slave1.toComputer().waitUntilOnline();
@ -400,7 +401,7 @@ public class OfflineNodeCommandTest {
} }
@Test @Test
public void offlineNodeManyShouldSucceedEvenANodeIsSpecifiedTwiceWithCause() throws Exception { void offlineNodeManyShouldSucceedEvenANodeIsSpecifiedTwiceWithCause() throws Exception {
DumbSlave slave1 = j.createSlave("aNode1", "", null); DumbSlave slave1 = j.createSlave("aNode1", "", null);
DumbSlave slave2 = j.createSlave("aNode2", "", null); DumbSlave slave2 = j.createSlave("aNode2", "", null);
slave1.toComputer().waitUntilOnline(); slave1.toComputer().waitUntilOnline();
@ -423,7 +424,7 @@ public class OfflineNodeCommandTest {
} }
@Test @Test
public void offlineNodeShouldSucceedOnMaster() { void offlineNodeShouldSucceedOnMaster() {
final Computer masterComputer = Jenkins.get().getComputer(""); final Computer masterComputer = Jenkins.get().getComputer("");
final CLICommandInvoker.Result result = command final CLICommandInvoker.Result result = command
@ -437,7 +438,7 @@ public class OfflineNodeCommandTest {
} }
@Test @Test
public void offlineNodeShouldSucceedOnMasterWithCause() { void offlineNodeShouldSucceedOnMasterWithCause() {
final Computer masterComputer = Jenkins.get().getComputer(""); final Computer masterComputer = Jenkins.get().getComputer("");
final CLICommandInvoker.Result result = command final CLICommandInvoker.Result result = command

View File

@ -24,7 +24,7 @@
package hudson.diagnosis; package hudson.diagnosis;
import static org.junit.Assert.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import java.net.URL; import java.net.URL;
import java.util.List; import java.util.List;
@ -32,250 +32,165 @@ import jenkins.model.JenkinsLocationConfiguration;
import org.htmlunit.FailingHttpStatusCodeException; import org.htmlunit.FailingHttpStatusCodeException;
import org.htmlunit.WebRequest; import org.htmlunit.WebRequest;
import org.htmlunit.util.NameValuePair; import org.htmlunit.util.NameValuePair;
import org.junit.Before; import org.junit.jupiter.api.BeforeEach;
import org.junit.Rule; import org.junit.jupiter.api.Test;
import org.junit.Test;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.RestartableJenkinsRule; import org.jvnet.hudson.test.junit.jupiter.WithJenkins;
public class ReverseProxySetupMonitorTest { @WithJenkins
class ReverseProxySetupMonitorTest {
@Rule private JenkinsRule j;
public RestartableJenkinsRule rr = new RestartableJenkinsRule() {
@Override
protected JenkinsRule createJenkinsRule(Description description) {
JenkinsRule j = super.createJenkinsRule(description);
j.contextPath = desiredContextPath;
return j;
}
};
private String desiredContextPath; @BeforeEach
void setUp(JenkinsRule rule) {
@Before j = rule;
public void resetContextPath() {
this.desiredContextPath = "/jenkins";
} }
@Test @Test
public void localhost_correct() { void localhost_correct() throws Exception {
rr.addStep(new Statement() { JenkinsRule.WebClient wc = j.createWebClient();
@Override WebRequest request = new WebRequest(new URL(j.getURL(), getAdminMonitorTestUrl(j)));
public void evaluate() throws Throwable { request.setAdditionalHeader("Referer", j.getURL() + "manage");
JenkinsRule j = rr.j; wc.getPage(request);
JenkinsRule.WebClient wc = rr.j.createWebClient();
WebRequest request = new WebRequest(new URL(j.getURL(), getAdminMonitorTestUrl(j)));
request.setAdditionalHeader("Referer", j.getURL() + "manage");
wc.getPage(request);
}
});
} }
@Test @Test
public void localhost_testingForContext() { void localhost_testingForContext() throws Exception {
rr.addStep(new Statement() { JenkinsRule.WebClient wc = j.createWebClient();
@Override WebRequest request = new WebRequest(new URL(j.getURL(), getAdminMonitorTestUrl(j)));
public void evaluate() throws Throwable { request.setAdditionalHeader("Referer", j.getURL() + "manage");
JenkinsRule j = rr.j;
JenkinsRule.WebClient wc = rr.j.createWebClient();
WebRequest request = new WebRequest(new URL(j.getURL(), getAdminMonitorTestUrl(j)));
request.setAdditionalHeader("Referer", j.getURL() + "manage");
// As the context was already set inside the referer, adding another one will fail // As the context was already set inside the referer, adding another one will fail
request.setRequestParameters(List.of(new NameValuePair("testWithContext", "true"))); request.setRequestParameters(List.of(new NameValuePair("testWithContext", "true")));
assertThrows(FailingHttpStatusCodeException.class, () -> wc.getPage(request)); assertThrows(FailingHttpStatusCodeException.class, () -> wc.getPage(request));
}
});
} }
@Test @Test
public void localhost_withoutReferer() { void localhost_withoutReferer() throws Exception {
rr.addStep(new Statement() { JenkinsRule.WebClient wc = j.createWebClient();
@Override WebRequest request = new WebRequest(new URL(j.getURL(), getAdminMonitorTestUrl(j)));
public void evaluate() throws Throwable { // no referer
JenkinsRule j = rr.j; assertThrows(FailingHttpStatusCodeException.class, () -> wc.getPage(request));
JenkinsRule.WebClient wc = rr.j.createWebClient();
WebRequest request = new WebRequest(new URL(j.getURL(), getAdminMonitorTestUrl(j)));
// no referer
assertThrows(FailingHttpStatusCodeException.class, () -> wc.getPage(request));
}
});
} }
@Test @Test
public void localhost_withRefererNotComingFromManage() { void localhost_withRefererNotComingFromManage() throws Exception {
rr.addStep(new Statement() { JenkinsRule.WebClient wc = j.createWebClient();
@Override WebRequest request = new WebRequest(new URL(j.getURL(), getAdminMonitorTestUrl(j)));
public void evaluate() throws Throwable { // wrong referer
JenkinsRule j = rr.j; request.setAdditionalHeader("Referer", j.getURL() + "configure");
JenkinsRule.WebClient wc = rr.j.createWebClient(); assertThrows(FailingHttpStatusCodeException.class, () -> wc.getPage(request));
WebRequest request = new WebRequest(new URL(j.getURL(), getAdminMonitorTestUrl(j)));
// wrong referer
request.setAdditionalHeader("Referer", j.getURL() + "configure");
assertThrows(FailingHttpStatusCodeException.class, () -> wc.getPage(request));
}
});
} }
@Test @Test
public void withRootURL_localhost_missingContext() { void withRootURL_localhost_missingContext() throws Exception {
rr.addStep(new Statement() { String fullRootUrl = j.getURL().toString();
@Override String rootUrlWithoutContext = fullRootUrl.replace("/jenkins", "");
public void evaluate() throws Throwable { JenkinsLocationConfiguration.get().setUrl(rootUrlWithoutContext);
JenkinsRule j = rr.j;
String fullRootUrl = j.getURL().toString(); JenkinsRule.WebClient wc = j.createWebClient();
String rootUrlWithoutContext = fullRootUrl.replace("/jenkins", ""); WebRequest request = new WebRequest(new URL(j.getURL(), getAdminMonitorTestUrl(j)));
JenkinsLocationConfiguration.get().setUrl(rootUrlWithoutContext); request.setAdditionalHeader("Referer", j.getURL() + "manage");
JenkinsRule.WebClient wc = rr.j.createWebClient(); // As the rootURL is missing the context, a regular test will fail
WebRequest request = new WebRequest(new URL(j.getURL(), getAdminMonitorTestUrl(j))); assertThrows(FailingHttpStatusCodeException.class, () -> wc.getPage(request));
request.setAdditionalHeader("Referer", j.getURL() + "manage");
// As the rootURL is missing the context, a regular test will fail // When testing with the context, it will be OK, allowing to display an additional message
assertThrows(FailingHttpStatusCodeException.class, () -> wc.getPage(request)); request.setRequestParameters(List.of(new NameValuePair("testWithContext", "true")));
wc.getPage(request);
// When testing with the context, it will be OK, allowing to display an additional message
request.setRequestParameters(List.of(new NameValuePair("testWithContext", "true")));
wc.getPage(request);
}
});
} }
@Test @Test
public void withRootURL_localhost_wrongContext() { void withRootURL_localhost_wrongContext() throws Exception {
rr.addStep(new Statement() { String fullRootUrl = j.getURL().toString();
@Override String rootUrlWithoutContext = fullRootUrl.replace("/jenkins", "/wrong");
public void evaluate() throws Throwable { JenkinsLocationConfiguration.get().setUrl(rootUrlWithoutContext);
JenkinsRule j = rr.j;
String fullRootUrl = j.getURL().toString(); JenkinsRule.WebClient wc = j.createWebClient();
String rootUrlWithoutContext = fullRootUrl.replace("/jenkins", "/wrong"); WebRequest request = new WebRequest(new URL(j.getURL(), getAdminMonitorTestUrl(j)));
JenkinsLocationConfiguration.get().setUrl(rootUrlWithoutContext); request.setAdditionalHeader("Referer", j.getURL() + "manage");
JenkinsRule.WebClient wc = rr.j.createWebClient(); assertThrows(FailingHttpStatusCodeException.class, () -> wc.getPage(request));
WebRequest request = new WebRequest(new URL(j.getURL(), getAdminMonitorTestUrl(j)));
request.setAdditionalHeader("Referer", j.getURL() + "manage");
assertThrows(FailingHttpStatusCodeException.class, () -> wc.getPage(request)); request.setRequestParameters(List.of(new NameValuePair("testWithContext", "true")));
assertThrows(FailingHttpStatusCodeException.class, () -> wc.getPage(request));
request.setRequestParameters(List.of(new NameValuePair("testWithContext", "true")));
assertThrows(FailingHttpStatusCodeException.class, () -> wc.getPage(request));
}
});
} }
@Test @Test
public void desiredContextPathEmpty_localhost() { void desiredContextPathEmpty_localhost() throws Throwable {
desiredContextPath = ""; j.contextPath = "";
rr.addStep(new Statement() {
@Override
public void evaluate() throws Throwable {
JenkinsRule j = rr.j;
JenkinsRule.WebClient wc = rr.j.createWebClient(); j.restart();
WebRequest request = new WebRequest(new URL(j.getURL(), getAdminMonitorTestUrl(j)));
request.setAdditionalHeader("Referer", j.getURL() + "manage");
wc.getPage(request); JenkinsRule.WebClient wc = j.createWebClient();
WebRequest request = new WebRequest(new URL(j.getURL(), getAdminMonitorTestUrl(j)));
request.setAdditionalHeader("Referer", j.getURL() + "manage");
// adding the context does not have any impact as there is no configured context wc.getPage(request);
request.setRequestParameters(List.of(new NameValuePair("testWithContext", "true")));
wc.getPage(request); // adding the context does not have any impact as there is no configured context
} request.setRequestParameters(List.of(new NameValuePair("testWithContext", "true")));
}); wc.getPage(request);
} }
@Test @Test
public void usingIp_butRefererUsingRootUrl() { void usingIp_butRefererUsingRootUrl() throws Exception {
rr.addStep(new Statement() { JenkinsRule.WebClient wc = j.createWebClient();
@Override WebRequest request = new WebRequest(new URL(getRootUrlWithIp(j), getAdminMonitorTestUrl(j)));
public void evaluate() throws Throwable { request.setAdditionalHeader("Referer", j.getURL() + "manage");
JenkinsRule j = rr.j; wc.getPage(request);
JenkinsRule.WebClient wc = rr.j.createWebClient();
WebRequest request = new WebRequest(new URL(getRootUrlWithIp(j), getAdminMonitorTestUrl(j)));
request.setAdditionalHeader("Referer", j.getURL() + "manage");
wc.getPage(request);
}
});
} }
@Test @Test
public void usingIp_withoutReferer() { void usingIp_withoutReferer() throws Exception {
rr.addStep(new Statement() { JenkinsRule.WebClient wc = j.createWebClient();
@Override WebRequest request = new WebRequest(new URL(getRootUrlWithIp(j), getAdminMonitorTestUrl(j)));
public void evaluate() throws Throwable { // no referer
JenkinsRule j = rr.j; assertThrows(FailingHttpStatusCodeException.class, () -> wc.getPage(request));
JenkinsRule.WebClient wc = rr.j.createWebClient();
WebRequest request = new WebRequest(new URL(getRootUrlWithIp(j), getAdminMonitorTestUrl(j)));
// no referer
assertThrows(FailingHttpStatusCodeException.class, () -> wc.getPage(request));
}
});
} }
@Test @Test
public void usingIp_withRefererIp() { void usingIp_withRefererIp() throws Exception {
rr.addStep(new Statement() { JenkinsRule.WebClient wc = j.createWebClient();
@Override WebRequest request = new WebRequest(new URL(getRootUrlWithIp(j), getAdminMonitorTestUrl(j)));
public void evaluate() throws Throwable { // referer using IP
JenkinsRule j = rr.j; request.setAdditionalHeader("Referer", getRootUrlWithIp(j) + "manage");
JenkinsRule.WebClient wc = rr.j.createWebClient();
WebRequest request = new WebRequest(new URL(getRootUrlWithIp(j), getAdminMonitorTestUrl(j)));
// referer using IP
request.setAdditionalHeader("Referer", getRootUrlWithIp(j) + "manage");
// by default the JenkinsRule set the rootURL to localhost:<port>/jenkins // by default the JenkinsRule set the rootURL to localhost:<port>/jenkins
// even with similar request and referer, if the root URL is set, this will show a wrong proxy setting // even with similar request and referer, if the root URL is set, this will show a wrong proxy setting
assertThrows(FailingHttpStatusCodeException.class, () -> wc.getPage(request)); assertThrows(FailingHttpStatusCodeException.class, () -> wc.getPage(request));
}
});
} }
@Test @Test
public void withRootURL_usingIp_withRefererIp() { void withRootURL_usingIp_withRefererIp() throws Exception {
rr.addStep(new Statement() { JenkinsLocationConfiguration.get().setUrl(getRootUrlWithIp(j).toString());
@Override
public void evaluate() throws Throwable {
JenkinsRule j = rr.j;
JenkinsLocationConfiguration.get().setUrl(getRootUrlWithIp(j).toString());
JenkinsRule.WebClient wc = rr.j.createWebClient(); JenkinsRule.WebClient wc = j.createWebClient();
WebRequest request = new WebRequest(new URL(getRootUrlWithIp(j), getAdminMonitorTestUrl(j))); WebRequest request = new WebRequest(new URL(getRootUrlWithIp(j), getAdminMonitorTestUrl(j)));
// referer using IP // referer using IP
request.setAdditionalHeader("Referer", getRootUrlWithIp(j) + "manage"); request.setAdditionalHeader("Referer", getRootUrlWithIp(j) + "manage");
wc.getPage(request); wc.getPage(request);
}
});
} }
@Test @Test
public void withRootURL_usingIp_missingContext_withRefererIp() { void withRootURL_usingIp_missingContext_withRefererIp() throws Exception {
rr.addStep(new Statement() { String fullRootUrl = getRootUrlWithIp(j).toString();
@Override String rootUrlWithoutContext = fullRootUrl.replace("/jenkins", "");
public void evaluate() throws Throwable { JenkinsLocationConfiguration.get().setUrl(rootUrlWithoutContext);
JenkinsRule j = rr.j;
String fullRootUrl = getRootUrlWithIp(j).toString(); JenkinsRule.WebClient wc = j.createWebClient();
String rootUrlWithoutContext = fullRootUrl.replace("/jenkins", ""); WebRequest request = new WebRequest(new URL(getRootUrlWithIp(j), getAdminMonitorTestUrl(j)));
JenkinsLocationConfiguration.get().setUrl(rootUrlWithoutContext); // referer using IP
request.setAdditionalHeader("Referer", getRootUrlWithIp(j) + "manage");
JenkinsRule.WebClient wc = rr.j.createWebClient(); // As the rootURL is missing the context, a regular test will fail
WebRequest request = new WebRequest(new URL(getRootUrlWithIp(j), getAdminMonitorTestUrl(j))); assertThrows(FailingHttpStatusCodeException.class, () -> wc.getPage(request));
// referer using IP
request.setAdditionalHeader("Referer", getRootUrlWithIp(j) + "manage");
// As the rootURL is missing the context, a regular test will fail // When testing with the context, it will be OK, allowing to display an additional message
assertThrows(FailingHttpStatusCodeException.class, () -> wc.getPage(request)); request.setRequestParameters(List.of(new NameValuePair("testWithContext", "true")));
wc.getPage(request);
// When testing with the context, it will be OK, allowing to display an additional message
request.setRequestParameters(List.of(new NameValuePair("testWithContext", "true")));
wc.getPage(request);
}
});
} }
private String getAdminMonitorTestUrl(JenkinsRule j) { private String getAdminMonitorTestUrl(JenkinsRule j) {

View File

@ -30,21 +30,21 @@ import static org.hamcrest.Matchers.is;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.logging.Level; import java.util.logging.Level;
import jenkins.model.Jenkins; import jenkins.model.Jenkins;
import org.junit.Rule; import org.junit.jupiter.api.Test;
import org.junit.Test; import org.junit.jupiter.api.extension.RegisterExtension;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.RealJenkinsRule; import org.jvnet.hudson.test.junit.jupiter.RealJenkinsExtension;
public final class LifecycleTest { class LifecycleTest {
@Rule @RegisterExtension
public RealJenkinsRule rr = new RealJenkinsRule() private final RealJenkinsExtension rr = new RealJenkinsExtension()
.addPlugins("plugins/custom-lifecycle.hpi") .addPlugins("plugins/custom-lifecycle.hpi")
.javaOptions("-Dhudson.lifecycle=test.custom_lifecycle.CustomLifecycle") .javaOptions("-Dhudson.lifecycle=test.custom_lifecycle.CustomLifecycle")
.withLogger(Lifecycle.class, Level.FINE); .withLogger(Lifecycle.class, Level.FINE);
@Test @Test
public void definedInPlugin() throws Throwable { void definedInPlugin() throws Throwable {
rr.then(LifecycleTest::_definedInPlugin); rr.then(LifecycleTest::_definedInPlugin);
} }

View File

@ -27,27 +27,26 @@ package hudson.model;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import hudson.XmlFile; import hudson.XmlFile;
import java.util.logging.Level; import java.util.logging.Level;
import org.junit.Rule; import org.junit.jupiter.api.Test;
import org.junit.Test; import org.junit.jupiter.api.extension.RegisterExtension;
import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsSessionRule; import org.jvnet.hudson.test.LogRecorder;
import org.jvnet.hudson.test.LoggerRule; import org.jvnet.hudson.test.junit.jupiter.JenkinsSessionExtension;
public class AbstractItem2Test { class AbstractItem2Test {
@Rule @RegisterExtension
public JenkinsSessionRule sessions = new JenkinsSessionRule(); private final JenkinsSessionExtension sessions = new JenkinsSessionExtension();
@Rule private final LogRecorder logging = new LogRecorder().record(XmlFile.class, Level.WARNING).capture(100);
public LoggerRule logging = new LoggerRule().record(XmlFile.class, Level.WARNING).capture(100);
@Issue("JENKINS-45892") @Issue("JENKINS-45892")
@Test @Test
public void badSerialization() throws Throwable { void badSerialization() throws Throwable {
sessions.then(j -> { sessions.then(j -> {
FreeStyleProject p1 = j.createFreeStyleProject("p1"); FreeStyleProject p1 = j.createFreeStyleProject("p1");
p1.setDescription("this is p1"); p1.setDescription("this is p1");

View File

@ -8,17 +8,24 @@ import static org.hamcrest.Matchers.lessThan;
import hudson.ExtensionList; import hudson.ExtensionList;
import java.time.Duration; import java.time.Duration;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.junit.Rule; import org.junit.jupiter.api.BeforeEach;
import org.junit.Test; import org.junit.jupiter.api.Test;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.TestExtension; import org.jvnet.hudson.test.TestExtension;
import org.jvnet.hudson.test.junit.jupiter.WithJenkins;
public class AsyncPeriodicWorkTest { @WithJenkins
@Rule class AsyncPeriodicWorkTest {
public JenkinsRule r = new JenkinsRule();
private JenkinsRule r;
@BeforeEach
void setUp(JenkinsRule rule) {
r = rule;
}
@Test @Test
public void extraCallGetsIgnored() { void extraCallGetsIgnored() {
var instance = ExtensionList.lookupSingleton(AsyncPeriodicWorkTestImpl.class); var instance = ExtensionList.lookupSingleton(AsyncPeriodicWorkTestImpl.class);
assertThat(instance.getCount(), is(0)); assertThat(instance.getCount(), is(0));
instance.run(); instance.run();
@ -29,7 +36,7 @@ public class AsyncPeriodicWorkTest {
} }
@Test @Test
public void extraCallGetsQueued() { void extraCallGetsQueued() {
var instance = ExtensionList.lookupSingleton(AsyncPeriodicWorkTestImpl.class); var instance = ExtensionList.lookupSingleton(AsyncPeriodicWorkTestImpl.class);
instance.setQueueIfAlreadyRunning(true); instance.setQueueIfAlreadyRunning(true);
assertThat(instance.getCount(), is(0)); assertThat(instance.getCount(), is(0));
@ -44,6 +51,7 @@ public class AsyncPeriodicWorkTest {
private boolean queueIfAlreadyRunning; private boolean queueIfAlreadyRunning;
private int count = 0; private int count = 0;
@SuppressWarnings(value = "checkstyle:redundantmodifier")
public AsyncPeriodicWorkTestImpl() { public AsyncPeriodicWorkTestImpl() {
super(AsyncPeriodicWorkTestImpl.class.getSimpleName()); super(AsyncPeriodicWorkTestImpl.class.getSimpleName());
} }

View File

@ -63,8 +63,8 @@ import org.htmlunit.Page;
import org.htmlunit.WebRequest; import org.htmlunit.WebRequest;
import org.htmlunit.html.HtmlForm; import org.htmlunit.html.HtmlForm;
import org.htmlunit.xml.XmlPage; import org.htmlunit.xml.XmlPage;
import org.junit.experimental.categories.Category;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
@ -73,11 +73,10 @@ import org.jvnet.hudson.test.LogRecorder;
import org.jvnet.hudson.test.MemoryAssert; import org.jvnet.hudson.test.MemoryAssert;
import org.jvnet.hudson.test.MockAuthorizationStrategy; import org.jvnet.hudson.test.MockAuthorizationStrategy;
import org.jvnet.hudson.test.MockFolder; import org.jvnet.hudson.test.MockFolder;
import org.jvnet.hudson.test.SmokeTest;
import org.jvnet.hudson.test.junit.jupiter.WithJenkins; import org.jvnet.hudson.test.junit.jupiter.WithJenkins;
import org.jvnet.hudson.test.recipes.LocalData; import org.jvnet.hudson.test.recipes.LocalData;
@Category(SmokeTest.class) @Tag("SmokeTest")
@WithJenkins @WithJenkins
class ComputerTest { class ComputerTest {

View File

@ -241,7 +241,7 @@ public class ExecutorTest {
} }
@Test @Test
public void recordCauseOfInterruption() throws Exception { void recordCauseOfInterruption() throws Exception {
FreeStyleProject p = j.createFreeStyleProject(); FreeStyleProject p = j.createFreeStyleProject();
p.getBuildersList().add(TestBuilder.of((build, launcher, listener) -> { p.getBuildersList().add(TestBuilder.of((build, launcher, listener) -> {
Executor exec = build.getExecutor(); Executor exec = build.getExecutor();

View File

@ -2,8 +2,8 @@ package hudson.model;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import hudson.Functions; import hudson.Functions;
import hudson.tasks.BatchFile; import hudson.tasks.BatchFile;
@ -15,32 +15,32 @@ import java.nio.file.Path;
import org.htmlunit.html.HtmlForm; import org.htmlunit.html.HtmlForm;
import org.htmlunit.html.HtmlInput; import org.htmlunit.html.HtmlInput;
import org.htmlunit.html.HtmlPage; import org.htmlunit.html.HtmlPage;
import org.junit.Rule; import org.junit.jupiter.api.Test;
import org.junit.Test; import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.rules.TemporaryFolder; import org.junit.jupiter.api.io.TempDir;
import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.JenkinsSessionRule; import org.jvnet.hudson.test.junit.jupiter.JenkinsSessionExtension;
public class FileParameterValuePersistenceTest { class FileParameterValuePersistenceTest {
private static final String FILENAME = "file.txt"; private static final String FILENAME = "file.txt";
private static final String CONTENTS = "foobar"; private static final String CONTENTS = "foobar";
@Rule @RegisterExtension
public JenkinsSessionRule sessions = new JenkinsSessionRule(); private final JenkinsSessionExtension sessions = new JenkinsSessionExtension();
@Rule @TempDir
public TemporaryFolder tmp = new TemporaryFolder(); private File tmp;
@Issue("JENKINS-13536") @Issue("JENKINS-13536")
@Test @Test
public void fileParameterValuePersistence() throws Throwable { void fileParameterValuePersistence() throws Throwable {
sessions.then(j -> { sessions.then(j -> {
FreeStyleProject p = j.createFreeStyleProject("p"); FreeStyleProject p = j.createFreeStyleProject("p");
p.addProperty(new ParametersDefinitionProperty(new FileParameterDefinition(FILENAME, "The file."))); p.addProperty(new ParametersDefinitionProperty(new FileParameterDefinition(FILENAME, "The file.")));
p.getBuildersList().add(Functions.isWindows() ? new BatchFile("type " + FILENAME) : new Shell("cat " + FILENAME)); p.getBuildersList().add(Functions.isWindows() ? new BatchFile("type " + FILENAME) : new Shell("cat " + FILENAME));
File test = tmp.newFile(); File test = File.createTempFile("junit", null, tmp);
Files.writeString(test.toPath(), CONTENTS, StandardCharsets.UTF_8); Files.writeString(test.toPath(), CONTENTS, StandardCharsets.UTF_8);
try (JenkinsRule.WebClient wc = j.createWebClient()) { try (JenkinsRule.WebClient wc = j.createWebClient()) {
// ParametersDefinitionProperty/index.jelly sends a 405 // ParametersDefinitionProperty/index.jelly sends a 405

View File

@ -28,12 +28,12 @@ import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.instanceOf;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.Assert.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.Assert.assertNull; import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.Assert.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import hudson.EnvVars; import hudson.EnvVars;
import hudson.FilePath; import hudson.FilePath;
@ -98,139 +98,149 @@ import org.htmlunit.html.HtmlElement;
import org.htmlunit.html.HtmlForm; import org.htmlunit.html.HtmlForm;
import org.htmlunit.html.HtmlPage; import org.htmlunit.html.HtmlPage;
import org.htmlunit.javascript.host.event.Event; import org.htmlunit.javascript.host.event.Event;
import org.junit.Ignore; import org.junit.jupiter.api.BeforeEach;
import org.junit.Rule; import org.junit.jupiter.api.Disabled;
import org.junit.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.jvnet.hudson.reactor.ReactorException; import org.jvnet.hudson.reactor.ReactorException;
import org.jvnet.hudson.test.FakeChangeLogSCM; import org.jvnet.hudson.test.FakeChangeLogSCM;
import org.jvnet.hudson.test.InboundAgentRule;
import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.TestBuilder; import org.jvnet.hudson.test.TestBuilder;
import org.jvnet.hudson.test.TestExtension; import org.jvnet.hudson.test.TestExtension;
import org.jvnet.hudson.test.junit.jupiter.InboundAgentExtension;
import org.jvnet.hudson.test.junit.jupiter.WithJenkins;
import org.kohsuke.stapler.StaplerRequest2; import org.kohsuke.stapler.StaplerRequest2;
/** /**
* *
* @author Lucie Votypkova * @author Lucie Votypkova
*/ */
@WithJenkins
public class ProjectTest { public class ProjectTest {
@Rule public JenkinsRule j = new JenkinsRule(); @RegisterExtension
private final InboundAgentExtension inboundAgents = new InboundAgentExtension();
@Rule public InboundAgentRule inboundAgents = new InboundAgentRule();
public static boolean createAction = false; public static boolean createAction = false;
public static boolean getFilePath = false; public static boolean getFilePath = false;
public static boolean createSubTask = false; public static boolean createSubTask = false;
private JenkinsRule j;
@BeforeEach
void setUp(JenkinsRule rule) {
j = rule;
}
@Test @Test
public void testSave() throws IOException, InterruptedException, ReactorException { void testSave() throws IOException, InterruptedException, ReactorException {
FreeStyleProject p = j.createFreeStyleProject("project"); FreeStyleProject p = j.createFreeStyleProject("project");
p.disabled = true; p.disabled = true;
p.nextBuildNumber = 5; p.nextBuildNumber = 5;
p.description = "description"; p.description = "description";
p.save(); p.save();
j.jenkins.reload(); j.jenkins.reload();
assertEquals("All persistent data should be saved.", "description", p.description); assertEquals("description", p.description, "All persistent data should be saved.");
assertEquals("All persistent data should be saved.", 5, p.nextBuildNumber); assertEquals(5, p.nextBuildNumber, "All persistent data should be saved.");
assertTrue("All persistent data should be saved", p.disabled); assertTrue(p.disabled, "All persistent data should be saved");
} }
@Test @Test
public void testOnCreateFromScratch() throws Exception { void testOnCreateFromScratch() throws Exception {
FreeStyleProject p = j.createFreeStyleProject("project"); FreeStyleProject p = j.createFreeStyleProject("project");
j.buildAndAssertSuccess(p); j.buildAndAssertSuccess(p);
p.removeRun(p.getLastBuild()); p.removeRun(p.getLastBuild());
createAction = true; createAction = true;
p.onCreatedFromScratch(); p.onCreatedFromScratch();
assertNotNull("Project should have last build.", p.getLastBuild()); assertNotNull(p.getLastBuild(), "Project should have last build.");
assertNotNull("Project should have transient action TransientAction.", p.getAction(TransientAction.class)); assertNotNull(p.getAction(TransientAction.class), "Project should have transient action TransientAction.");
createAction = false; createAction = false;
} }
@Test @Test
public void testOnLoad() throws Exception { void testOnLoad() throws Exception {
FreeStyleProject p = j.createFreeStyleProject("project"); FreeStyleProject p = j.createFreeStyleProject("project");
j.buildAndAssertSuccess(p); j.buildAndAssertSuccess(p);
p.removeRun(p.getLastBuild()); p.removeRun(p.getLastBuild());
createAction = true; createAction = true;
p.onLoad(j.jenkins, "project"); p.onLoad(j.jenkins, "project");
assertNotNull("Project should have a build.", p.getLastBuild()); assertNotNull(p.getLastBuild(), "Project should have a build.");
assertNotNull("Project should have a scm.", p.getScm()); assertNotNull(p.getScm(), "Project should have a scm.");
assertNotNull("Project should have Transient Action TransientAction.", p.getAction(TransientAction.class)); assertNotNull(p.getAction(TransientAction.class), "Project should have Transient Action TransientAction.");
createAction = false; createAction = false;
} }
@Test @Test
public void testGetEnvironment() throws Exception { void testGetEnvironment() throws Exception {
FreeStyleProject p = j.createFreeStyleProject("project"); FreeStyleProject p = j.createFreeStyleProject("project");
Slave slave = j.createOnlineSlave(); Slave slave = j.createOnlineSlave();
EnvironmentVariablesNodeProperty.Entry entry = new EnvironmentVariablesNodeProperty.Entry("jdk", "some_java"); EnvironmentVariablesNodeProperty.Entry entry = new EnvironmentVariablesNodeProperty.Entry("jdk", "some_java");
slave.getNodeProperties().add(new EnvironmentVariablesNodeProperty(entry)); slave.getNodeProperties().add(new EnvironmentVariablesNodeProperty(entry));
EnvVars var = p.getEnvironment(slave, TaskListener.NULL); EnvVars var = p.getEnvironment(slave, TaskListener.NULL);
assertEquals("Environment should have set jdk.", "some_java", var.get("jdk")); assertEquals("some_java", var.get("jdk"), "Environment should have set jdk.");
} }
@Test @Test
public void testPerformDelete() throws Exception { void testPerformDelete() throws Exception {
FreeStyleProject p = j.createFreeStyleProject("project"); FreeStyleProject p = j.createFreeStyleProject("project");
p.performDelete(); p.performDelete();
assertFalse("Project should be deleted from disk.", p.getConfigFile().exists()); assertFalse(p.getConfigFile().exists(), "Project should be deleted from disk.");
assertTrue("Project should be disabled when deleting start.", p.isDisabled()); assertTrue(p.isDisabled(), "Project should be disabled when deleting start.");
} }
@Test @Test
public void testGetAssignedLabel() throws Exception { void testGetAssignedLabel() throws Exception {
FreeStyleProject p = j.createFreeStyleProject("project"); FreeStyleProject p = j.createFreeStyleProject("project");
p.setAssignedLabel(j.jenkins.getSelfLabel()); p.setAssignedLabel(j.jenkins.getSelfLabel());
Slave slave = j.createOnlineSlave(); Slave slave = j.createOnlineSlave();
assertEquals("Project should have Jenkins's self label.", j.jenkins.getSelfLabel(), p.getAssignedLabel()); assertEquals(j.jenkins.getSelfLabel(), p.getAssignedLabel(), "Project should have Jenkins's self label.");
p.setAssignedLabel(null); p.setAssignedLabel(null);
assertNull("Project should not have any label.", p.getAssignedLabel()); assertNull(p.getAssignedLabel(), "Project should not have any label.");
p.setAssignedLabel(slave.getSelfLabel()); p.setAssignedLabel(slave.getSelfLabel());
assertEquals("Project should have self label of slave", slave.getSelfLabel(), p.getAssignedLabel()); assertEquals(slave.getSelfLabel(), p.getAssignedLabel(), "Project should have self label of slave");
} }
@Test @Test
public void testGetAssignedLabelString() throws Exception { void testGetAssignedLabelString() throws Exception {
FreeStyleProject p = j.createFreeStyleProject("project"); FreeStyleProject p = j.createFreeStyleProject("project");
Slave slave = j.createOnlineSlave(); Slave slave = j.createOnlineSlave();
assertNull("Project should not have any label.", p.getAssignedLabelString()); assertNull(p.getAssignedLabelString(), "Project should not have any label.");
p.setAssignedLabel(j.jenkins.getSelfLabel()); p.setAssignedLabel(j.jenkins.getSelfLabel());
assertNull("Project should return null, because assigned label is Jenkins.", p.getAssignedLabelString()); assertNull(p.getAssignedLabelString(), "Project should return null, because assigned label is Jenkins.");
p.setAssignedLabel(slave.getSelfLabel()); p.setAssignedLabel(slave.getSelfLabel());
assertEquals("Project should return name of slave.", slave.getSelfLabel().name, p.getAssignedLabelString()); assertEquals(slave.getSelfLabel().name, p.getAssignedLabelString(), "Project should return name of slave.");
} }
@Test @Test
public void testGetSomeWorkspace() throws Exception { void testGetSomeWorkspace() throws Exception {
FreeStyleProject p = j.createFreeStyleProject("project"); FreeStyleProject p = j.createFreeStyleProject("project");
assertNull("Project which has never run should not have any workspace.", p.getSomeWorkspace()); assertNull(p.getSomeWorkspace(), "Project which has never run should not have any workspace.");
getFilePath = true; getFilePath = true;
assertNotNull("Project should have any workspace because WorkspaceBrowser find some.", p.getSomeWorkspace()); assertNotNull(p.getSomeWorkspace(), "Project should have any workspace because WorkspaceBrowser find some.");
getFilePath = false; getFilePath = false;
String cmd = "echo ahoj > some.log"; String cmd = "echo ahoj > some.log";
p.getBuildersList().add(Functions.isWindows() ? new BatchFile(cmd) : new Shell(cmd)); p.getBuildersList().add(Functions.isWindows() ? new BatchFile(cmd) : new Shell(cmd));
j.buildAndAssertSuccess(p); j.buildAndAssertSuccess(p);
assertNotNull("Project should has any workspace.", p.getSomeWorkspace()); assertNotNull(p.getSomeWorkspace(), "Project should has any workspace.");
} }
@Test @Test
public void testGetSomeBuildWithWorkspace() throws Exception { void testGetSomeBuildWithWorkspace() throws Exception {
FreeStyleProject p = j.createFreeStyleProject("project"); FreeStyleProject p = j.createFreeStyleProject("project");
String cmd = "echo ahoj > some.log"; String cmd = "echo ahoj > some.log";
p.getBuildersList().add(Functions.isWindows() ? new BatchFile(cmd) : new Shell(cmd)); p.getBuildersList().add(Functions.isWindows() ? new BatchFile(cmd) : new Shell(cmd));
assertNull("Project which has never run should not have any build with workspace.", p.getSomeBuildWithWorkspace()); assertNull(p.getSomeBuildWithWorkspace(), "Project which has never run should not have any build with workspace.");
j.buildAndAssertSuccess(p); j.buildAndAssertSuccess(p);
assertEquals("Last build should have workspace.", p.getLastBuild(), p.getSomeBuildWithWorkspace()); assertEquals(p.getLastBuild(), p.getSomeBuildWithWorkspace(), "Last build should have workspace.");
p.getLastBuild().delete(); p.getLastBuild().delete();
assertNull("Project should not have build with some workspace.", p.getSomeBuildWithWorkspace()); assertNull(p.getSomeBuildWithWorkspace(), "Project should not have build with some workspace.");
} }
@Issue("JENKINS-10450") @Issue("JENKINS-10450")
@Test public void workspaceBrowsing() throws Exception { @Test
void workspaceBrowsing() throws Exception {
FreeStyleProject p = j.createFreeStyleProject("project"); FreeStyleProject p = j.createFreeStyleProject("project");
String cmd = "echo ahoj > some.log"; String cmd = "echo ahoj > some.log";
p.getBuildersList().add(Functions.isWindows() ? new BatchFile(cmd) : new Shell(cmd)); p.getBuildersList().add(Functions.isWindows() ? new BatchFile(cmd) : new Shell(cmd));
@ -243,83 +253,83 @@ public class ProjectTest {
} }
@Test @Test
public void testGetQuietPeriod() throws IOException { void testGetQuietPeriod() throws IOException {
FreeStyleProject p = j.createFreeStyleProject("project"); FreeStyleProject p = j.createFreeStyleProject("project");
assertEquals("Quiet period should be default.", j.jenkins.getQuietPeriod(), p.getQuietPeriod()); assertEquals(j.jenkins.getQuietPeriod(), p.getQuietPeriod(), "Quiet period should be default.");
j.jenkins.setQuietPeriod(0); j.jenkins.setQuietPeriod(0);
assertEquals("Quiet period is not set so it should be the same as global quiet period.", 0, p.getQuietPeriod()); assertEquals(0, p.getQuietPeriod(), "Quiet period is not set so it should be the same as global quiet period.");
p.setQuietPeriod(10); p.setQuietPeriod(10);
assertEquals("Quiet period was set.", 10, p.getQuietPeriod()); assertEquals(10, p.getQuietPeriod(), "Quiet period was set.");
} }
@Test @Test
public void testGetScmCheckoutStrategy() throws IOException { void testGetScmCheckoutStrategy() throws IOException {
FreeStyleProject p = j.createFreeStyleProject("project"); FreeStyleProject p = j.createFreeStyleProject("project");
p.setScmCheckoutStrategy(null); p.setScmCheckoutStrategy(null);
assertThat("Project should return default checkout strategy if scm checkout strategy is not set.", p.getScmCheckoutStrategy(), instanceOf(DefaultSCMCheckoutStrategyImpl.class)); assertThat("Project should return default checkout strategy if scm checkout strategy is not set.", p.getScmCheckoutStrategy(), instanceOf(DefaultSCMCheckoutStrategyImpl.class));
SCMCheckoutStrategy strategy = new SCMCheckoutStrategyImpl(); SCMCheckoutStrategy strategy = new SCMCheckoutStrategyImpl();
p.setScmCheckoutStrategy(strategy); p.setScmCheckoutStrategy(strategy);
assertEquals("Project should return its scm checkout strategy if this strategy is not null", strategy, p.getScmCheckoutStrategy()); assertEquals(strategy, p.getScmCheckoutStrategy(), "Project should return its scm checkout strategy if this strategy is not null");
} }
@Test @Test
public void testGetScmCheckoutRetryCount() throws Exception { void testGetScmCheckoutRetryCount() throws Exception {
FreeStyleProject p = j.createFreeStyleProject("project"); FreeStyleProject p = j.createFreeStyleProject("project");
assertEquals("Scm retry count should be default.", j.jenkins.getScmCheckoutRetryCount(), p.getScmCheckoutRetryCount()); assertEquals(j.jenkins.getScmCheckoutRetryCount(), p.getScmCheckoutRetryCount(), "Scm retry count should be default.");
j.jenkins.setScmCheckoutRetryCount(6); j.jenkins.setScmCheckoutRetryCount(6);
assertEquals("Scm retry count should be the same as global scm retry count.", 6, p.getScmCheckoutRetryCount()); assertEquals(6, p.getScmCheckoutRetryCount(), "Scm retry count should be the same as global scm retry count.");
HtmlForm form = j.createWebClient().goTo(p.getUrl() + "/configure").getFormByName("config"); HtmlForm form = j.createWebClient().goTo(p.getUrl() + "/configure").getFormByName("config");
((HtmlElement) form.querySelectorAll(".advancedButton").get(0)).click(); ((HtmlElement) form.querySelectorAll(".advancedButton").get(0)).click();
// required due to the new default behavior of click // required due to the new default behavior of click
form.getInputByName("hasCustomScmCheckoutRetryCount").click(new Event(), false, false, false, true); form.getInputByName("hasCustomScmCheckoutRetryCount").click(new Event(), false, false, false, true);
form.getInputByName("scmCheckoutRetryCount").setValue("7"); form.getInputByName("scmCheckoutRetryCount").setValue("7");
j.submit(form); j.submit(form);
assertEquals("Scm retry count was set.", 7, p.getScmCheckoutRetryCount()); assertEquals(7, p.getScmCheckoutRetryCount(), "Scm retry count was set.");
} }
@Test @Test
public void isBuildable() throws IOException { void isBuildable() throws IOException {
FreeStyleProject p = j.createFreeStyleProject("project"); FreeStyleProject p = j.createFreeStyleProject("project");
assertTrue("Project should be buildable.", p.isBuildable()); assertTrue(p.isBuildable(), "Project should be buildable.");
p.disable(); p.disable();
assertFalse("Project should not be buildable if it is disabled.", p.isBuildable()); assertFalse(p.isBuildable(), "Project should not be buildable if it is disabled.");
p.enable(); p.enable();
AbstractProject p2 = (AbstractProject) j.jenkins.copy(j.jenkins.getItem("project"), "project2"); AbstractProject p2 = (AbstractProject) j.jenkins.copy(j.jenkins.getItem("project"), "project2");
assertFalse("Project should not be buildable until is saved.", p2.isBuildable()); assertFalse(p2.isBuildable(), "Project should not be buildable until is saved.");
p2.save(); p2.save();
assertTrue("Project should be buildable after save.", p2.isBuildable()); assertTrue(p2.isBuildable(), "Project should be buildable after save.");
} }
@Test @Test
public void testMakeDisabled() throws IOException { void testMakeDisabled() throws IOException {
FreeStyleProject p = j.createFreeStyleProject("project"); FreeStyleProject p = j.createFreeStyleProject("project");
p.makeDisabled(false); p.makeDisabled(false);
assertFalse("Project should be enabled.", p.isDisabled()); assertFalse(p.isDisabled(), "Project should be enabled.");
p.makeDisabled(true); p.makeDisabled(true);
assertTrue("Project should be disabled.", p.isDisabled()); assertTrue(p.isDisabled(), "Project should be disabled.");
p.makeDisabled(false); p.makeDisabled(false);
p.setAssignedLabel(j.jenkins.getLabel("nonExist")); p.setAssignedLabel(j.jenkins.getLabel("nonExist"));
p.scheduleBuild2(0); p.scheduleBuild2(0);
p.makeDisabled(true); p.makeDisabled(true);
assertNull("Project should be canceled.", Queue.getInstance().getItem(p)); assertNull(Queue.getInstance().getItem(p), "Project should be canceled.");
} }
@Test @Test
public void testAddProperty() throws IOException { void testAddProperty() throws IOException {
FreeStyleProject p = j.createFreeStyleProject("project"); FreeStyleProject p = j.createFreeStyleProject("project");
JobProperty prop = new JobPropertyImp(); JobProperty prop = new JobPropertyImp();
createAction = true; createAction = true;
p.addProperty(prop); p.addProperty(prop);
assertNotNull("Project does not contain added property.", p.getProperty(prop.getClass())); assertNotNull(p.getProperty(prop.getClass()), "Project does not contain added property.");
assertNotNull("Project did not update transient actions.", p.getAction(TransientAction.class)); assertNotNull(p.getAction(TransientAction.class), "Project did not update transient actions.");
} }
@Test @Test
public void testScheduleBuild2() throws Exception { void testScheduleBuild2() throws Exception {
FreeStyleProject p = j.createFreeStyleProject("project"); FreeStyleProject p = j.createFreeStyleProject("project");
p.setAssignedLabel(j.jenkins.getLabel("nonExist")); p.setAssignedLabel(j.jenkins.getLabel("nonExist"));
p.scheduleBuild(0, new UserIdCause()); p.scheduleBuild(0, new UserIdCause());
assertNotNull("Project should be in queue.", Queue.getInstance().getItem(p)); assertNotNull(Queue.getInstance().getItem(p), "Project should be in queue.");
p.setAssignedLabel(null); p.setAssignedLabel(null);
int count = 0; int count = 0;
while (count < 5 && p.getLastBuild() == null) { while (count < 5 && p.getLastBuild() == null) {
@ -327,25 +337,25 @@ public class ProjectTest {
count++; count++;
} }
FreeStyleBuild b = p.getLastBuild(); FreeStyleBuild b = p.getLastBuild();
assertNotNull("Build should be done or in progress.", b); assertNotNull(b, "Build should be done or in progress.");
j.assertBuildStatusSuccess(j.waitForCompletion(b)); j.assertBuildStatusSuccess(j.waitForCompletion(b));
} }
@Test @Test
public void testSchedulePolling() throws IOException { void testSchedulePolling() throws IOException {
FreeStyleProject p = j.createFreeStyleProject("project"); FreeStyleProject p = j.createFreeStyleProject("project");
assertFalse("Project should not schedule polling because no scm trigger is set.", p.schedulePolling()); assertFalse(p.schedulePolling(), "Project should not schedule polling because no scm trigger is set.");
SCMTrigger trigger = new SCMTrigger("0 0 * * *"); SCMTrigger trigger = new SCMTrigger("0 0 * * *");
p.addTrigger(trigger); p.addTrigger(trigger);
trigger.start(p, true); trigger.start(p, true);
assertTrue("Project should schedule polling.", p.schedulePolling()); assertTrue(p.schedulePolling(), "Project should schedule polling.");
p.disable(); p.disable();
assertFalse("Project should not schedule polling because project is disabled.", p.schedulePolling()); assertFalse(p.schedulePolling(), "Project should not schedule polling because project is disabled.");
} }
@Test @Test
public void testSaveAfterSet() throws Exception { void testSaveAfterSet() throws Exception {
FreeStyleProject p = j.createFreeStyleProject("project"); FreeStyleProject p = j.createFreeStyleProject("project");
p.setScm(new NullSCM()); p.setScm(new NullSCM());
p.setScmCheckoutStrategy(new SCMCheckoutStrategyImpl()); p.setScmCheckoutStrategy(new SCMCheckoutStrategyImpl());
@ -357,21 +367,21 @@ public class ProjectTest {
p.setJDK(j.jenkins.getJDK("jdk")); p.setJDK(j.jenkins.getJDK("jdk"));
p.setCustomWorkspace("/some/path"); p.setCustomWorkspace("/some/path");
j.jenkins.reload(); j.jenkins.reload();
assertNotNull("Project did not save scm.", p.getScm()); assertNotNull(p.getScm(), "Project did not save scm.");
assertThat("Project did not save scm checkout strategy.", p.getScmCheckoutStrategy(), instanceOf(SCMCheckoutStrategyImpl.class)); assertThat("Project did not save scm checkout strategy.", p.getScmCheckoutStrategy(), instanceOf(SCMCheckoutStrategyImpl.class));
assertEquals("Project did not save quiet period.", 15, p.getQuietPeriod()); assertEquals(15, p.getQuietPeriod(), "Project did not save quiet period.");
assertTrue("Project did not save block if downstream is building.", p.blockBuildWhenDownstreamBuilding()); assertTrue(p.blockBuildWhenDownstreamBuilding(), "Project did not save block if downstream is building.");
assertTrue("Project did not save block if upstream is building.", p.blockBuildWhenUpstreamBuilding()); assertTrue(p.blockBuildWhenUpstreamBuilding(), "Project did not save block if upstream is building.");
assertNotNull("Project did not save jdk", p.getJDK()); assertNotNull(p.getJDK(), "Project did not save jdk");
assertEquals("Project did not save custom workspace.", "/some/path", p.getCustomWorkspace()); assertEquals("/some/path", p.getCustomWorkspace(), "Project did not save custom workspace.");
} }
@Test @Test
public void testGetActions() throws IOException { void testGetActions() throws IOException {
FreeStyleProject p = j.createFreeStyleProject("project"); FreeStyleProject p = j.createFreeStyleProject("project");
createAction = true; createAction = true;
p.updateTransientActions(); p.updateTransientActions();
assertNotNull("Action should contain transient actions too.", p.getAction(TransientAction.class)); assertNotNull(p.getAction(TransientAction.class), "Action should contain transient actions too.");
createAction = false; createAction = false;
} }
@ -381,7 +391,7 @@ public class ProjectTest {
// } // }
@Test @Test
public void testGetCauseOfBlockage() throws Exception { void testGetCauseOfBlockage() throws Exception {
FreeStyleProject p = j.createFreeStyleProject("project"); FreeStyleProject p = j.createFreeStyleProject("project");
p.getBuildersList().add(Functions.isWindows() ? new BatchFile("ping -n 10 127.0.0.1 >nul") : new Shell("sleep 10")); p.getBuildersList().add(Functions.isWindows() ? new BatchFile("ping -n 10 127.0.0.1 >nul") : new Shell("sleep 10"));
QueueTaskFuture<FreeStyleBuild> b1 = waitForStart(p); QueueTaskFuture<FreeStyleBuild> b1 = waitForStart(p);
@ -418,7 +428,7 @@ public class ProjectTest {
} }
@Test @Test
public void testGetSubTasks() throws IOException { void testGetSubTasks() throws IOException {
FreeStyleProject p = j.createFreeStyleProject("project"); FreeStyleProject p = j.createFreeStyleProject("project");
p.addProperty(new JobPropertyImp()); p.addProperty(new JobPropertyImp());
createSubTask = true; createSubTask = true;
@ -432,27 +442,27 @@ public class ProjectTest {
containsSubTaskImpl2 = true; containsSubTaskImpl2 = true;
} }
createSubTask = false; createSubTask = false;
assertTrue("Project should return subtasks provided by SubTaskContributor.", containsSubTaskImpl2); assertTrue(containsSubTaskImpl2, "Project should return subtasks provided by SubTaskContributor.");
assertTrue("Project should return subtasks provided by JobProperty.", containsSubTaskImpl); assertTrue(containsSubTaskImpl, "Project should return subtasks provided by JobProperty.");
} }
@Test @Test
public void testCreateExecutable() throws IOException { void testCreateExecutable() throws IOException {
FreeStyleProject p = j.createFreeStyleProject("project"); FreeStyleProject p = j.createFreeStyleProject("project");
Build build = p.createExecutable(); Build build = p.createExecutable();
assertNotNull("Project should create executable.", build); assertNotNull(build, "Project should create executable.");
assertEquals("CreatedExecutable should be the last build.", build, p.getLastBuild()); assertEquals(build, p.getLastBuild(), "CreatedExecutable should be the last build.");
assertEquals("Next build number should be increased.", 2, p.nextBuildNumber); assertEquals(2, p.nextBuildNumber, "Next build number should be increased.");
p.disable(); p.disable();
build = p.createExecutable(); build = p.createExecutable();
assertNull("Disabled project should not create executable.", build); assertNull(build, "Disabled project should not create executable.");
assertEquals("Next build number should not be increased.", 2, p.nextBuildNumber); assertEquals(2, p.nextBuildNumber, "Next build number should not be increased.");
} }
@Test @Test
public void testCheckout() throws Exception { void testCheckout() throws Exception {
SCM scm = new NullSCM(); SCM scm = new NullSCM();
FreeStyleProject p = j.createFreeStyleProject("project"); FreeStyleProject p = j.createFreeStyleProject("project");
Slave slave = j.createOnlineSlave(); Slave slave = j.createOnlineSlave();
@ -462,59 +472,59 @@ public class ProjectTest {
FilePath path = slave.toComputer().getWorkspaceList().allocate(ws, build).path; FilePath path = slave.toComputer().getWorkspaceList().allocate(ws, build).path;
build.setWorkspace(path); build.setWorkspace(path);
BuildListener listener = new StreamBuildListener(TaskListener.NULL.getLogger(), Charset.defaultCharset()); BuildListener listener = new StreamBuildListener(TaskListener.NULL.getLogger(), Charset.defaultCharset());
assertTrue("Project with null smc should perform checkout without problems.", p.checkout(build, new RemoteLauncher(listener, slave.getChannel(), true), listener, new File(build.getRootDir(), "changelog.xml"))); assertTrue(p.checkout(build, new RemoteLauncher(listener, slave.getChannel(), true), listener, new File(build.getRootDir(), "changelog.xml")), "Project with null smc should perform checkout without problems.");
p.setScm(scm); p.setScm(scm);
assertTrue("Project should perform checkout without problems.", p.checkout(build, new RemoteLauncher(listener, slave.getChannel(), true), listener, new File(build.getRootDir(), "changelog.xml"))); assertTrue(p.checkout(build, new RemoteLauncher(listener, slave.getChannel(), true), listener, new File(build.getRootDir(), "changelog.xml")), "Project should perform checkout without problems.");
} }
@Ignore("randomly failed: Project should have polling result no change expected:<NONE> but was:<INCOMPARABLE>") @Disabled("randomly failed: Project should have polling result no change expected:<NONE> but was:<INCOMPARABLE>")
@Test @Test
public void testPoll() throws Exception { void testPoll() throws Exception {
FreeStyleProject p = j.createFreeStyleProject("project"); FreeStyleProject p = j.createFreeStyleProject("project");
SCM scm = new NullSCM(); SCM scm = new NullSCM();
p.setScm(null); p.setScm(null);
assertEquals("Project with null scm should have have polling result no change.", PollingResult.Change.NONE, p.poll(TaskListener.NULL).change); assertEquals(PollingResult.Change.NONE, p.poll(TaskListener.NULL).change, "Project with null scm should have have polling result no change.");
p.setScm(scm); p.setScm(scm);
p.disable(); p.disable();
assertEquals("Project which is disabled should have have polling result no change.", PollingResult.Change.NONE, p.poll(TaskListener.NULL).change); assertEquals(PollingResult.Change.NONE, p.poll(TaskListener.NULL).change, "Project which is disabled should have have polling result no change.");
p.enable(); p.enable();
assertEquals("Project which has no builds should have have polling result incomparable.", PollingResult.Change.INCOMPARABLE, p.poll(TaskListener.NULL).change); assertEquals(PollingResult.Change.INCOMPARABLE, p.poll(TaskListener.NULL).change, "Project which has no builds should have have polling result incomparable.");
p.setAssignedLabel(j.jenkins.getLabel("nonExist")); p.setAssignedLabel(j.jenkins.getLabel("nonExist"));
p.scheduleBuild2(0); p.scheduleBuild2(0);
assertEquals("Project which build is building should have polling result result no change.", PollingResult.Change.NONE, p.poll(TaskListener.NULL).change); assertEquals(PollingResult.Change.NONE, p.poll(TaskListener.NULL).change, "Project which build is building should have polling result result no change.");
p.setAssignedLabel(null); p.setAssignedLabel(null);
while (p.getLastBuild() == null) while (p.getLastBuild() == null)
Thread.sleep(100); //wait until build start Thread.sleep(100); //wait until build start
assertEquals("Project should have polling result no change", PollingResult.Change.NONE, p.poll(TaskListener.NULL).change); assertEquals(PollingResult.Change.NONE, p.poll(TaskListener.NULL).change, "Project should have polling result no change");
SCM alwaysChange = new AlwaysChangedSCM(); SCM alwaysChange = new AlwaysChangedSCM();
p.setScm(alwaysChange); p.setScm(alwaysChange);
j.buildAndAssertSuccess(p); j.buildAndAssertSuccess(p);
assertEquals("Project should have polling result significant", PollingResult.Change.SIGNIFICANT, p.poll(TaskListener.NULL).change); assertEquals(PollingResult.Change.SIGNIFICANT, p.poll(TaskListener.NULL).change, "Project should have polling result significant");
} }
@Test @Test
public void testHasParticipant() throws Exception { void testHasParticipant() throws Exception {
User user = User.get("John Smith", true, Collections.emptyMap()); User user = User.get("John Smith", true, Collections.emptyMap());
FreeStyleProject project = j.createFreeStyleProject("project"); FreeStyleProject project = j.createFreeStyleProject("project");
FreeStyleProject project2 = j.createFreeStyleProject("project2"); FreeStyleProject project2 = j.createFreeStyleProject("project2");
FakeChangeLogSCM scm = new FakeChangeLogSCM(); FakeChangeLogSCM scm = new FakeChangeLogSCM();
project2.setScm(scm); project2.setScm(scm);
j.buildAndAssertSuccess(project2); j.buildAndAssertSuccess(project2);
assertFalse("Project should not have any participant.", project2.hasParticipant(user)); assertFalse(project2.hasParticipant(user), "Project should not have any participant.");
scm.addChange().withAuthor(user.getId()); scm.addChange().withAuthor(user.getId());
project.setScm(scm); project.setScm(scm);
j.buildAndAssertSuccess(project); j.buildAndAssertSuccess(project);
assertTrue("Project should have participant.", project.hasParticipant(user)); assertTrue(project.hasParticipant(user), "Project should have participant.");
} }
@Test @Test
public void testGetRelationship() throws Exception { void testGetRelationship() throws Exception {
final FreeStyleProject upstream = j.createFreeStyleProject("upstream"); final FreeStyleProject upstream = j.createFreeStyleProject("upstream");
FreeStyleProject downstream = j.createFreeStyleProject("downstream"); FreeStyleProject downstream = j.createFreeStyleProject("downstream");
j.buildAndAssertSuccess(upstream); j.buildAndAssertSuccess(upstream);
j.buildAndAssertSuccess(upstream); j.buildAndAssertSuccess(upstream);
j.buildAndAssertSuccess(downstream); j.buildAndAssertSuccess(downstream);
assertTrue("Project upstream should not have any relationship with downstream", upstream.getRelationship(downstream).isEmpty()); assertTrue(upstream.getRelationship(downstream).isEmpty(), "Project upstream should not have any relationship with downstream");
upstream.getPublishersList().add(new Fingerprinter("change.log", true)); upstream.getPublishersList().add(new Fingerprinter("change.log", true));
upstream.getBuildersList().add(new WorkspaceWriter("change.log", "hello")); upstream.getBuildersList().add(new WorkspaceWriter("change.log", "hello"));
@ -542,17 +552,17 @@ public class ProjectTest {
j.buildAndAssertSuccess(downstream); j.buildAndAssertSuccess(downstream);
Map<Integer, Fingerprint.RangeSet> relationship = upstream.getRelationship(downstream); Map<Integer, Fingerprint.RangeSet> relationship = upstream.getRelationship(downstream);
assertFalse("Project upstream should have relationship with downstream", relationship.isEmpty()); assertFalse(relationship.isEmpty(), "Project upstream should have relationship with downstream");
assertTrue("Relationship should contain upstream #3", relationship.containsKey(3)); assertTrue(relationship.containsKey(3), "Relationship should contain upstream #3");
assertFalse("Relationship should not contain upstream #4 because previous fingerprinted file was not changed since #3", relationship.containsKey(4)); assertFalse(relationship.containsKey(4), "Relationship should not contain upstream #4 because previous fingerprinted file was not changed since #3");
assertEquals("downstream #2 should be the first build which depends on upstream #3", 2, relationship.get(3).min()); assertEquals(2, relationship.get(3).min(), "downstream #2 should be the first build which depends on upstream #3");
assertEquals("downstream #3 should be the last build which depends on upstream #3", 3, relationship.get(3).max() - 1); assertEquals(3, relationship.get(3).max() - 1, "downstream #3 should be the last build which depends on upstream #3");
assertEquals("downstream #4 should depend only on upstream #5", 4, relationship.get(5).min()); assertEquals(4, relationship.get(5).min(), "downstream #4 should depend only on upstream #5");
assertEquals("downstream #4 should depend only on upstream #5", 4, relationship.get(5).max() - 1); assertEquals(4, relationship.get(5).max() - 1, "downstream #4 should depend only on upstream #5");
} }
@Test @Test
public void testDoCancelQueue() throws Exception { void testDoCancelQueue() throws Exception {
FreeStyleProject project = j.createFreeStyleProject("project"); FreeStyleProject project = j.createFreeStyleProject("project");
GlobalMatrixAuthorizationStrategy auth = new GlobalMatrixAuthorizationStrategy(); GlobalMatrixAuthorizationStrategy auth = new GlobalMatrixAuthorizationStrategy();
j.jenkins.setAuthorizationStrategy(auth); j.jenkins.setAuthorizationStrategy(auth);
@ -561,12 +571,12 @@ public class ProjectTest {
j.jenkins.setSecurityRealm(realm); j.jenkins.setSecurityRealm(realm);
User user = realm.createAccount("John Smith", "password"); User user = realm.createAccount("John Smith", "password");
try (ACLContext as = ACL.as(user)) { try (ACLContext as = ACL.as(user)) {
assertThrows("User should not have permission to build project", AccessDeniedException3.class, () -> project.doCancelQueue(null, null)); assertThrows(AccessDeniedException3.class, () -> project.doCancelQueue(null, null), "User should not have permission to build project");
} }
} }
@Test @Test
public void testDoDoDelete() throws Exception { void testDoDoDelete() throws Exception {
FreeStyleProject project = j.createFreeStyleProject("project"); FreeStyleProject project = j.createFreeStyleProject("project");
GlobalMatrixAuthorizationStrategy auth = new GlobalMatrixAuthorizationStrategy(); GlobalMatrixAuthorizationStrategy auth = new GlobalMatrixAuthorizationStrategy();
j.jenkins.setAuthorizationStrategy(auth); j.jenkins.setAuthorizationStrategy(auth);
@ -574,7 +584,7 @@ public class ProjectTest {
j.jenkins.setSecurityRealm(j.createDummySecurityRealm()); j.jenkins.setSecurityRealm(j.createDummySecurityRealm());
User user = User.getById("john", true); User user = User.getById("john", true);
try (ACLContext as = ACL.as(user)) { try (ACLContext as = ACL.as(user)) {
assertThrows("User should not have permission to build project", AccessDeniedException3.class, () -> project.doDoDelete((StaplerRequest2) null, null)); assertThrows(AccessDeniedException3.class, () -> project.doDoDelete((StaplerRequest2) null, null), "User should not have permission to build project");
} }
auth.add(Jenkins.READ, user.getId()); auth.add(Jenkins.READ, user.getId());
auth.add(Item.READ, user.getId()); auth.add(Item.READ, user.getId());
@ -591,12 +601,12 @@ public class ProjectTest {
j.submit(form); j.submit(form);
} }
} }
assertNull("Project should be deleted form memory.", j.jenkins.getItem(project.getDisplayName())); assertNull(j.jenkins.getItem(project.getDisplayName()), "Project should be deleted form memory.");
assertFalse("Project should be deleted form disk.", project.getRootDir().exists()); assertFalse(project.getRootDir().exists(), "Project should be deleted form disk.");
} }
@Test @Test
public void testDoDoWipeOutWorkspace() throws Exception { void testDoDoWipeOutWorkspace() throws Exception {
FreeStyleProject project = j.createFreeStyleProject("project"); FreeStyleProject project = j.createFreeStyleProject("project");
GlobalMatrixAuthorizationStrategy auth = new GlobalMatrixAuthorizationStrategy(); GlobalMatrixAuthorizationStrategy auth = new GlobalMatrixAuthorizationStrategy();
j.jenkins.setAuthorizationStrategy(auth); j.jenkins.setAuthorizationStrategy(auth);
@ -605,7 +615,7 @@ public class ProjectTest {
j.jenkins.setSecurityRealm(realm); j.jenkins.setSecurityRealm(realm);
User user = realm.createAccount("John Smith", "password"); User user = realm.createAccount("John Smith", "password");
try (ACLContext as = ACL.as(user)) { try (ACLContext as = ACL.as(user)) {
assertThrows("User should not have permission to build project", AccessDeniedException3.class, project::doDoWipeOutWorkspace); assertThrows(AccessDeniedException3.class, project::doDoWipeOutWorkspace, "User should not have permission to build project");
} }
auth.add(Item.READ, user.getId()); auth.add(Item.READ, user.getId());
auth.add(Item.BUILD, user.getId()); auth.add(Item.BUILD, user.getId());
@ -624,11 +634,11 @@ public class ProjectTest {
assertEquals(200, p.getWebResponse().getStatusCode()); assertEquals(200, p.getWebResponse().getStatusCode());
Thread.sleep(500); Thread.sleep(500);
assertFalse("Workspace should not exist.", project.getSomeWorkspace().exists()); assertFalse(project.getSomeWorkspace().exists(), "Workspace should not exist.");
} }
@Test @Test
public void testDoDisable() throws Exception { void testDoDisable() throws Exception {
FreeStyleProject project = j.createFreeStyleProject("project"); FreeStyleProject project = j.createFreeStyleProject("project");
GlobalMatrixAuthorizationStrategy auth = new GlobalMatrixAuthorizationStrategy(); GlobalMatrixAuthorizationStrategy auth = new GlobalMatrixAuthorizationStrategy();
j.jenkins.setAuthorizationStrategy(auth); j.jenkins.setAuthorizationStrategy(auth);
@ -637,7 +647,7 @@ public class ProjectTest {
j.jenkins.setSecurityRealm(realm); j.jenkins.setSecurityRealm(realm);
User user = realm.createAccount("John Smith", "password"); User user = realm.createAccount("John Smith", "password");
try (ACLContext as = ACL.as(user)) { try (ACLContext as = ACL.as(user)) {
assertThrows("User should not have permission to build project", AccessDeniedException3.class, project::doDisable); assertThrows(AccessDeniedException3.class, project::doDisable, "User should not have permission to build project");
} }
auth.add(Item.READ, user.getId()); auth.add(Item.READ, user.getId());
auth.add(Item.CONFIGURE, user.getId()); auth.add(Item.CONFIGURE, user.getId());
@ -651,11 +661,11 @@ public class ProjectTest {
form.getInputByName("enable").click(); form.getInputByName("enable").click();
j.submit(form); j.submit(form);
assertTrue("Project should be disabled.", project.isDisabled()); assertTrue(project.isDisabled(), "Project should be disabled.");
} }
@Test @Test
public void testDoEnable() throws Exception { void testDoEnable() throws Exception {
FreeStyleProject project = j.createFreeStyleProject("project"); FreeStyleProject project = j.createFreeStyleProject("project");
GlobalMatrixAuthorizationStrategy auth = new GlobalMatrixAuthorizationStrategy(); GlobalMatrixAuthorizationStrategy auth = new GlobalMatrixAuthorizationStrategy();
j.jenkins.setAuthorizationStrategy(auth); j.jenkins.setAuthorizationStrategy(auth);
@ -667,7 +677,7 @@ public class ProjectTest {
project.disable(); project.disable();
} }
try (ACLContext as = ACL.as(user)) { try (ACLContext as = ACL.as(user)) {
assertThrows("User should not have permission to build project", AccessDeniedException3.class, project::doEnable); assertThrows(AccessDeniedException3.class, project::doEnable, "User should not have permission to build project");
} }
auth.add(Item.READ, user.getId()); auth.add(Item.READ, user.getId());
auth.add(Item.CONFIGURE, user.getId()); auth.add(Item.CONFIGURE, user.getId());
@ -683,14 +693,14 @@ public class ProjectTest {
j.submit(form); j.submit(form);
} }
} }
assertFalse("Project should be enabled.", project.isDisabled()); assertFalse(project.isDisabled(), "Project should be enabled.");
} }
/** /**
* Job is un-restricted (no nabel), this is submitted to queue, which spawns an on demand slave * Job is un-restricted (no nabel), this is submitted to queue, which spawns an on demand slave
*/ */
@Test @Test
public void testJobSubmittedShouldSpawnCloud() throws Exception { void testJobSubmittedShouldSpawnCloud() throws Exception {
/* /*
* Setup a project with an SCM. Jenkins should have no executors in itself. * Setup a project with an SCM. Jenkins should have no executors in itself.
*/ */
@ -720,7 +730,7 @@ public class ProjectTest {
* Job is restricted, but label can not be provided by any cloud, only normal agents. Then job will not submit, because no slave is available. * Job is restricted, but label can not be provided by any cloud, only normal agents. Then job will not submit, because no slave is available.
*/ */
@Test @Test
public void testUnrestrictedJobNoLabelByCloudNoQueue() throws Exception { void testUnrestrictedJobNoLabelByCloudNoQueue() throws Exception {
assertTrue(j.jenkins.clouds.isEmpty()); assertTrue(j.jenkins.clouds.isEmpty());
//Create slave. (Online) //Create slave. (Online)
Slave s1 = j.createOnlineSlave(); Slave s1 = j.createOnlineSlave();
@ -737,7 +747,7 @@ public class ProjectTest {
//Now create another slave. And restrict the job to that slave. The slave is offline, leaving the job with no assignable nodes. //Now create another slave. And restrict the job to that slave. The slave is offline, leaving the job with no assignable nodes.
//We tell our mock SCM to return that it has got changes. But since there are no agents, we get the desired result. //We tell our mock SCM to return that it has got changes. But since there are no agents, we get the desired result.
Slave s2 = inboundAgents.createAgent(j, InboundAgentRule.Options.newBuilder().skipStart().build()); Slave s2 = inboundAgents.createAgent(j, InboundAgentExtension.Options.newBuilder().skipStart().build());
proj.setAssignedLabel(s2.getSelfLabel()); proj.setAssignedLabel(s2.getSelfLabel());
requiresWorkspaceScm.hasChange = true; requiresWorkspaceScm.hasChange = true;
@ -764,7 +774,7 @@ public class ProjectTest {
* Job is restricted. Label is on slave that can be started in cloud. Job is submitted to queue, which spawns an on demand slave. * Job is restricted. Label is on slave that can be started in cloud. Job is submitted to queue, which spawns an on demand slave.
*/ */
@Test @Test
public void testRestrictedLabelOnSlaveYesQueue() throws Exception { void testRestrictedLabelOnSlaveYesQueue() throws Exception {
FreeStyleProject proj = j.createFreeStyleProject("JENKINS-21394-yesqueue"); FreeStyleProject proj = j.createFreeStyleProject("JENKINS-21394-yesqueue");
RequiresWorkspaceSCM requiresWorkspaceScm = new RequiresWorkspaceSCM(true); RequiresWorkspaceSCM requiresWorkspaceScm = new RequiresWorkspaceSCM(true);
proj.setScm(requiresWorkspaceScm); proj.setScm(requiresWorkspaceScm);
@ -791,7 +801,7 @@ public class ProjectTest {
@Issue("JENKINS-22750") @Issue("JENKINS-22750")
@Test @Test
public void testMasterJobPutInQueue() throws Exception { void testMasterJobPutInQueue() throws Exception {
FreeStyleProject proj = j.createFreeStyleProject("JENKINS-21394-yes-master-queue"); FreeStyleProject proj = j.createFreeStyleProject("JENKINS-21394-yes-master-queue");
RequiresWorkspaceSCM requiresWorkspaceScm = new RequiresWorkspaceSCM(true); RequiresWorkspaceSCM requiresWorkspaceScm = new RequiresWorkspaceSCM(true);
proj.setAssignedLabel(null); proj.setAssignedLabel(null);
@ -955,7 +965,7 @@ public class ProjectTest {
} }
public class ActionImpl extends InvisibleAction{ public static class ActionImpl extends InvisibleAction {
} }

View File

@ -1,57 +1,66 @@
package hudson.model; package hudson.model;
import static org.junit.Assert.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import hudson.ExtensionList; import hudson.ExtensionList;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.junit.Rule; import org.junit.jupiter.api.BeforeEach;
import org.junit.Test; import org.junit.jupiter.api.Test;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.RestartableJenkinsRule; import org.jvnet.hudson.test.junit.jupiter.WithJenkins;
public class QueueCrashTest { @WithJenkins
class QueueCrashTest {
private JenkinsRule j;
@BeforeEach
void setUp(JenkinsRule rule) {
j = rule;
}
@Rule public RestartableJenkinsRule rr = new RestartableJenkinsRule();
@Test @Test
public void persistQueueOnCrash() { void persistQueueOnCrash() throws Throwable {
rr.thenWithHardShutdown(j -> { // Speed up the test run by shortening the periodic save interval from 60 seconds to 5
// Speed up the test run by shortening the periodic save interval from 60 seconds to 5 // seconds.
// seconds. Queue.Saver.DELAY_SECONDS = 5;
Queue.Saver.DELAY_SECONDS = 5;
scheduleSomeBuild(j); scheduleSomeBuild(j);
assertBuildIsScheduled(j); assertBuildIsScheduled(j);
// Wait for the periodic save to complete. // Wait for the periodic save to complete.
ExtensionList.lookupSingleton(Queue.Saver.class) ExtensionList.lookupSingleton(Queue.Saver.class)
.getNextSave() .getNextSave()
.get(30, TimeUnit.SECONDS); .get(30, TimeUnit.SECONDS);
// Ensure the periodic save process saved the queue, since the cleanup process will not // Ensure the periodic save process saved the queue, since the cleanup process will not
// run on a crash. // run on a crash.
assertTrue(new File(j.jenkins.getRootDir(), "queue.xml").exists()); assertTrue(new File(j.jenkins.getRootDir(), "queue.xml").exists());
});
rr.then(QueueCrashTest::assertBuildIsScheduled); j.restart();
assertBuildIsScheduled(j);
} }
@Test @Test
public void doNotPersistQueueOnCrashBeforeSave() { void doNotPersistQueueOnCrashBeforeSave() throws Throwable {
rr.thenWithHardShutdown(j -> { // Avoid periodic save in order to simulate the scenario of a crash before initial save.
// Avoid periodic save in order to simulate the scenario of a crash before initial save. Queue.Saver.DELAY_SECONDS = (int) TimeUnit.DAYS.toSeconds(1);
Queue.Saver.DELAY_SECONDS = (int) TimeUnit.DAYS.toSeconds(1);
scheduleSomeBuild(j); scheduleSomeBuild(j);
assertBuildIsScheduled(j); assertBuildIsScheduled(j);
// Ensure the queue has not been saved in order to test that a crash in this scenario // Ensure the queue has not been saved in order to test that a crash in this scenario
// results in the queue being lost. // results in the queue being lost.
assertFalse(new File(j.jenkins.getRootDir(), "queue.xml").exists()); assertFalse(new File(j.jenkins.getRootDir(), "queue.xml").exists());
});
rr.then(QueueCrashTest::assertBuildIsNotScheduled); j.restart();
assertBuildIsNotScheduled(j);
} }
private static void assertBuildIsScheduled(JenkinsRule j) { private static void assertBuildIsScheduled(JenkinsRule j) {

View File

@ -24,28 +24,29 @@
package hudson.model; package hudson.model;
import static org.junit.Assert.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.junit.Ignore; import org.junit.jupiter.api.Disabled;
import org.junit.Rule; import org.junit.jupiter.api.Test;
import org.junit.Test; import org.junit.jupiter.api.extension.RegisterExtension;
import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.RealJenkinsRule; import org.jvnet.hudson.test.junit.jupiter.RealJenkinsExtension;
import org.jvnet.hudson.test.recipes.LocalData; import org.jvnet.hudson.test.recipes.LocalData;
public class QueueRestartTest { class QueueRestartTest {
@Rule public RealJenkinsRule rr = new RealJenkinsRule(); @RegisterExtension
private final RealJenkinsExtension rr = new RealJenkinsExtension();
@Ignore("Pending JENKINS-68319 sometimes fails, in CI & locally") @Disabled("Pending JENKINS-68319 sometimes fails, in CI & locally")
@Issue("JENKINS-68319") @Issue("JENKINS-68319")
@LocalData("quietDown") @LocalData("quietDown")
@Test @Test
public void persistQueueOnRestart() throws Throwable { void persistQueueOnRestart() throws Throwable {
// Avoid periodic save in order to test that the cleanup process saves the queue. // Avoid periodic save in order to test that the cleanup process saves the queue.
rr.javaOptions("-Dhudson.model.Queue.Saver.DELAY_SECONDS=" + TimeUnit.DAYS.toSeconds(1)); rr.javaOptions("-Dhudson.model.Queue.Saver.DELAY_SECONDS=" + TimeUnit.DAYS.toSeconds(1));
@ -53,11 +54,11 @@ public class QueueRestartTest {
rr.then(QueueRestartTest::assertBuildFinishes); rr.then(QueueRestartTest::assertBuildFinishes);
} }
@Ignore("Pending JENKINS-68319 sometimes fails, in CI & locally") @Disabled("Pending JENKINS-68319 sometimes fails, in CI & locally")
@Issue("JENKINS-68319") @Issue("JENKINS-68319")
@LocalData("quietDown") @LocalData("quietDown")
@Test @Test
public void persistQueueOnConsecutiveRestarts() throws Throwable { void persistQueueOnConsecutiveRestarts() throws Throwable {
// Avoid periodic save in order to test that the cleanup process saves the queue. // Avoid periodic save in order to test that the cleanup process saves the queue.
rr.javaOptions("-Dhudson.model.Queue.Saver.DELAY_SECONDS=" + TimeUnit.DAYS.toSeconds(1)); rr.javaOptions("-Dhudson.model.Queue.Saver.DELAY_SECONDS=" + TimeUnit.DAYS.toSeconds(1));

View File

@ -27,23 +27,23 @@ package hudson.model;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import hudson.XmlFile; import hudson.XmlFile;
import java.io.File; import java.io.File;
import org.junit.Rule; import org.junit.jupiter.api.Test;
import org.junit.Test; import org.junit.jupiter.api.extension.RegisterExtension;
import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsSessionRule; import org.jvnet.hudson.test.junit.jupiter.JenkinsSessionExtension;
public class RunActionTest { class RunActionTest {
@Rule @RegisterExtension
public JenkinsSessionRule sessions = new JenkinsSessionRule(); private final JenkinsSessionExtension sessions = new JenkinsSessionExtension();
@Issue("JENKINS-45892") @Issue("JENKINS-45892")
@Test @Test
public void badSerialization() throws Throwable { void badSerialization() throws Throwable {
sessions.then(j -> { sessions.then(j -> {
FreeStyleProject p = j.createFreeStyleProject("p"); FreeStyleProject p = j.createFreeStyleProject("p");
FreeStyleBuild b1 = j.buildAndAssertSuccess(p); FreeStyleBuild b1 = j.buildAndAssertSuccess(p);

View File

@ -29,62 +29,110 @@ import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.instanceOf;
import jakarta.servlet.ServletContext; import jakarta.servlet.ServletContext;
import org.junit.Rule; import java.io.File;
import org.junit.Test; import java.lang.reflect.Method;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.junit.jupiter.JenkinsSessionExtension;
/** /**
* Tests of the custom {@link UpdateCenter} implementation. * Tests of the custom {@link UpdateCenter} implementation.
*/ */
public class UpdateCenterCustomTest { class UpdateCenterCustomTest {
@Rule @RegisterExtension
public final JenkinsRule j = new CustomUpdateCenterRule(CustomUpdateCenter.class); private final JenkinsSessionExtension session = new CustomUpdateCenterExtension(CustomUpdateCenterExtension.CustomUpdateCenter.class);
@Test @Test
public void shouldStartupWithCustomUpdateCenter() { void shouldStartupWithCustomUpdateCenter() throws Throwable {
UpdateCenter uc = j.jenkins.getUpdateCenter(); session.then(j -> {
assertThat("Update Center must be a custom instance", uc, instanceOf(CustomUpdateCenter.class)); UpdateCenter uc = j.jenkins.getUpdateCenter();
assertThat("Update Center must be a custom instance", uc, instanceOf(CustomUpdateCenterExtension.CustomUpdateCenter.class));
});
} }
// TODO: move to Jenkins Test Harness // TODO: move to Jenkins Test Harness
private static final class CustomUpdateCenterRule extends JenkinsRule { private static final class CustomUpdateCenterExtension extends JenkinsSessionExtension {
private int port;
private Description description;
private final String updateCenterClassName; private final String updateCenterClassName;
private String _oldValue = null;
private static final String PROPERTY_NAME = UpdateCenter.class.getName() + ".className"; CustomUpdateCenterExtension(Class<?> ucClass) {
CustomUpdateCenterRule(Class<?> ucClass) {
this.updateCenterClassName = ucClass.getName(); this.updateCenterClassName = ucClass.getName();
} }
@Override @Override
protected ServletContext createWebServer2() throws Exception { public void beforeEach(ExtensionContext context) {
_oldValue = System.getProperty(PROPERTY_NAME); super.beforeEach(context);
System.setProperty(PROPERTY_NAME, updateCenterClassName); description = Description.createTestDescription(
return super.createWebServer2(); context.getTestClass().map(Class::getName).orElse(null),
context.getTestMethod().map(Method::getName).orElse(null),
context.getTestMethod().map(Method::getAnnotations).orElse(null));
} }
@Override @Override
public void after() { public void then(Step s) throws Throwable {
if (_oldValue != null) { CustomJenkinsRule r = new CustomJenkinsRule(updateCenterClassName, getHome(), port);
System.setProperty(PROPERTY_NAME, _oldValue); r.apply(
new Statement() {
@Override
public void evaluate() throws Throwable {
port = r.getPort();
s.run(r);
}
},
description
).evaluate();
}
private static final class CustomJenkinsRule extends JenkinsRule {
private final String updateCenterClassName;
private String _oldValue = null;
private static final String PROPERTY_NAME = UpdateCenter.class.getName() + ".className";
CustomJenkinsRule(final String updateCenterClassName, File home, int port) {
this.updateCenterClassName = updateCenterClassName;
with(() -> home);
localPort = port;
}
int getPort() {
return localPort;
}
@Override
protected ServletContext createWebServer2() throws Exception {
_oldValue = System.getProperty(PROPERTY_NAME);
System.setProperty(PROPERTY_NAME, updateCenterClassName);
return super.createWebServer2();
}
@Override
public void after() {
if (_oldValue != null) {
System.setProperty(PROPERTY_NAME, _oldValue);
}
} }
} }
public String getUpdateCenterClassName() { public static final class CustomUpdateCenter extends UpdateCenter {
return updateCenterClassName;
@SuppressWarnings("checkstyle:redundantmodifier")
public CustomUpdateCenter() {
}
@SuppressWarnings("checkstyle:redundantmodifier")
public CustomUpdateCenter(UpdateCenterConfiguration config) {
super(config);
}
} }
} }
public static final class CustomUpdateCenter extends UpdateCenter {
public CustomUpdateCenter() {
}
public CustomUpdateCenter(UpdateCenterConfiguration config) {
super(config);
}
}
} }

View File

@ -1,35 +1,85 @@
package hudson.model; package hudson.model;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
import org.junit.Rule; import java.io.File;
import org.junit.Test; import java.lang.reflect.Method;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.junit.jupiter.JenkinsSessionExtension;
import org.jvnet.hudson.test.recipes.LocalData; import org.jvnet.hudson.test.recipes.LocalData;
public class UpdateCenterMigrationTest { class UpdateCenterMigrationTest {
@Rule @RegisterExtension
public JenkinsRule j = new JenkinsRule() { private final JenkinsSessionExtension session = new CustomUpdateCenterExtension();
@Override
protected void configureUpdateCenter() {
// Avoid reverse proxy
DownloadService.neverUpdate = true;
UpdateSite.neverUpdate = true;
}
};
@Issue("JENKINS-73760") @Issue("JENKINS-73760")
@LocalData @LocalData
@Test @Test
public void updateCenterMigration() { void updateCenterMigration() throws Throwable {
UpdateSite site = j.jenkins.getUpdateCenter().getSites().stream() session.then(j -> {
.filter(s -> UpdateCenter.PREDEFINED_UPDATE_SITE_ID.equals(s.getId())) UpdateSite site = j.jenkins.getUpdateCenter().getSites().stream()
.findFirst() .filter(s -> UpdateCenter.PREDEFINED_UPDATE_SITE_ID.equals(s.getId()))
.orElseThrow(); .findFirst()
assertFalse(site.isLegacyDefault()); .orElseThrow();
assertEquals(j.jenkins.getUpdateCenter().getDefaultBaseUrl() + "update-center.json", site.getUrl()); assertFalse(site.isLegacyDefault());
assertEquals(j.jenkins.getUpdateCenter().getDefaultBaseUrl() + "update-center.json", site.getUrl());
});
}
private static final class CustomUpdateCenterExtension extends JenkinsSessionExtension {
private int port;
private Description description;
@Override
public void beforeEach(ExtensionContext context) {
super.beforeEach(context);
description = Description.createTestDescription(
context.getTestClass().map(Class::getName).orElse(null),
context.getTestMethod().map(Method::getName).orElse(null),
context.getTestMethod().map(Method::getAnnotations).orElse(null));
}
@Override
public void then(Step s) throws Throwable {
CustomJenkinsRule r = new CustomJenkinsRule(getHome(), port);
r.apply(
new Statement() {
@Override
public void evaluate() throws Throwable {
port = r.getPort();
s.run(r);
}
},
description
).evaluate();
}
private static final class CustomJenkinsRule extends JenkinsRule {
CustomJenkinsRule(File home, int port) {
with(() -> home);
localPort = port;
}
int getPort() {
return localPort;
}
@Override
protected void configureUpdateCenter() {
// Avoid reverse proxy
DownloadService.neverUpdate = true;
UpdateSite.neverUpdate = true;
}
}
} }
} }

View File

@ -28,8 +28,8 @@ import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import hudson.FilePath; import hudson.FilePath;
import hudson.tasks.Mailer; import hudson.tasks.Mailer;
@ -37,18 +37,19 @@ import java.net.URI;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Base64; import java.util.Base64;
import org.htmlunit.WebRequest; import org.htmlunit.WebRequest;
import org.junit.Rule; import org.junit.jupiter.api.Test;
import org.junit.Test; import org.junit.jupiter.api.extension.RegisterExtension;
import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.JenkinsSessionRule; import org.jvnet.hudson.test.junit.jupiter.JenkinsSessionExtension;
public class UserRestartTest { class UserRestartTest {
@Rule @RegisterExtension
public JenkinsSessionRule sessions = new JenkinsSessionRule(); private final JenkinsSessionExtension sessions = new JenkinsSessionExtension();
@Test public void persistedUsers() throws Throwable { @Test
void persistedUsers() throws Throwable {
sessions.then(r -> { sessions.then(r -> {
User bob = User.getById("bob", true); User bob = User.getById("bob", true);
bob.setFullName("Bob"); bob.setFullName("Bob");
@ -66,7 +67,7 @@ public class UserRestartTest {
@Issue("JENKINS-45892") @Issue("JENKINS-45892")
@Test @Test
public void badSerialization() throws Throwable { void badSerialization() throws Throwable {
sessions.then(r -> { sessions.then(r -> {
r.jenkins.setSecurityRealm(r.createDummySecurityRealm()); r.jenkins.setSecurityRealm(r.createDummySecurityRealm());
FreeStyleProject p = r.createFreeStyleProject("p"); FreeStyleProject p = r.createFreeStyleProject("p");
@ -103,7 +104,7 @@ public class UserRestartTest {
@Test @Test
@Issue("SECURITY-897") @Issue("SECURITY-897")
public void legacyConfigMoveCannotEscapeUserFolder() throws Throwable { void legacyConfigMoveCannotEscapeUserFolder() throws Throwable {
sessions.then(r -> { sessions.then(r -> {
r.jenkins.setSecurityRealm(r.createDummySecurityRealm()); r.jenkins.setSecurityRealm(r.createDummySecurityRealm());
assertThat(r.jenkins.isUseSecurity(), equalTo(true)); assertThat(r.jenkins.isUseSecurity(), equalTo(true));

View File

@ -1,9 +1,9 @@
package hudson.node_monitors; package hudson.node_monitors;
import static org.awaitility.Awaitility.await; import static org.awaitility.Awaitility.await;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.Assert.assertNull; import static org.junit.jupiter.api.Assertions.assertNull;
import hudson.model.Computer; import hudson.model.Computer;
import hudson.model.ComputerSet; import hudson.model.ComputerSet;
@ -14,29 +14,36 @@ import hudson.slaves.OfflineCause;
import hudson.slaves.SlaveComputer; import hudson.slaves.SlaveComputer;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.junit.Rule; import org.junit.jupiter.api.BeforeEach;
import org.junit.Test; import org.junit.jupiter.api.Test;
import org.jvnet.hudson.test.InboundAgentRule; import org.junit.jupiter.api.extension.RegisterExtension;
import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.junit.jupiter.InboundAgentExtension;
import org.jvnet.hudson.test.junit.jupiter.WithJenkins;
/** /**
* @author Andrew Bayer * @author Andrew Bayer
*/ */
public class ResponseTimeMonitorTest { @WithJenkins
class ResponseTimeMonitorTest {
@Rule @RegisterExtension
public JenkinsRule j = new JenkinsRule(); private final InboundAgentExtension inboundAgents = new InboundAgentExtension();
@Rule private JenkinsRule j;
public InboundAgentRule inboundAgents = new InboundAgentRule();
@BeforeEach
void setUp(JenkinsRule rule) {
j = rule;
}
/** /**
* Makes sure that it doesn't try to monitor an already-offline agent. * Makes sure that it doesn't try to monitor an already-offline agent.
*/ */
@Test @Test
@Issue("JENKINS-20272") @Issue("JENKINS-20272")
public void skipOfflineAgent() throws Exception { void skipOfflineAgent() throws Exception {
DumbSlave s = j.createSlave(); DumbSlave s = j.createSlave();
SlaveComputer c = s.getComputer(); SlaveComputer c = s.getComputer();
c.connect(false).get(); // wait until it's connected c.connect(false).get(); // wait until it's connected
@ -64,8 +71,8 @@ public class ResponseTimeMonitorTest {
} }
@Test @Test
public void doNotDisconnectBeforeLaunched() throws Exception { void doNotDisconnectBeforeLaunched() throws Exception {
Slave slave = inboundAgents.createAgent(j, InboundAgentRule.Options.newBuilder().skipStart().build()); Slave slave = inboundAgents.createAgent(j, InboundAgentExtension.Options.newBuilder().skipStart().build());
Computer c = slave.toComputer(); Computer c = slave.toComputer();
assertNotNull(c); assertNotNull(c);
OfflineCause originalOfflineCause = c.getOfflineCause(); OfflineCause originalOfflineCause = c.getOfflineCause();

View File

@ -29,7 +29,7 @@ import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.startsWith; import static org.hamcrest.Matchers.startsWith;
import static org.junit.Assert.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import hudson.logging.LogRecorder; import hudson.logging.LogRecorder;
import hudson.logging.LogRecorderManager; import hudson.logging.LogRecorderManager;
@ -45,29 +45,28 @@ import org.htmlunit.FailingHttpStatusCodeException;
import org.htmlunit.html.HtmlForm; import org.htmlunit.html.HtmlForm;
import org.htmlunit.html.HtmlPage; import org.htmlunit.html.HtmlPage;
import org.htmlunit.html.HtmlPasswordInput; import org.htmlunit.html.HtmlPasswordInput;
import org.junit.Rule; import org.junit.jupiter.api.Test;
import org.junit.Test; import org.junit.jupiter.api.extension.RegisterExtension;
import org.jvnet.hudson.test.For; import org.jvnet.hudson.test.For;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.JenkinsRule.WebClient; import org.jvnet.hudson.test.JenkinsRule.WebClient;
import org.jvnet.hudson.test.RealJenkinsRule; import org.jvnet.hudson.test.junit.jupiter.RealJenkinsExtension;
import org.jvnet.hudson.test.recipes.LocalData; import org.jvnet.hudson.test.recipes.LocalData;
@For(HudsonPrivateSecurityRealm.class) @For(HudsonPrivateSecurityRealm.class)
public class HudsonPrivateSecurityRealmFIPSTest { class HudsonPrivateSecurityRealmFIPSTest {
// the bcrypt encoded form of "passwordpassword" without the quotes // the bcrypt encoded form of "passwordpassword" without the quotes
private static final String JBCRYPT_ENCODED_PASSWORD = "#jbcrypt:$2a$10$Nm37vwdZwJ5T2QTBwYuBYONHD3qKilgd5UO7wuDXI83z5dAdrgi4i"; private static final String JBCRYPT_ENCODED_PASSWORD = "#jbcrypt:$2a$10$Nm37vwdZwJ5T2QTBwYuBYONHD3qKilgd5UO7wuDXI83z5dAdrgi4i";
private static final String LOG_RECORDER_NAME = "HPSR_LOG_RECORDER"; private static final String LOG_RECORDER_NAME = "HPSR_LOG_RECORDER";
@Rule @RegisterExtension
public RealJenkinsRule rjr = new RealJenkinsRule().includeTestClasspathPlugins(false) private final RealJenkinsExtension rjr = new RealJenkinsExtension().includeTestClasspathPlugins(false)
.javaOptions("-Xmx256M", "-Djenkins.security.FIPS140.COMPLIANCE=true"); .javaOptions("-Xmx256M", "-Djenkins.security.FIPS140.COMPLIANCE=true");
@Test @Test
public void generalLogin() throws Throwable { void generalLogin() throws Throwable {
rjr.then(HudsonPrivateSecurityRealmFIPSTest::generalLoginStep); rjr.then(HudsonPrivateSecurityRealmFIPSTest::generalLoginStep);
} }
@ -90,7 +89,7 @@ public class HudsonPrivateSecurityRealmFIPSTest {
} }
@Test @Test
public void userCreationWithHashedPasswords() throws Throwable { void userCreationWithHashedPasswords() throws Throwable {
rjr.then(HudsonPrivateSecurityRealmFIPSTest::userCreationWithHashedPasswordsStep); rjr.then(HudsonPrivateSecurityRealmFIPSTest::userCreationWithHashedPasswordsStep);
} }
@ -112,11 +111,11 @@ public class HudsonPrivateSecurityRealmFIPSTest {
@Test @Test
@LocalData @LocalData
public void userLoginAfterEnablingFIPS() throws Throwable { void userLoginAfterEnablingFIPS() throws Throwable {
rjr.then(HudsonPrivateSecurityRealmFIPSTest::userLoginAfterEnablingFIPSStep); rjr.then(HudsonPrivateSecurityRealmFIPSTest::userLoginAfterEnablingFIPSStep);
} }
private static void userLoginAfterEnablingFIPSStep(JenkinsRule j) throws Exception { private static void userLoginAfterEnablingFIPSStep(JenkinsRule j) {
setupLogRecorder(); setupLogRecorder();
HudsonPrivateSecurityRealm securityRealm = new HudsonPrivateSecurityRealm(false, false, null); HudsonPrivateSecurityRealm securityRealm = new HudsonPrivateSecurityRealm(false, false, null);
j.jenkins.setSecurityRealm(securityRealm); j.jenkins.setSecurityRealm(securityRealm);
@ -130,12 +129,12 @@ public class HudsonPrivateSecurityRealmFIPSTest {
} }
@Test @Test
public void userCreationWithJBCryptPasswords() throws Throwable { void userCreationWithJBCryptPasswords() throws Throwable {
rjr.then(HudsonPrivateSecurityRealmFIPSTest::userCreationWithJBCryptPasswordsStep); rjr.then(HudsonPrivateSecurityRealmFIPSTest::userCreationWithJBCryptPasswordsStep);
} }
private static void userCreationWithJBCryptPasswordsStep(JenkinsRule j) throws Exception { private static void userCreationWithJBCryptPasswordsStep(JenkinsRule j) {
HudsonPrivateSecurityRealm securityRealm = new HudsonPrivateSecurityRealm(false, false, null); HudsonPrivateSecurityRealm securityRealm = new HudsonPrivateSecurityRealm(false, false, null);
IllegalArgumentException illegalArgumentException = assertThrows(IllegalArgumentException.class, IllegalArgumentException illegalArgumentException = assertThrows(IllegalArgumentException.class,
@ -145,7 +144,7 @@ public class HudsonPrivateSecurityRealmFIPSTest {
} }
@Test @Test
public void validatePasswordLengthForFIPS() throws Throwable { void validatePasswordLengthForFIPS() throws Throwable {
rjr.then(HudsonPrivateSecurityRealmFIPSTest::validatePasswordLengthForFIPSStep); rjr.then(HudsonPrivateSecurityRealmFIPSTest::validatePasswordLengthForFIPSStep);
} }
@ -166,13 +165,12 @@ public class HudsonPrivateSecurityRealmFIPSTest {
password2.setText("mockPassword"); password2.setText("mockPassword");
HtmlForm form = configurePage.getFormByName("config"); HtmlForm form = configurePage.getFormByName("config");
assertThrows(FailingHttpStatusCodeException.class, () -> { assertThrows(FailingHttpStatusCodeException.class, () ->
j.submit(form); j.submit(form));
});
} }
@Test @Test
public void validatePasswordMismatchForFIPS() throws Throwable { void validatePasswordMismatchForFIPS() throws Throwable {
rjr.then(HudsonPrivateSecurityRealmFIPSTest::validatePasswordMismatchForFIPSStep); rjr.then(HudsonPrivateSecurityRealmFIPSTest::validatePasswordMismatchForFIPSStep);
} }
@ -194,13 +192,12 @@ public class HudsonPrivateSecurityRealmFIPSTest {
password2.setText("14charPa$$word"); password2.setText("14charPa$$word");
HtmlForm form = configurePage.getFormByName("config"); HtmlForm form = configurePage.getFormByName("config");
assertThrows(FailingHttpStatusCodeException.class, () -> { assertThrows(FailingHttpStatusCodeException.class, () ->
j.submit(form); j.submit(form));
});
} }
@Test @Test
public void validatePasswordSuccessForFIPS() throws Throwable { void validatePasswordSuccessForFIPS() throws Throwable {
rjr.then(HudsonPrivateSecurityRealmFIPSTest::validatePasswordSuccessForFIPSStep); rjr.then(HudsonPrivateSecurityRealmFIPSTest::validatePasswordSuccessForFIPSStep);
} }

View File

@ -3,9 +3,9 @@ package hudson.security;
import static jakarta.servlet.http.HttpServletResponse.SC_UNAUTHORIZED; import static jakarta.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.Assert.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.Assert.assertNull; import static org.junit.jupiter.api.Assertions.assertNull;
import hudson.model.User; import hudson.model.User;
import java.io.IOException; import java.io.IOException;
@ -14,30 +14,34 @@ import jenkins.model.Jenkins;
import org.htmlunit.html.HtmlForm; import org.htmlunit.html.HtmlForm;
import org.htmlunit.html.HtmlFormUtil; import org.htmlunit.html.HtmlFormUtil;
import org.htmlunit.html.HtmlPage; import org.htmlunit.html.HtmlPage;
import org.junit.Rule; import org.junit.jupiter.api.BeforeEach;
import org.junit.Test; import org.junit.jupiter.api.Test;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.JenkinsRule.WebClient; import org.jvnet.hudson.test.JenkinsRule.WebClient;
import org.jvnet.hudson.test.MockAuthorizationStrategy; import org.jvnet.hudson.test.MockAuthorizationStrategy;
import org.jvnet.hudson.test.recipes.PresetData; import org.jvnet.hudson.test.junit.jupiter.WithJenkins;
import org.jvnet.hudson.test.recipes.PresetData.DataSet;
import org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices; import org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
/** /**
* @author Kohsuke Kawaguchi * @author Kohsuke Kawaguchi
*/ */
public class LoginTest { @WithJenkins
class LoginTest {
@Rule private JenkinsRule j;
public JenkinsRule j = new JenkinsRule();
@BeforeEach
void setUp(JenkinsRule rule) {
j = rule;
}
/** /**
* Requesting a loginError page directly should result in a redirect, * Requesting a loginError page directly should result in a redirect,
* on a non-secured Hudson. * on a non-secured Hudson.
*/ */
@Test @Test
public void loginErrorRedirect1() throws Exception { void loginErrorRedirect1() throws Exception {
verifyNotError(j.createWebClient()); verifyNotError(j.createWebClient());
} }
@ -52,8 +56,13 @@ public class LoginTest {
* Same as {@link #loginErrorRedirect1()} if the user has already successfully authenticated. * Same as {@link #loginErrorRedirect1()} if the user has already successfully authenticated.
*/ */
@Test @Test
@PresetData(DataSet.ANONYMOUS_READONLY) void loginErrorRedirect2() throws Exception {
public void loginErrorRedirect2() throws Exception { JenkinsRule.DummySecurityRealm realm = j.createDummySecurityRealm();
j.jenkins.setSecurityRealm(realm);
j.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy()
.grant(Jenkins.READ).everywhere().toEveryone()
.grant(Jenkins.ADMINISTER).everywhere().toAuthenticated());
// in a secured Hudson, the error page should render. // in a secured Hudson, the error page should render.
WebClient wc = j.createWebClient(); WebClient wc = j.createWebClient();
wc.assertFails("loginError", SC_UNAUTHORIZED); wc.assertFails("loginError", SC_UNAUTHORIZED);
@ -62,7 +71,7 @@ public class LoginTest {
} }
@Test @Test
public void loginError() throws Exception { void loginError() throws Exception {
j.jenkins.setSecurityRealm(j.createDummySecurityRealm()); j.jenkins.setSecurityRealm(j.createDummySecurityRealm());
j.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy().grant(Jenkins.ADMINISTER).everywhere().toAuthenticated()); j.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy().grant(Jenkins.ADMINISTER).everywhere().toAuthenticated());
WebClient wc = j.createWebClient(); WebClient wc = j.createWebClient();
@ -97,8 +106,13 @@ public class LoginTest {
* Test 'remember me' cookie * Test 'remember me' cookie
*/ */
@Test @Test
@PresetData(DataSet.SECURED_ACEGI) void loginRememberMe() throws Exception {
public void loginRememberMe() throws Exception { JenkinsRule.DummySecurityRealm realm = j.createDummySecurityRealm();
j.jenkins.setSecurityRealm(realm);
j.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy()
.grant(Jenkins.READ).everywhere().toEveryone()
.grant(Jenkins.ADMINISTER).everywhere().toAuthenticated());
WebClient wc = j.createWebClient(); WebClient wc = j.createWebClient();
HtmlFormUtil.submit(prepareLoginFormWithRememberMeChecked(wc), null); HtmlFormUtil.submit(prepareLoginFormWithRememberMeChecked(wc), null);
@ -111,8 +125,13 @@ public class LoginTest {
* This models the case when the feature is disabled between another user loading and submitting the login page. * This models the case when the feature is disabled between another user loading and submitting the login page.
*/ */
@Test @Test
@PresetData(DataSet.SECURED_ACEGI) void loginDisabledRememberMe() throws Exception {
public void loginDisabledRememberMe() throws Exception { JenkinsRule.DummySecurityRealm realm = j.createDummySecurityRealm();
j.jenkins.setSecurityRealm(realm);
j.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy()
.grant(Jenkins.READ).everywhere().toEveryone()
.grant(Jenkins.ADMINISTER).everywhere().toAuthenticated());
WebClient wc = j.createWebClient(); WebClient wc = j.createWebClient();
HtmlForm form = prepareLoginFormWithRememberMeChecked(wc); HtmlForm form = prepareLoginFormWithRememberMeChecked(wc);

View File

@ -24,7 +24,7 @@
package hudson.slaves; package hudson.slaves;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import hudson.model.Slave; import hudson.model.Slave;
import java.util.logging.Level; import java.util.logging.Level;
@ -33,44 +33,60 @@ import org.dom4j.Document;
import org.dom4j.Element; import org.dom4j.Element;
import org.dom4j.io.DOMReader; import org.dom4j.io.DOMReader;
import org.htmlunit.xml.XmlPage; import org.htmlunit.xml.XmlPage;
import org.junit.Rule; import org.junit.jupiter.api.AfterEach;
import org.junit.Test; import org.junit.jupiter.api.BeforeEach;
import org.jvnet.hudson.test.FlagRule; import org.junit.jupiter.api.Test;
import org.jvnet.hudson.test.InboundAgentRule; import org.junit.jupiter.api.extension.RegisterExtension;
import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.LoggerRule; import org.jvnet.hudson.test.LogRecorder;
import org.jvnet.hudson.test.MockAuthorizationStrategy; import org.jvnet.hudson.test.MockAuthorizationStrategy;
import org.jvnet.hudson.test.junit.jupiter.InboundAgentExtension;
import org.jvnet.hudson.test.junit.jupiter.WithJenkins;
/** /**
* Tests of {@link JNLPLauncher} using a custom inbound agent url. * Tests of {@link JNLPLauncher} using a custom inbound agent url.
*/ */
public class AgentInboundUrlTest { @WithJenkins
@Rule class AgentInboundUrlTest {
public JenkinsRule j = new JenkinsRule();
@Rule @RegisterExtension
public InboundAgentRule inboundAgents = new InboundAgentRule(); private final InboundAgentExtension inboundAgents = new InboundAgentExtension();
@Rule private final LogRecorder logging = new LogRecorder().record(Slave.class, Level.FINE);
public LoggerRule logging = new LoggerRule().record(Slave.class, Level.FINE);
// Override the inbound agent url // Override the inbound agent url
private static final String customInboundUrl = "http://localhost:8080/jenkins"; private static final String CUSTOM_INBOUND_URL = "http://localhost:8080/jenkins";
@Rule private String customInboundUrlRule;
public final FlagRule<String> customInboundUrlRule = FlagRule.systemProperty(JNLPLauncher.CUSTOM_INBOUND_URL_PROPERTY, customInboundUrl);
private JenkinsRule j;
@BeforeEach
void setUp(JenkinsRule rule) {
j = rule;
customInboundUrlRule = System.setProperty(JNLPLauncher.CUSTOM_INBOUND_URL_PROPERTY, CUSTOM_INBOUND_URL);
}
@AfterEach
void tearDown() {
if (customInboundUrlRule != null) {
System.setProperty(JNLPLauncher.CUSTOM_INBOUND_URL_PROPERTY, customInboundUrlRule);
} else {
System.clearProperty(JNLPLauncher.CUSTOM_INBOUND_URL_PROPERTY);
}
}
@Issue("JENKINS-63222") @Issue("JENKINS-63222")
@Test @Test
public void testInboundAgentUrlOverride() throws Exception { void testInboundAgentUrlOverride() throws Exception {
j.jenkins.setSecurityRealm(j.createDummySecurityRealm()); j.jenkins.setSecurityRealm(j.createDummySecurityRealm());
MockAuthorizationStrategy authorizationStrategy = new MockAuthorizationStrategy(); MockAuthorizationStrategy authorizationStrategy = new MockAuthorizationStrategy();
authorizationStrategy.grant(Jenkins.ADMINISTER).everywhere().toEveryone(); authorizationStrategy.grant(Jenkins.ADMINISTER).everywhere().toEveryone();
j.jenkins.setAuthorizationStrategy(authorizationStrategy); j.jenkins.setAuthorizationStrategy(authorizationStrategy);
// Create an agent // Create an agent
inboundAgents.createAgent(j, InboundAgentRule.Options.newBuilder().name("test").skipStart().build()); inboundAgents.createAgent(j, InboundAgentExtension.Options.newBuilder().name("test").skipStart().build());
// parse the JNLP page into DOM to inspect the jnlp url argument. // parse the JNLP page into DOM to inspect the jnlp url argument.
JenkinsRule.WebClient agent = j.createWebClient(); JenkinsRule.WebClient agent = j.createWebClient();
@ -78,6 +94,6 @@ public class AgentInboundUrlTest {
Document dom = new DOMReader().read(jnlp.getXmlDocument()); Document dom = new DOMReader().read(jnlp.getXmlDocument());
Object arg = dom.selectSingleNode("//application-desc/argument[7]/following-sibling::argument[1]"); Object arg = dom.selectSingleNode("//application-desc/argument[7]/following-sibling::argument[1]");
String val = ((Element) arg).getText(); String val = ((Element) arg).getText();
assertEquals(customInboundUrl, val); assertEquals(CUSTOM_INBOUND_URL, val);
} }
} }

View File

@ -35,26 +35,29 @@ import hudson.model.FreeStyleProject;
import hudson.model.Slave; import hudson.model.Slave;
import jenkins.agents.WebSocketAgentsTest; import jenkins.agents.WebSocketAgentsTest;
import jenkins.slaves.JnlpSlaveAgentProtocol4; import jenkins.slaves.JnlpSlaveAgentProtocol4;
import org.junit.Rule; import org.junit.jupiter.api.Test;
import org.junit.Test; import org.junit.jupiter.api.extension.RegisterExtension;
import org.jvnet.hudson.test.For; import org.jvnet.hudson.test.For;
import org.jvnet.hudson.test.InboundAgentRule;
import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.PrefixedOutputStream; import org.jvnet.hudson.test.PrefixedOutputStream;
import org.jvnet.hudson.test.RealJenkinsRule; import org.jvnet.hudson.test.junit.jupiter.InboundAgentExtension;
import org.jvnet.hudson.test.junit.jupiter.RealJenkinsExtension;
@For({JNLPLauncher.class, JnlpSlaveAgentProtocol4.class}) @For({JNLPLauncher.class, JnlpSlaveAgentProtocol4.class})
public class JNLPLauncherRealTest { class JNLPLauncherRealTest {
private static final String STATIC_AGENT_NAME = "static"; private static final String STATIC_AGENT_NAME = "static";
@Rule public RealJenkinsRule rr = new RealJenkinsRule().withColor(PrefixedOutputStream.Color.BLUE); @RegisterExtension
private final RealJenkinsExtension rr = new RealJenkinsExtension().withColor(PrefixedOutputStream.Color.BLUE);
@Rule public InboundAgentRule iar = new InboundAgentRule(); @RegisterExtension
private final InboundAgentExtension iar = new InboundAgentExtension();
@Issue("JEP-230") @Issue("JEP-230")
@Test public void smokes() throws Throwable { @Test
void smokes() throws Throwable {
/* Since RealJenkinsRuleInit.jpi will load detached and test scope plugins, to reproduce a failure use: /* Since RealJenkinsRuleInit.jpi will load detached and test scope plugins, to reproduce a failure use:
rr.includeTestClasspathPlugins(false); rr.includeTestClasspathPlugins(false);
FileUtils.touch(new File(rr.getHome(), "plugins/instance-identity.jpi.disabled")); FileUtils.touch(new File(rr.getHome(), "plugins/instance-identity.jpi.disabled"));
@ -66,14 +69,15 @@ public class JNLPLauncherRealTest {
* Simplified version of {@link WebSocketAgentsTest#smokes} just checking Jetty/Winstone. * Simplified version of {@link WebSocketAgentsTest#smokes} just checking Jetty/Winstone.
*/ */
@Issue("JENKINS-68933") @Issue("JENKINS-68933")
@Test public void webSocket() throws Throwable { @Test
void webSocket() throws Throwable {
then(true); then(true);
} }
private void then(boolean websocket) throws Throwable { private void then(boolean websocket) throws Throwable {
try { try {
rr.startJenkins(); rr.startJenkins();
InboundAgentRule.Options.Builder options = InboundAgentRule.Options.newBuilder().name(STATIC_AGENT_NAME).color(PrefixedOutputStream.Color.RED); InboundAgentExtension.Options.Builder options = InboundAgentExtension.Options.newBuilder().name(STATIC_AGENT_NAME).color(PrefixedOutputStream.Color.RED);
if (websocket) { if (websocket) {
options = options.webSocket(); options = options.webSocket();
} }
@ -84,7 +88,7 @@ public class JNLPLauncherRealTest {
} }
} }
private static class RunJobStep implements RealJenkinsRule.Step { private static class RunJobStep implements RealJenkinsExtension.Step {
private final String agentName; private final String agentName;
private final boolean webSocket; private final boolean webSocket;

View File

@ -1,6 +1,6 @@
package hudson.slaves; package hudson.slaves;
import static org.junit.Assert.fail; import static org.junit.jupiter.api.Assertions.fail;
import hudson.model.Slave; import hudson.model.Slave;
import java.util.ArrayList; import java.util.ArrayList;
@ -14,27 +14,34 @@ import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.junit.Rule; import org.junit.jupiter.api.BeforeEach;
import org.junit.Test; import org.junit.jupiter.api.Test;
import org.jvnet.hudson.test.InboundAgentRule; import org.junit.jupiter.api.extension.RegisterExtension;
import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.junit.jupiter.InboundAgentExtension;
import org.jvnet.hudson.test.junit.jupiter.WithJenkins;
public class NodeParallelTest { @WithJenkins
class NodeParallelTest {
@Rule @RegisterExtension
public JenkinsRule r = new JenkinsRule(); public InboundAgentExtension inboundAgents = new InboundAgentExtension();
@Rule
public InboundAgentRule inboundAgents = new InboundAgentRule();
private static final Logger LOGGER = Logger.getLogger(NodeParallelTest.class.getName()); private static final Logger LOGGER = Logger.getLogger(NodeParallelTest.class.getName());
private final AtomicInteger count = new AtomicInteger(); private final AtomicInteger count = new AtomicInteger();
private JenkinsRule r;
@BeforeEach
void setUp(JenkinsRule rule) {
r = rule;
}
@Test @Test
@Issue("JENKINS-53401") @Issue("JENKINS-53401")
public void createNodesWithParallelThreads() throws InterruptedException, ExecutionException { void createNodesWithParallelThreads() throws InterruptedException, ExecutionException {
int n = 50; int n = 50;
List<Callable<Void>> tasks = Collections.nCopies(n, () -> { List<Callable<Void>> tasks = Collections.nCopies(n, () -> {
try { try {
@ -42,7 +49,7 @@ public class NodeParallelTest {
LOGGER.log(Level.INFO, "Creating slave " + i); LOGGER.log(Level.INFO, "Creating slave " + i);
// JenkinsRule sync on Jenkins singleton, so this doesn't work // JenkinsRule sync on Jenkins singleton, so this doesn't work
// r.createSlave(); // r.createSlave();
Slave agent = inboundAgents.createAgent(r, InboundAgentRule.Options.newBuilder().name("agent-" + i).skipStart().build()); Slave agent = inboundAgents.createAgent(r, InboundAgentExtension.Options.newBuilder().name("agent-" + i).skipStart().build());
agent.setNodeProperties(List.of(new EnvironmentVariablesNodeProperty(new EnvironmentVariablesNodeProperty.Entry("foo", "" + i)))); agent.setNodeProperties(List.of(new EnvironmentVariablesNodeProperty(new EnvironmentVariablesNodeProperty.Entry("foo", "" + i))));
return null; return null;
} catch (Exception e1) { } catch (Exception e1) {

View File

@ -27,9 +27,9 @@ package hudson.slaves;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.anyOf; import static org.hamcrest.Matchers.anyOf;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.Assume.assumeFalse; import static org.junit.jupiter.api.Assumptions.assumeFalse;
import hudson.BulkChange; import hudson.BulkChange;
import hudson.Functions; import hudson.Functions;
@ -66,23 +66,24 @@ import java.util.logging.ConsoleHandler;
import java.util.logging.Handler; import java.util.logging.Handler;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.junit.Before; import org.junit.jupiter.api.BeforeEach;
import org.junit.Rule; import org.junit.jupiter.api.Test;
import org.junit.Test; import org.junit.jupiter.api.extension.RegisterExtension;
import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.RealJenkinsRule;
import org.jvnet.hudson.test.SleepBuilder; import org.jvnet.hudson.test.SleepBuilder;
import org.jvnet.hudson.test.junit.jupiter.RealJenkinsExtension;
/** /**
* @author Kohsuke Kawaguchi * @author Kohsuke Kawaguchi
*/ */
public class NodeProvisionerTest { class NodeProvisionerTest {
@Rule public RealJenkinsRule rr = new RealJenkinsRule(); @RegisterExtension
private final RealJenkinsExtension rr = new RealJenkinsExtension();
@Before @BeforeEach
public void setUp() { void setUp() {
// run 10x the regular speed to speed up the test // run 10x the regular speed to speed up the test
rr.javaOptions( rr.javaOptions(
"-Dhudson.model.LoadStatistics.clock=" + TimeUnit.SECONDS.toMillis(1), "-Dhudson.model.LoadStatistics.clock=" + TimeUnit.SECONDS.toMillis(1),
@ -128,8 +129,9 @@ public class NodeProvisionerTest {
* Scenario: schedule a build and see if one agent is provisioned. * Scenario: schedule a build and see if one agent is provisioned.
*/ */
// TODO fragile // TODO fragile
@Test public void autoProvision() throws Throwable { @Test
assumeFalse("TODO: Windows container agents do not have enough resources to run this test", Functions.isWindows() && System.getenv("CI") != null); void autoProvision() throws Throwable {
assumeFalse(Functions.isWindows() && System.getenv("CI") != null, "TODO: Windows container agents do not have enough resources to run this test");
rr.then(NodeProvisionerTest::_autoProvision); rr.then(NodeProvisionerTest::_autoProvision);
} }
@ -151,8 +153,9 @@ public class NodeProvisionerTest {
* Scenario: we got a lot of jobs all of the sudden, and we need to fire up a few nodes. * Scenario: we got a lot of jobs all of the sudden, and we need to fire up a few nodes.
*/ */
// TODO fragile // TODO fragile
@Test public void loadSpike() throws Throwable { @Test
assumeFalse("TODO: Windows container agents do not have enough resources to run this test", Functions.isWindows() && System.getenv("CI") != null); void loadSpike() throws Throwable {
assumeFalse(Functions.isWindows() && System.getenv("CI") != null, "TODO: Windows container agents do not have enough resources to run this test");
rr.then(NodeProvisionerTest::_loadSpike); rr.then(NodeProvisionerTest::_loadSpike);
} }
@ -173,8 +176,9 @@ public class NodeProvisionerTest {
* Scenario: make sure we take advantage of statically configured agents. * Scenario: make sure we take advantage of statically configured agents.
*/ */
// TODO fragile // TODO fragile
@Test public void baselineSlaveUsage() throws Throwable { @Test
assumeFalse("TODO: Windows container agents do not have enough resources to run this test", Functions.isWindows() && System.getenv("CI") != null); void baselineSlaveUsage() throws Throwable {
assumeFalse(Functions.isWindows() && System.getenv("CI") != null, "TODO: Windows container agents do not have enough resources to run this test");
rr.then(NodeProvisionerTest::_baselineSlaveUsage); rr.then(NodeProvisionerTest::_baselineSlaveUsage);
} }
@ -197,8 +201,9 @@ public class NodeProvisionerTest {
* Scenario: loads on one label shouldn't translate to load on another label. * Scenario: loads on one label shouldn't translate to load on another label.
*/ */
// TODO fragile // TODO fragile
@Test public void labels() throws Throwable { @Test
assumeFalse("TODO: Windows container agents do not have enough resources to run this test", Functions.isWindows() && System.getenv("CI") != null); void labels() throws Throwable {
assumeFalse(Functions.isWindows() && System.getenv("CI") != null, "TODO: Windows container agents do not have enough resources to run this test");
rr.then(NodeProvisionerTest::_labels); rr.then(NodeProvisionerTest::_labels);
} }
@ -235,8 +240,8 @@ public class NodeProvisionerTest {
@Issue("JENKINS-7291") @Issue("JENKINS-7291")
@Test @Test
public void flyweightTasksWithoutMasterExecutors() throws Throwable { void flyweightTasksWithoutMasterExecutors() throws Throwable {
assumeFalse("TODO: Windows container agents do not have enough resources to run this test", Functions.isWindows() && System.getenv("CI") != null); assumeFalse(Functions.isWindows() && System.getenv("CI") != null, "TODO: Windows container agents do not have enough resources to run this test");
rr.then(NodeProvisionerTest::_flyweightTasksWithoutMasterExecutors); rr.then(NodeProvisionerTest::_flyweightTasksWithoutMasterExecutors);
} }
@ -267,8 +272,8 @@ public class NodeProvisionerTest {
*/ */
@Issue("JENKINS-30084") @Issue("JENKINS-30084")
@Test @Test
public void shouldRunFlyweightTaskOnProvisionedNodeWhenNodeRestricted() throws Throwable { void shouldRunFlyweightTaskOnProvisionedNodeWhenNodeRestricted() throws Throwable {
assumeFalse("TODO: Windows container agents do not have enough resources to run this test", Functions.isWindows() && System.getenv("CI") != null); assumeFalse(Functions.isWindows() && System.getenv("CI") != null, "TODO: Windows container agents do not have enough resources to run this test");
rr.then(NodeProvisionerTest::_shouldRunFlyweightTaskOnProvisionedNodeWhenNodeRestricted); rr.then(NodeProvisionerTest::_shouldRunFlyweightTaskOnProvisionedNodeWhenNodeRestricted);
} }
@ -286,8 +291,8 @@ public class NodeProvisionerTest {
@Issue("JENKINS-67635") @Issue("JENKINS-67635")
@Test @Test
public void testJobWithCloudLabelExpressionProvisionsOnlyOneAgent() throws Throwable { void testJobWithCloudLabelExpressionProvisionsOnlyOneAgent() throws Throwable {
assumeFalse("TODO: Windows container agents do not have enough resources to run this test", Functions.isWindows() && System.getenv("CI") != null); assumeFalse(Functions.isWindows() && System.getenv("CI") != null, "TODO: Windows container agents do not have enough resources to run this test");
rr.then(NodeProvisionerTest::_testJobWithCloudLabelExpressionProvisionsOnlyOneAgent); rr.then(NodeProvisionerTest::_testJobWithCloudLabelExpressionProvisionsOnlyOneAgent);
} }

View File

@ -75,7 +75,7 @@ import org.springframework.security.core.Authentication;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
@WithJenkins @WithJenkins
public class BuildTriggerTest { class BuildTriggerTest {
private JenkinsRule j; private JenkinsRule j;

View File

@ -26,10 +26,8 @@ package hudson.util;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assumptions.assumeTrue;
import static org.junit.Assume.assumeThat;
import static org.junit.Assume.assumeTrue;
import hudson.Functions; import hudson.Functions;
import hudson.Launcher.LocalLauncher; import hudson.Launcher.LocalLauncher;
@ -43,31 +41,36 @@ import java.nio.charset.Charset;
import java.util.logging.Level; import java.util.logging.Level;
import jenkins.util.SystemProperties; import jenkins.util.SystemProperties;
import org.apache.tools.ant.util.JavaEnvUtils; import org.apache.tools.ant.util.JavaEnvUtils;
import org.junit.Rule; import org.junit.jupiter.api.BeforeEach;
import org.junit.Test; import org.junit.jupiter.api.Test;
import org.jvnet.hudson.test.Email; import org.jvnet.hudson.test.Email;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.LoggerRule; import org.jvnet.hudson.test.LogRecorder;
import org.jvnet.hudson.test.junit.jupiter.WithJenkins;
/** /**
* @author Kohsuke Kawaguchi * @author Kohsuke Kawaguchi
*/ */
public class ArgumentListBuilder2Test { @WithJenkins
class ArgumentListBuilder2Test {
@Rule private final LogRecorder logging = new LogRecorder().
public JenkinsRule j = new JenkinsRule();
@Rule
public LoggerRule logging = new LoggerRule().
record(StreamTaskListener.class, Level.FINE). record(StreamTaskListener.class, Level.FINE).
record(SystemProperties.class, Level.FINE); record(SystemProperties.class, Level.FINE);
private JenkinsRule j;
@BeforeEach
void setUp(JenkinsRule rule) {
j = rule;
}
/** /**
* Makes sure {@link RemoteLauncher} properly masks arguments. * Makes sure {@link RemoteLauncher} properly masks arguments.
*/ */
@Test @Test
@Email("http://n4.nabble.com/Password-masking-when-running-commands-on-a-slave-tp1753033p1753033.html") @Email("http://n4.nabble.com/Password-masking-when-running-commands-on-a-slave-tp1753033p1753033.html")
public void slaveMask() throws Exception { void slaveMask() throws Exception {
ArgumentListBuilder args = new ArgumentListBuilder(); ArgumentListBuilder args = new ArgumentListBuilder();
args.add("java"); args.add("java");
args.addMasked("-version"); args.addMasked("-version");
@ -81,7 +84,7 @@ public class ArgumentListBuilder2Test {
} }
@Test @Test
public void ensureArgumentsArePassedViaCmdExeUnmodified() throws Exception { void ensureArgumentsArePassedViaCmdExeUnmodified() throws Exception {
assumeTrue(Functions.isWindows()); assumeTrue(Functions.isWindows());
String[] specials = new String[] { String[] specials = new String[] {
@ -147,7 +150,7 @@ public class ArgumentListBuilder2Test {
int code = p.join(); int code = p.join();
listener.close(); listener.close();
assumeThat("Failed to run " + args, code, equalTo(0)); assumeTrue(code == 0, "Failed to run " + args);
return out.toString(Charset.defaultCharset()); return out.toString(Charset.defaultCharset());
} }
} }

View File

@ -1,9 +1,9 @@
package hudson.util; package hudson.util;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.Assert.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.Assert.assertNull; import static org.junit.jupiter.api.Assertions.assertNull;
import hudson.WebAppMain; import hudson.WebAppMain;
import hudson.model.Hudson; import hudson.model.Hudson;
@ -12,6 +12,7 @@ import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletContextEvent; import jakarta.servlet.ServletContextEvent;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
@ -20,16 +21,20 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
import jenkins.model.Jenkins; import jenkins.model.Jenkins;
import jenkins.util.SystemProperties; import jenkins.util.SystemProperties;
import org.junit.After; import org.junit.jupiter.api.AfterAll;
import org.junit.AfterClass; import org.junit.jupiter.api.AfterEach;
import org.junit.BeforeClass; import org.junit.jupiter.api.BeforeAll;
import org.junit.Rule; import org.junit.jupiter.api.Test;
import org.junit.Test; import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.rules.TemporaryFolder; import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.api.io.TempDir;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.TestEnvironment; import org.jvnet.hudson.test.TestEnvironment;
import org.jvnet.hudson.test.TestExtension; import org.jvnet.hudson.test.TestExtension;
import org.jvnet.hudson.test.junit.jupiter.JenkinsSessionExtension;
import org.kohsuke.stapler.WebApp; import org.kohsuke.stapler.WebApp;
/** /**
@ -37,15 +42,23 @@ import org.kohsuke.stapler.WebApp;
* *
* @author Kohsuke Kawaguchi * @author Kohsuke Kawaguchi
*/ */
public class BootFailureTest { class BootFailureTest {
@Rule
public TemporaryFolder tmpDir = new TemporaryFolder(); @TempDir
private File tmpDir;
static boolean makeBootFail = true; static boolean makeBootFail = true;
static WebAppMain wa; static WebAppMain wa;
private static String forceSessionTrackingByCookiePreviousValue; private static String forceSessionTrackingByCookiePreviousValue;
// to be set by the script
private static Exception problem;
private static List<String> runRecord = new ArrayList<>();
@RegisterExtension
private final JenkinsSessionExtension session = new CustomJenkinsSessionExtension();
/* /*
* TODO use RealJenkinsRule * TODO use RealJenkinsRule
* *
@ -54,14 +67,14 @@ public class BootFailureTest {
* use RealJenkinsRule, this workaround should be deleted. * use RealJenkinsRule, this workaround should be deleted.
*/ */
@BeforeClass @BeforeAll
public static void disableSessionTrackingSetting() { static void disableSessionTrackingSetting() {
forceSessionTrackingByCookiePreviousValue = SystemProperties.getString(WebAppMain.FORCE_SESSION_TRACKING_BY_COOKIE_PROP); forceSessionTrackingByCookiePreviousValue = SystemProperties.getString(WebAppMain.FORCE_SESSION_TRACKING_BY_COOKIE_PROP);
System.setProperty(WebAppMain.FORCE_SESSION_TRACKING_BY_COOKIE_PROP, "false"); System.setProperty(WebAppMain.FORCE_SESSION_TRACKING_BY_COOKIE_PROP, "false");
} }
@AfterClass @AfterAll
public static void resetSessionTrackingSetting() { static void resetSessionTrackingSetting() {
if (forceSessionTrackingByCookiePreviousValue == null) { if (forceSessionTrackingByCookiePreviousValue == null) {
System.clearProperty(WebAppMain.FORCE_SESSION_TRACKING_BY_COOKIE_PROP); System.clearProperty(WebAppMain.FORCE_SESSION_TRACKING_BY_COOKIE_PROP);
} else { } else {
@ -69,44 +82,8 @@ public class BootFailureTest {
} }
} }
static class CustomRule extends JenkinsRule { @AfterEach
@Override void tearDown() {
public void before() {
env = new TestEnvironment(testDescription);
env.pin();
// don't let Jenkins start automatically
}
@Override
public Hudson newHudson() throws Exception {
localPort = 0;
ServletContext ws = createWebServer2();
wa = new WebAppMain() {
@Override
public WebAppMain.FileAndDescription getHomeDir(ServletContextEvent event) {
try {
return new WebAppMain.FileAndDescription(homeLoader.allocate(), "test");
} catch (Exception x) {
throw new AssertionError(x);
}
}
};
wa.contextInitialized(new ServletContextEvent(ws));
wa.joinInit();
Object a = WebApp.get(ws).getApp();
if (a instanceof Hudson) {
return (Hudson) a;
}
return null; // didn't boot
}
}
@Rule
public CustomRule j = new CustomRule();
@After
public void tearDown() {
Jenkins j = Jenkins.getInstanceOrNull(); Jenkins j = Jenkins.getInstanceOrNull();
if (j != null) { if (j != null) {
j.cleanUp(); j.cleanUp();
@ -125,52 +102,56 @@ public class BootFailureTest {
} }
@Test @Test
public void runBootFailureScript() throws Exception { void runBootFailureScript() throws Throwable {
final File home = tmpDir.newFolder(); session.then(j -> {
j.with(() -> home); final File home = newFolder(tmpDir, "junit");
j.with(() -> home);
// creates a script // creates a script
Files.writeString(home.toPath().resolve("boot-failure.groovy"), "hudson.util.BootFailureTest.problem = exception", StandardCharsets.UTF_8); Files.writeString(home.toPath().resolve("boot-failure.groovy"), "hudson.util.BootFailureTest.problem = exception", StandardCharsets.UTF_8);
Path d = home.toPath().resolve("boot-failure.groovy.d"); Path d = home.toPath().resolve("boot-failure.groovy.d");
Files.createDirectory(d); Files.createDirectory(d);
Files.writeString(d.resolve("1.groovy"), "hudson.util.BootFailureTest.runRecord << '1'", StandardCharsets.UTF_8); Files.writeString(d.resolve("1.groovy"), "hudson.util.BootFailureTest.runRecord << '1'", StandardCharsets.UTF_8);
Files.writeString(d.resolve("2.groovy"), "hudson.util.BootFailureTest.runRecord << '2'", StandardCharsets.UTF_8); Files.writeString(d.resolve("2.groovy"), "hudson.util.BootFailureTest.runRecord << '2'", StandardCharsets.UTF_8);
// first failed boot // first failed boot
makeBootFail = true; makeBootFail = true;
assertNull(j.newHudson()); assertNull(((CustomJenkinsSessionExtension.CustomJenkinsRule) j).newHudson());
assertEquals(1, bootFailures(home)); assertEquals(1, bootFailures(home));
// second failed boot // second failed boot
problem = null; problem = null;
runRecord = new ArrayList<>(); runRecord = new ArrayList<>();
assertNull(j.newHudson()); assertNull(((CustomJenkinsSessionExtension.CustomJenkinsRule) j).newHudson());
assertEquals(2, bootFailures(home)); assertEquals(2, bootFailures(home));
assertEquals(Arrays.asList("1", "2"), runRecord); assertEquals(Arrays.asList("1", "2"), runRecord);
// make sure the script has actually run // make sure the script has actually run
assertEquals(SeriousError.class, problem.getCause().getClass()); assertEquals(SeriousError.class, problem.getCause().getClass());
// if it boots well, the failure record should be gone // if it boots well, the failure record should be gone
makeBootFail = false; makeBootFail = false;
assertNotNull(j.newHudson()); assertNotNull(((CustomJenkinsSessionExtension.CustomJenkinsRule) j).newHudson());
assertFalse(BootFailure.getBootFailureFile(home).exists()); assertFalse(BootFailure.getBootFailureFile(home).exists());
});
} }
private static int bootFailures(File home) throws IOException { private static int bootFailures(File home) {
return new BootFailure() { }.loadAttempts(home).size(); return new BootFailure() { }.loadAttempts(home).size();
} }
@Issue("JENKINS-24696") @Issue("JENKINS-24696")
@Test @Test
public void interruptedStartup() throws Exception { void interruptedStartup() throws Throwable {
final File home = tmpDir.newFolder(); session.then(j -> {
j.with(() -> home); final File home = newFolder(tmpDir, "junit");
Path d = home.toPath().resolve("boot-failure.groovy.d"); j.with(() -> home);
Files.createDirectory(d); Path d = home.toPath().resolve("boot-failure.groovy.d");
Files.writeString(d.resolve("1.groovy"), "hudson.util.BootFailureTest.runRecord << '1'", StandardCharsets.UTF_8); Files.createDirectory(d);
j.newHudson(); Files.writeString(d.resolve("1.groovy"), "hudson.util.BootFailureTest.runRecord << '1'", StandardCharsets.UTF_8);
assertEquals(List.of("1"), runRecord); ((CustomJenkinsSessionExtension.CustomJenkinsRule) j).newHudson();
assertEquals(List.of("1"), runRecord);
});
} }
@TestExtension("interruptedStartup") @TestExtension("interruptedStartup")
@ -181,8 +162,85 @@ public class BootFailureTest {
} }
} }
// to be set by the script private static File newFolder(File root, String... subDirs) throws IOException {
public static Exception problem; String subFolder = String.join("/", subDirs);
public static List<String> runRecord = new ArrayList<>(); File result = new File(root, subFolder);
if (!result.mkdirs()) {
throw new IOException("Couldn't create folders " + root);
}
return result;
}
private static class CustomJenkinsSessionExtension extends JenkinsSessionExtension {
private int port;
private Description description;
@Override
public void beforeEach(ExtensionContext context) {
super.beforeEach(context);
description = Description.createTestDescription(
context.getTestClass().map(Class::getName).orElse(null),
context.getTestMethod().map(Method::getName).orElse(null),
context.getTestMethod().map(Method::getAnnotations).orElse(null));
}
@Override
public void then(Step s) throws Throwable {
CustomJenkinsRule r = new CustomJenkinsRule(getHome(), port);
r.apply(
new Statement() {
@Override
public void evaluate() throws Throwable {
port = r.getPort();
s.run(r);
}
},
description
).evaluate();
}
private static final class CustomJenkinsRule extends JenkinsRule {
CustomJenkinsRule(File home, int port) {
with(() -> home);
localPort = port;
}
int getPort() {
return localPort;
}
@Override
public void before() {
env = new TestEnvironment(testDescription);
env.pin();
// don't let Jenkins start automatically
}
@Override
public Hudson newHudson() throws Exception {
localPort = 0;
ServletContext ws = createWebServer2();
wa = new WebAppMain() {
@Override
public WebAppMain.FileAndDescription getHomeDir(ServletContextEvent event) {
try {
return new WebAppMain.FileAndDescription(homeLoader.allocate(), "test");
} catch (Exception x) {
throw new AssertionError(x);
}
}
};
wa.contextInitialized(new ServletContextEvent(ws));
wa.joinInit();
Object a = WebApp.get(ws).getApp();
if (a instanceof Hudson) {
return (Hudson) a;
}
return null; // didn't boot
}
}
}
} }

View File

@ -29,34 +29,34 @@ import static org.awaitility.Awaitility.await;
import hudson.ExtensionList; import hudson.ExtensionList;
import java.time.Duration; import java.time.Duration;
import java.util.logging.Level; import java.util.logging.Level;
import org.junit.Rule; import org.junit.jupiter.api.Test;
import org.junit.Test; import org.junit.jupiter.api.extension.RegisterExtension;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.PrefixedOutputStream; import org.jvnet.hudson.test.PrefixedOutputStream;
import org.jvnet.hudson.test.RealJenkinsRule; import org.jvnet.hudson.test.junit.jupiter.RealJenkinsExtension;
public final class DoubleLaunchCheckerTest { class DoubleLaunchCheckerTest {
@Rule @RegisterExtension
public RealJenkinsRule mainController = new RealJenkinsRule(). private final RealJenkinsExtension mainController = new RealJenkinsExtension().
withName("main"). withName("main").
withColor(PrefixedOutputStream.Color.BLUE). withColor(PrefixedOutputStream.Color.BLUE).
withLogger(DoubleLaunchChecker.class, Level.FINE); withLogger(DoubleLaunchChecker.class, Level.FINE);
@Rule @RegisterExtension
public RealJenkinsRule duplicateController = new RealJenkinsRule(mainController). private final RealJenkinsExtension duplicateController = new RealJenkinsExtension(mainController).
withName("dupe"). withName("dupe").
withColor(PrefixedOutputStream.Color.RED). withColor(PrefixedOutputStream.Color.RED).
withLogger(DoubleLaunchChecker.class, Level.FINE); withLogger(DoubleLaunchChecker.class, Level.FINE);
@Test @Test
public void activated() throws Throwable { void activated() throws Throwable {
mainController.startJenkins(); mainController.startJenkins();
duplicateController.startJenkins(); duplicateController.startJenkins();
mainController.runRemotely(DoubleLaunchCheckerTest::waitForWarning); mainController.runRemotely(DoubleLaunchCheckerTest::waitForWarning);
} }
private static void waitForWarning(JenkinsRule r) throws Throwable { private static void waitForWarning(JenkinsRule r) {
await().atMost(Duration.ofMinutes(3)).until(ExtensionList.lookupSingleton(DoubleLaunchChecker.class)::isActivated); await().atMost(Duration.ofMinutes(3)).until(ExtensionList.lookupSingleton(DoubleLaunchChecker.class)::isActivated);
} }

View File

@ -33,18 +33,18 @@ import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import jenkins.model.GlobalConfiguration; import jenkins.model.GlobalConfiguration;
import org.junit.Rule; import org.junit.jupiter.api.Test;
import org.junit.Test; import org.junit.jupiter.api.extension.RegisterExtension;
import org.jvnet.hudson.test.JenkinsSessionRule;
import org.jvnet.hudson.test.TestExtension; import org.jvnet.hudson.test.TestExtension;
import org.jvnet.hudson.test.junit.jupiter.JenkinsSessionExtension;
public class XStream2AnnotationTest { class XStream2AnnotationTest {
@Rule @RegisterExtension
public JenkinsSessionRule rr = new JenkinsSessionRule(); public JenkinsSessionExtension rr = new JenkinsSessionExtension();
@Test @Test
public void xStreamAlias() throws Throwable { void xStreamAlias() throws Throwable {
rr.then(r -> { rr.then(r -> {
AnnotatedProcessed annotatedProcessed = AnnotatedProcessed.get(); AnnotatedProcessed annotatedProcessed = AnnotatedProcessed.get();
annotatedProcessed.x = 1; annotatedProcessed.x = 1;
@ -78,6 +78,7 @@ public class XStream2AnnotationTest {
int x; int x;
@SuppressWarnings(value = "checkstyle:redundantmodifier")
public AnnotatedProcessed() { public AnnotatedProcessed() {
getConfigFile().getXStream().processAnnotations(AnnotatedProcessed.class); getConfigFile().getXStream().processAnnotations(AnnotatedProcessed.class);
load(); load();
@ -97,6 +98,7 @@ public class XStream2AnnotationTest {
int x; int x;
@SuppressWarnings(value = "checkstyle:redundantmodifier")
public AnnotatedUnprocessed() { public AnnotatedUnprocessed() {
load(); load();
} }
@ -118,6 +120,7 @@ public class XStream2AnnotationTest {
int x; int x;
@SuppressWarnings(value = "checkstyle:redundantmodifier")
public Programmatic() { public Programmatic() {
getConfigFile().getXStream().alias("myconf-programmatic", Programmatic.class); getConfigFile().getXStream().alias("myconf-programmatic", Programmatic.class);
load(); load();

View File

@ -1,27 +1,27 @@
package jenkins.agents; package jenkins.agents;
import org.junit.Before; import org.junit.jupiter.api.BeforeEach;
import org.junit.Rule; import org.junit.jupiter.api.Test;
import org.junit.Test; import org.junit.jupiter.api.extension.RegisterExtension;
import org.jvnet.hudson.test.InboundAgentRule; import org.jvnet.hudson.test.junit.jupiter.InboundAgentExtension;
import org.jvnet.hudson.test.RealJenkinsRule; import org.jvnet.hudson.test.junit.jupiter.RealJenkinsExtension;
public class InboundAgentTlsTest { class InboundAgentTlsTest {
@Rule @RegisterExtension
public final RealJenkinsRule rjr = new RealJenkinsRule().https(); private final RealJenkinsExtension rjr = new RealJenkinsExtension().https();
@Rule @RegisterExtension
public InboundAgentRule iar = new InboundAgentRule(); private final InboundAgentExtension iar = new InboundAgentExtension();
@Before @BeforeEach
public void setUp() throws Throwable { void setUp() throws Throwable {
rjr.startJenkins(); rjr.startJenkins();
} }
@Test @Test
public void webSocketNoCertificateCheck() throws Throwable { void webSocketNoCertificateCheck() throws Throwable {
var options = InboundAgentRule.Options var options = InboundAgentExtension.Options
.newBuilder() .newBuilder()
.webSocket() .webSocket()
.noCertificateCheck(); .noCertificateCheck();
@ -29,8 +29,8 @@ public class InboundAgentTlsTest {
} }
@Test @Test
public void webSocketWithCertByValue() throws Throwable { void webSocketWithCertByValue() throws Throwable {
var options = InboundAgentRule.Options var options = InboundAgentExtension.Options
.newBuilder() .newBuilder()
.webSocket() .webSocket()
.cert(rjr.getRootCAPem()); .cert(rjr.getRootCAPem());
@ -38,16 +38,16 @@ public class InboundAgentTlsTest {
} }
@Test @Test
public void tcpWithNoCertificateCheck() throws Throwable { void tcpWithNoCertificateCheck() throws Throwable {
var options = InboundAgentRule.Options var options = InboundAgentExtension.Options
.newBuilder() .newBuilder()
.noCertificateCheck(); .noCertificateCheck();
iar.createAgent(rjr, options.build()); iar.createAgent(rjr, options.build());
} }
@Test @Test
public void tcpWithCertByValue() throws Throwable { void tcpWithCertByValue() throws Throwable {
var options = InboundAgentRule.Options var options = InboundAgentExtension.Options
.newBuilder() .newBuilder()
.cert(rjr.getRootCAPem()); .cert(rjr.getRootCAPem());
iar.createAgent(rjr, options.build()); iar.createAgent(rjr, options.build());

View File

@ -45,29 +45,36 @@ import jenkins.security.SlaveToMasterCallable;
import jenkins.slaves.JnlpSlaveAgentProtocol4; import jenkins.slaves.JnlpSlaveAgentProtocol4;
import org.jenkinsci.remoting.engine.JnlpConnectionState; import org.jenkinsci.remoting.engine.JnlpConnectionState;
import org.jenkinsci.remoting.engine.JnlpProtocol4ProxyHandler; import org.jenkinsci.remoting.engine.JnlpProtocol4ProxyHandler;
import org.junit.Rule; import org.junit.jupiter.api.BeforeEach;
import org.junit.Test; import org.junit.jupiter.api.Test;
import org.jvnet.hudson.test.InboundAgentRule; import org.junit.jupiter.api.extension.RegisterExtension;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.TestExtension; import org.jvnet.hudson.test.TestExtension;
import org.jvnet.hudson.test.junit.jupiter.InboundAgentExtension;
import org.jvnet.hudson.test.junit.jupiter.WithJenkins;
/** /**
* Example server counterpart to {@link JnlpProtocol4ProxyHandler}. * Example server counterpart to {@link JnlpProtocol4ProxyHandler}.
*/ */
public final class JnlpProtocol4ProxyHandlerTest { @WithJenkins
class JnlpProtocol4ProxyHandlerTest {
private static final Logger LOGGER = Logger.getLogger(JnlpProtocol4ProxyHandlerTest.class.getName()); private static final Logger LOGGER = Logger.getLogger(JnlpProtocol4ProxyHandlerTest.class.getName());
@Rule @RegisterExtension
public JenkinsRule r = new JenkinsRule(); private final InboundAgentExtension inboundAgents = new InboundAgentExtension();
@Rule private JenkinsRule r;
public InboundAgentRule inboundAgents = new InboundAgentRule();
@BeforeEach
void setUp(JenkinsRule rule) {
r = rule;
}
@Test @Test
public void smokes() throws Exception { void smokes() throws Exception {
// withLogger(JnlpProtocol4ProxyHandler.class, Level.FINE) pointless since log dumper is set up after these messages are printed // withLogger(JnlpProtocol4ProxyHandler.class, Level.FINE) pointless since log dumper is set up after these messages are printed
Slave s = inboundAgents.createAgent(r, InboundAgentRule.Options.newBuilder().secret().build()); Slave s = inboundAgents.createAgent(r, InboundAgentExtension.Options.newBuilder().build());
try { try {
assertThat(s.getChannel().call(new DummyTask()), is("response")); assertThat(s.getChannel().call(new DummyTask()), is("response"));
s.toComputer().getLogText().writeLogTo(0, System.out); s.toComputer().getLogText().writeLogTo(0, System.out);

View File

@ -24,8 +24,8 @@
package jenkins.agents; package jenkins.agents;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import hudson.Functions; import hudson.Functions;
import hudson.model.FreeStyleProject; import hudson.model.FreeStyleProject;
@ -39,36 +39,42 @@ import java.util.Random;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import jenkins.security.SlaveToMasterCallable; import jenkins.security.SlaveToMasterCallable;
import org.junit.ClassRule; import org.junit.jupiter.api.BeforeEach;
import org.junit.Rule; import org.junit.jupiter.api.Test;
import org.junit.Test; import org.junit.jupiter.api.extension.RegisterExtension;
import org.jvnet.hudson.test.BuildWatcher;
import org.jvnet.hudson.test.InboundAgentRule;
import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.LogRecorder;
import org.jvnet.hudson.test.LoggerRule; import org.jvnet.hudson.test.LoggerRule;
import org.jvnet.hudson.test.junit.jupiter.BuildWatcherExtension;
import org.jvnet.hudson.test.junit.jupiter.InboundAgentExtension;
import org.jvnet.hudson.test.junit.jupiter.WithJenkins;
@Issue("JEP-222") @Issue("JEP-222")
@WithJenkins
public class WebSocketAgentsTest { public class WebSocketAgentsTest {
private static final Logger LOGGER = Logger.getLogger(WebSocketAgentsTest.class.getName()); private static final Logger LOGGER = Logger.getLogger(WebSocketAgentsTest.class.getName());
@ClassRule @RegisterExtension
public static BuildWatcher buildWatcher = new BuildWatcher(); private static final BuildWatcherExtension buildWatcher = new BuildWatcherExtension();
@Rule @RegisterExtension
public JenkinsRule r = new JenkinsRule(); private final InboundAgentExtension inboundAgents = new InboundAgentExtension();
@Rule private final LogRecorder logging = new LogRecorder().
public InboundAgentRule inboundAgents = new InboundAgentRule();
@Rule
public LoggerRule logging = new LoggerRule().
record(Slave.class, Level.FINE). record(Slave.class, Level.FINE).
record(SlaveComputer.class, Level.FINEST). record(SlaveComputer.class, Level.FINEST).
record(WebSocketAgents.class, Level.FINEST). record(WebSocketAgents.class, Level.FINEST).
record(Engine.class, Level.FINEST); record(Engine.class, Level.FINEST);
private JenkinsRule r;
@BeforeEach
void setUp(JenkinsRule rule) {
r = rule;
}
/** /**
* Verify basic functionality of an agent in {@code -webSocket} mode. * Verify basic functionality of an agent in {@code -webSocket} mode.
* Requires {@code remoting} to have been {@code mvn install}ed. * Requires {@code remoting} to have been {@code mvn install}ed.
@ -77,8 +83,8 @@ public class WebSocketAgentsTest {
* @see hudson.remoting.Launcher * @see hudson.remoting.Launcher
*/ */
@Test @Test
public void smokes() throws Exception { void smokes() throws Exception {
Slave s = inboundAgents.createAgent(r, InboundAgentRule.Options.newBuilder().secret().webSocket().build()); Slave s = inboundAgents.createAgent(r, InboundAgentExtension.Options.newBuilder().webSocket().build());
try { try {
assertEquals("response", s.getChannel().call(new DummyTask())); assertEquals("response", s.getChannel().call(new DummyTask()));
assertNotNull(s.getChannel().call(new FatTask())); assertNotNull(s.getChannel().call(new FatTask()));

View File

@ -27,54 +27,53 @@ package jenkins.bugs;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsStringIgnoringCase; import static org.hamcrest.Matchers.containsStringIgnoringCase;
import static org.hamcrest.Matchers.endsWithIgnoringCase; import static org.hamcrest.Matchers.endsWithIgnoringCase;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import hudson.model.FreeStyleProject; import hudson.model.FreeStyleProject;
import hudson.security.Messages; import hudson.security.Messages;
import hudson.security.Permission; import hudson.security.Permission;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import jenkins.model.Jenkins; import jenkins.model.Jenkins;
import org.htmlunit.Page; import org.htmlunit.Page;
import org.htmlunit.html.HtmlFormUtil; import org.htmlunit.html.HtmlFormUtil;
import org.htmlunit.html.HtmlPage; import org.htmlunit.html.HtmlPage;
import org.htmlunit.html.HtmlPasswordInput; import org.htmlunit.html.HtmlPasswordInput;
import org.htmlunit.html.HtmlTextInput; import org.htmlunit.html.HtmlTextInput;
import org.junit.Before; import org.junit.jupiter.api.BeforeEach;
import org.junit.Rule; import org.junit.jupiter.api.Test;
import org.junit.Test; import org.junit.jupiter.params.Parameter;
import org.junit.runner.RunWith; import org.junit.jupiter.params.ParameterizedClass;
import org.junit.runners.Parameterized; import org.junit.jupiter.params.provider.ValueSource;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.MockAuthorizationStrategy; import org.jvnet.hudson.test.MockAuthorizationStrategy;
import org.jvnet.hudson.test.junit.jupiter.WithJenkins;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
@RunWith(Parameterized.class) @ParameterizedClass
public class Jenkins64991Test { @ValueSource(strings = { "/jenkins", "" })
@Parameterized.Parameters @WithJenkins
public static List<String> contexts() { class Jenkins64991Test {
return Arrays.asList("/jenkins", "");
}
public Jenkins64991Test(String context) { @Parameter
j.contextPath = context; private String contextPath;
}
@Rule private JenkinsRule j;
public JenkinsRule j = new JenkinsRule();
@Before @BeforeEach
public void setUp() throws Exception { void setUp(JenkinsRule rule) throws Throwable {
j = rule;
j.jenkins.setSecurityRealm(j.createDummySecurityRealm()); j.jenkins.setSecurityRealm(j.createDummySecurityRealm());
j.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy().grant(Permission.READ).everywhere().toEveryone().grant(Jenkins.ADMINISTER).everywhere().to("alice")); j.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy().grant(Permission.READ).everywhere().toEveryone().grant(Jenkins.ADMINISTER).everywhere().to("alice"));
j.createFreeStyleProject("foo bar"); j.createFreeStyleProject("foo bar");
j.contextPath = contextPath;
j.restart();
} }
@Test @Test
public void test403Redirect() throws Exception { void test403Redirect() throws Exception {
final JenkinsRule.WebClient webClient = j.createWebClient().withThrowExceptionOnFailingStatusCode(false); final JenkinsRule.WebClient webClient = j.createWebClient().withThrowExceptionOnFailingStatusCode(false);
final HtmlPage loginPage = webClient.goTo("manage"); final HtmlPage loginPage = webClient.goTo("manage");
@ -90,9 +89,8 @@ public class Jenkins64991Test {
assertThat(redirectedPage.getWebResponse().getContentAsString(), containsStringIgnoringCase(Messages.GlobalSecurityConfiguration_DisplayName())); assertThat(redirectedPage.getWebResponse().getContentAsString(), containsStringIgnoringCase(Messages.GlobalSecurityConfiguration_DisplayName()));
} }
@Test @Test
public void testRedirect() throws Exception { void testRedirect() throws Exception {
final JenkinsRule.WebClient webClient = j.createWebClient(); final JenkinsRule.WebClient webClient = j.createWebClient();
final HtmlPage indexPage = webClient.goTo(""); final HtmlPage indexPage = webClient.goTo("");
@ -114,7 +112,7 @@ public class Jenkins64991Test {
} }
@Test @Test
public void withoutFrom() throws Exception { void withoutFrom() throws Exception {
final JenkinsRule.WebClient webClient = j.createWebClient(); final JenkinsRule.WebClient webClient = j.createWebClient();
final HtmlPage loginPage = webClient.goTo("login"); final HtmlPage loginPage = webClient.goTo("login");
@ -129,7 +127,7 @@ public class Jenkins64991Test {
} }
@Test @Test
public void emptyFrom() throws Exception { void emptyFrom() throws Exception {
final JenkinsRule.WebClient webClient = j.createWebClient(); final JenkinsRule.WebClient webClient = j.createWebClient();
final HtmlPage loginPage = webClient.goTo("login?from="); final HtmlPage loginPage = webClient.goTo("login?from=");
@ -144,7 +142,7 @@ public class Jenkins64991Test {
} }
@Test @Test
public void testRedirectToProject() throws Exception { void testRedirectToProject() throws Exception {
FreeStyleProject freeStyleProject = j.jenkins.getItemByFullName("foo bar", FreeStyleProject.class); FreeStyleProject freeStyleProject = j.jenkins.getItemByFullName("foo bar", FreeStyleProject.class);
assertNotNull(freeStyleProject); assertNotNull(freeStyleProject);
final JenkinsRule.WebClient webClient = j.createWebClient(); final JenkinsRule.WebClient webClient = j.createWebClient();
@ -169,24 +167,24 @@ public class Jenkins64991Test {
} }
@Test @Test
public void absoluteRedirect() throws Exception { void absoluteRedirect() throws Exception {
assertNoOpenRedirect("login?from=https:%2F%2Fjenkins.io"); assertNoOpenRedirect("login?from=https:%2F%2Fjenkins.io");
} }
@Test @Test
public void protocolRelativeRedirect() throws Exception { void protocolRelativeRedirect() throws Exception {
String loginUrl = "login?from=%2F%2Fjenkins.io"; String loginUrl = "login?from=%2F%2Fjenkins.io";
assertNoOpenRedirect(loginUrl); assertNoOpenRedirect(loginUrl);
} }
@Test @Test
public void hostRelativeRedirect() throws Exception { void hostRelativeRedirect() throws Exception {
String loginUrl = "login?from=%2Fjenkins.io"; String loginUrl = "login?from=%2Fjenkins.io";
assertNoOpenRedirect(loginUrl); assertNoOpenRedirect(loginUrl);
} }
@Test @Test
public void relativeRedirect() throws Exception { void relativeRedirect() throws Exception {
String loginUrl = "login?from=jenkins.io"; String loginUrl = "login?from=jenkins.io";
assertNoOpenRedirect(loginUrl); assertNoOpenRedirect(loginUrl);
} }

View File

@ -31,9 +31,9 @@ import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import hudson.ClassicPluginStrategy; import hudson.ClassicPluginStrategy;
import hudson.ExtensionList; import hudson.ExtensionList;
@ -41,7 +41,6 @@ import hudson.PluginManager;
import hudson.PluginManagerUtil; import hudson.PluginManagerUtil;
import hudson.PluginWrapper; import hudson.PluginWrapper;
import hudson.util.VersionNumber; import hudson.util.VersionNumber;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
@ -49,27 +48,28 @@ import java.util.stream.Collectors;
import jenkins.plugins.DetachedPluginsUtil; import jenkins.plugins.DetachedPluginsUtil;
import jenkins.plugins.DetachedPluginsUtil.DetachedPlugin; import jenkins.plugins.DetachedPluginsUtil.DetachedPlugin;
import jenkins.security.UpdateSiteWarningsMonitor; import jenkins.security.UpdateSiteWarningsMonitor;
import org.junit.Ignore; import org.junit.jupiter.api.Disabled;
import org.junit.Rule; import org.junit.jupiter.api.Tag;
import org.junit.Test; import org.junit.jupiter.api.Test;
import org.junit.experimental.categories.Category; import org.junit.jupiter.api.extension.RegisterExtension;
import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.LoggerRule; import org.jvnet.hudson.test.LogRecorder;
import org.jvnet.hudson.test.RestartableJenkinsRule; import org.jvnet.hudson.test.junit.jupiter.JenkinsSessionExtension;
import org.jvnet.hudson.test.SmokeTest;
import org.jvnet.hudson.test.recipes.LocalData; import org.jvnet.hudson.test.recipes.LocalData;
@Category(SmokeTest.class) @Tag("SmokeTest")
public class LoadDetachedPluginsTest { class LoadDetachedPluginsTest {
@Rule public RestartableJenkinsRule rr = PluginManagerUtil.newRestartableJenkinsRule(); @RegisterExtension
@Rule public LoggerRule logging = new LoggerRule(); private final JenkinsSessionExtension rr = PluginManagerUtil.newJenkinsSessionExtension();
private final LogRecorder logging = new LogRecorder();
@Issue("JENKINS-48365") @Issue("JENKINS-48365")
@Test @Test
@LocalData @LocalData
public void upgradeFromJenkins1() throws IOException { void upgradeFromJenkins1() throws Throwable {
VersionNumber since = new VersionNumber("1.490"); VersionNumber since = new VersionNumber("1.490");
rr.then(r -> { rr.then(r -> {
List<DetachedPlugin> detachedPlugins = DetachedPluginsUtil.getDetachedPlugins(since); List<DetachedPlugin> detachedPlugins = DetachedPluginsUtil.getDetachedPlugins(since);
@ -82,9 +82,9 @@ public class LoadDetachedPluginsTest {
} }
@Test @Test
@Ignore("Only useful while updating bundled plugins, otherwise new security warnings fail unrelated builds") @Disabled("Only useful while updating bundled plugins, otherwise new security warnings fail unrelated builds")
@LocalData @LocalData
public void noUpdateSiteWarnings() { void noUpdateSiteWarnings() throws Throwable {
rr.then(r -> { rr.then(r -> {
r.jenkins.getUpdateCenter().updateAllSites(); r.jenkins.getUpdateCenter().updateAllSites();
final UpdateSiteWarningsMonitor monitor = ExtensionList.lookupSingleton(UpdateSiteWarningsMonitor.class); final UpdateSiteWarningsMonitor monitor = ExtensionList.lookupSingleton(UpdateSiteWarningsMonitor.class);
@ -95,7 +95,7 @@ public class LoadDetachedPluginsTest {
@Issue("JENKINS-48365") @Issue("JENKINS-48365")
@Test @Test
@LocalData @LocalData
public void upgradeFromJenkins2() { void upgradeFromJenkins2() throws Throwable {
VersionNumber since = new VersionNumber("2.0"); VersionNumber since = new VersionNumber("2.0");
rr.then(r -> { rr.then(r -> {
List<DetachedPlugin> detachedPlugins = DetachedPluginsUtil.getDetachedPlugins(since); List<DetachedPlugin> detachedPlugins = DetachedPluginsUtil.getDetachedPlugins(since);
@ -108,7 +108,7 @@ public class LoadDetachedPluginsTest {
} }
@Test @Test
public void newInstallation() { void newInstallation() throws Throwable {
rr.then(r -> { rr.then(r -> {
List<DetachedPlugin> detachedPlugins = DetachedPluginsUtil.getDetachedPlugins(); List<DetachedPlugin> detachedPlugins = DetachedPluginsUtil.getDetachedPlugins();
assertThat("Detached plugins should exist", detachedPlugins, not(empty())); assertThat("Detached plugins should exist", detachedPlugins, not(empty()));
@ -128,7 +128,7 @@ public class LoadDetachedPluginsTest {
@Issue("JENKINS-55582") @Issue("JENKINS-55582")
@LocalData @LocalData
@Test @Test
public void installDetachedDependencies() { void installDetachedDependencies() throws Throwable {
logging.record(PluginManager.class, Level.FINE).record(ClassicPluginStrategy.class, Level.FINE); logging.record(PluginManager.class, Level.FINE).record(ClassicPluginStrategy.class, Level.FINE);
rr.then(r -> { rr.then(r -> {
List<String> activePlugins = r.jenkins.getPluginManager().getPlugins().stream().filter(PluginWrapper::isActive).map(PluginWrapper::getShortName).collect(Collectors.toList()); List<String> activePlugins = r.jenkins.getPluginManager().getPlugins().stream().filter(PluginWrapper::isActive).map(PluginWrapper::getShortName).collect(Collectors.toList());
@ -145,14 +145,14 @@ public class LoadDetachedPluginsTest {
private void assertLoader(Class<?> c, String expectedPlugin, JenkinsRule r) { private void assertLoader(Class<?> c, String expectedPlugin, JenkinsRule r) {
PluginWrapper pw = r.jenkins.pluginManager.whichPlugin(c); PluginWrapper pw = r.jenkins.pluginManager.whichPlugin(c);
assertNotNull("did not expect to be loading " + c + " from " + c.getClassLoader(), pw); assertNotNull(pw, "did not expect to be loading " + c + " from " + c.getClassLoader());
assertEquals(expectedPlugin, pw.getShortName()); assertEquals(expectedPlugin, pw.getShortName());
} }
@Issue("JENKINS-55582") @Issue("JENKINS-55582")
@LocalData @LocalData
@Test @Test
public void nonstandardFilenames() { void nonstandardFilenames() throws Throwable {
logging.record(PluginManager.class, Level.FINE).record(ClassicPluginStrategy.class, Level.FINE); logging.record(PluginManager.class, Level.FINE).record(ClassicPluginStrategy.class, Level.FINE);
rr.then(r -> { rr.then(r -> {
assertTrue(r.jenkins.pluginManager.getPlugin("build-token-root").isActive()); assertTrue(r.jenkins.pluginManager.getPlugin("build-token-root").isActive());
@ -170,7 +170,7 @@ public class LoadDetachedPluginsTest {
PluginWrapper wrapper = pluginManager.getPlugin(plugin.getShortName()); PluginWrapper wrapper = pluginManager.getPlugin(plugin.getShortName());
if (wrapper != null) { if (wrapper != null) {
installedPlugins.add(wrapper); installedPlugins.add(wrapper);
assertTrue("Detached plugins should be active if installed", wrapper.isActive()); assertTrue(wrapper.isActive(), "Detached plugins should be active if installed");
assertThat("Detached plugins should not have dependency errors", wrapper.getDependencyErrors(), empty()); assertThat("Detached plugins should not have dependency errors", wrapper.getDependencyErrors(), empty());
} }
} }

View File

@ -1,40 +1,40 @@
package jenkins.install; package jenkins.install;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import hudson.Main; import hudson.Main;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import org.junit.Rule; import org.junit.jupiter.api.Tag;
import org.junit.Test; import org.junit.jupiter.api.Test;
import org.junit.experimental.categories.Category; import org.junit.jupiter.api.extension.RegisterExtension;
import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsSessionRule; import org.jvnet.hudson.test.junit.jupiter.JenkinsSessionExtension;
import org.jvnet.hudson.test.SmokeTest;
@Category(SmokeTest.class) @Tag("SmokeTest")
public class SetupWizardRestartTest { class SetupWizardRestartTest {
@Rule
public JenkinsSessionRule sessions = new JenkinsSessionRule(); @RegisterExtension
private final JenkinsSessionExtension sessions = new JenkinsSessionExtension();
@Issue("JENKINS-47439") @Issue("JENKINS-47439")
@Test @Test
public void restartKeepsSetupWizardState() throws Throwable { void restartKeepsSetupWizardState() throws Throwable {
sessions.then(j -> { sessions.then(j -> {
// Modify state so that we get into the same conditions as a real start // Modify state so that we get into the same conditions as a real start
Main.isUnitTest = false; Main.isUnitTest = false;
Files.writeString(InstallUtil.getLastExecVersionFile().toPath(), "", StandardCharsets.US_ASCII); Files.writeString(InstallUtil.getLastExecVersionFile().toPath(), "", StandardCharsets.US_ASCII);
// Re-evaluate current state based on the new context // Re-evaluate current state based on the new context
InstallUtil.proceedToNextStateFrom(InstallState.UNKNOWN); InstallUtil.proceedToNextStateFrom(InstallState.UNKNOWN);
assertEquals("Unexpected install state", InstallState.NEW, j.jenkins.getInstallState()); assertEquals(InstallState.NEW, j.jenkins.getInstallState(), "Unexpected install state");
assertTrue("Expecting setup wizard filter to be up", j.jenkins.getSetupWizard().hasSetupWizardFilter()); assertTrue(j.jenkins.getSetupWizard().hasSetupWizardFilter(), "Expecting setup wizard filter to be up");
InstallUtil.saveLastExecVersion(); InstallUtil.saveLastExecVersion();
}); });
// Check that the state is retained after a restart // Check that the state is retained after a restart
sessions.then(j -> { sessions.then(j -> {
assertEquals("Unexpected install state", InstallState.NEW, j.jenkins.getInstallState()); assertEquals(InstallState.NEW, j.jenkins.getInstallState(), "Unexpected install state");
assertTrue("Expecting setup wizard filter to be up after restart", j.jenkins.getSetupWizard().hasSetupWizardFilter()); assertTrue(j.jenkins.getSetupWizard().hasSetupWizardFilter(), "Expecting setup wizard filter to be up after restart");
}); });
} }

View File

@ -2,6 +2,8 @@ package jenkins.model;
import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME; import static java.lang.annotation.RetentionPolicy.RUNTIME;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.File; import java.io.File;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
@ -11,72 +13,72 @@ import java.util.Objects;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.junit.Assert; import org.junit.jupiter.api.Test;
import org.junit.Rule; import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.Test;
import org.junit.runner.Description; import org.junit.runner.Description;
import org.jvnet.hudson.test.HudsonHomeLoader; import org.jvnet.hudson.test.HudsonHomeLoader;
import org.jvnet.hudson.test.JenkinsRecipe; import org.jvnet.hudson.test.JenkinsRecipe;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.JenkinsSessionRule; import org.jvnet.hudson.test.junit.jupiter.JenkinsSessionExtension;
import org.jvnet.hudson.test.recipes.LocalData; import org.jvnet.hudson.test.recipes.LocalData;
public class BuiltInNodeMigrationRestartTest { class BuiltInNodeMigrationRestartTest {
@Rule
public JenkinsSessionRule r = new JenkinsSessionRule(); @RegisterExtension
private final JenkinsSessionExtension r = new JenkinsSessionExtension();
@Test @Test
public void testNewInstanceWithoutConfiguration() throws Throwable { void testNewInstanceWithoutConfiguration() throws Throwable {
r.then(j -> { r.then(j -> {
Assert.assertTrue(j.jenkins.getRenameMigrationDone()); assertTrue(j.jenkins.getRenameMigrationDone());
Assert.assertFalse(j.jenkins.nodeRenameMigrationNeeded); assertFalse(j.jenkins.nodeRenameMigrationNeeded);
Assert.assertFalse(Objects.requireNonNull(j.jenkins.getAdministrativeMonitor(BuiltInNodeMigration.class.getName())).isActivated()); assertFalse(Objects.requireNonNull(j.jenkins.getAdministrativeMonitor(BuiltInNodeMigration.class.getName())).isActivated());
}); });
r.then(j -> { r.then(j -> {
Assert.assertTrue(j.jenkins.getRenameMigrationDone()); assertTrue(j.jenkins.getRenameMigrationDone());
Assert.assertFalse(j.jenkins.nodeRenameMigrationNeeded); assertFalse(j.jenkins.nodeRenameMigrationNeeded);
Assert.assertFalse(Objects.requireNonNull(j.jenkins.getAdministrativeMonitor(BuiltInNodeMigration.class.getName())).isActivated()); assertFalse(Objects.requireNonNull(j.jenkins.getAdministrativeMonitor(BuiltInNodeMigration.class.getName())).isActivated());
}); });
} }
@Test @Test
@LocalDataOnce @LocalDataOnce
public void migratedInstanceStartsWithNewTerminology() throws Throwable { void migratedInstanceStartsWithNewTerminology() throws Throwable {
r.then(j -> { r.then(j -> {
Assert.assertTrue(j.jenkins.getRenameMigrationDone()); assertTrue(j.jenkins.getRenameMigrationDone());
Assert.assertFalse(j.jenkins.nodeRenameMigrationNeeded); assertFalse(j.jenkins.nodeRenameMigrationNeeded);
Assert.assertFalse(Objects.requireNonNull(j.jenkins.getAdministrativeMonitor(BuiltInNodeMigration.class.getName())).isActivated()); assertFalse(Objects.requireNonNull(j.jenkins.getAdministrativeMonitor(BuiltInNodeMigration.class.getName())).isActivated());
}); });
r.then(j -> { r.then(j -> {
Assert.assertTrue(j.jenkins.getRenameMigrationDone()); assertTrue(j.jenkins.getRenameMigrationDone());
Assert.assertFalse(j.jenkins.nodeRenameMigrationNeeded); assertFalse(j.jenkins.nodeRenameMigrationNeeded);
Assert.assertFalse(Objects.requireNonNull(j.jenkins.getAdministrativeMonitor(BuiltInNodeMigration.class.getName())).isActivated()); assertFalse(Objects.requireNonNull(j.jenkins.getAdministrativeMonitor(BuiltInNodeMigration.class.getName())).isActivated());
}); });
} }
@Test @Test
@LocalDataOnce @LocalDataOnce
public void oldDataStartsWithOldTerminology() throws Throwable { void oldDataStartsWithOldTerminology() throws Throwable {
r.then(j -> { r.then(j -> {
Assert.assertFalse(j.jenkins.getRenameMigrationDone()); assertFalse(j.jenkins.getRenameMigrationDone());
Assert.assertTrue(j.jenkins.nodeRenameMigrationNeeded); assertTrue(j.jenkins.nodeRenameMigrationNeeded);
Assert.assertTrue(Objects.requireNonNull(j.jenkins.getAdministrativeMonitor(BuiltInNodeMigration.class.getName())).isActivated()); assertTrue(Objects.requireNonNull(j.jenkins.getAdministrativeMonitor(BuiltInNodeMigration.class.getName())).isActivated());
}); });
r.then(j -> { r.then(j -> {
Assert.assertFalse(j.jenkins.getRenameMigrationDone()); assertFalse(j.jenkins.getRenameMigrationDone());
Assert.assertTrue(j.jenkins.nodeRenameMigrationNeeded); assertTrue(j.jenkins.nodeRenameMigrationNeeded);
Assert.assertTrue(Objects.requireNonNull(j.jenkins.getAdministrativeMonitor(BuiltInNodeMigration.class.getName())).isActivated()); assertTrue(Objects.requireNonNull(j.jenkins.getAdministrativeMonitor(BuiltInNodeMigration.class.getName())).isActivated());
j.jenkins.performRenameMigration(); j.jenkins.performRenameMigration();
Assert.assertTrue(j.jenkins.getRenameMigrationDone()); assertTrue(j.jenkins.getRenameMigrationDone());
Assert.assertFalse(j.jenkins.nodeRenameMigrationNeeded); assertFalse(j.jenkins.nodeRenameMigrationNeeded);
Assert.assertFalse(Objects.requireNonNull(j.jenkins.getAdministrativeMonitor(BuiltInNodeMigration.class.getName())).isActivated()); assertFalse(Objects.requireNonNull(j.jenkins.getAdministrativeMonitor(BuiltInNodeMigration.class.getName())).isActivated());
}); });
r.then(j -> { r.then(j -> {
Assert.assertTrue(j.jenkins.getRenameMigrationDone()); assertTrue(j.jenkins.getRenameMigrationDone());
Assert.assertFalse(j.jenkins.nodeRenameMigrationNeeded); assertFalse(j.jenkins.nodeRenameMigrationNeeded);
Assert.assertFalse(Objects.requireNonNull(j.jenkins.getAdministrativeMonitor(BuiltInNodeMigration.class.getName())).isActivated()); assertFalse(Objects.requireNonNull(j.jenkins.getAdministrativeMonitor(BuiltInNodeMigration.class.getName())).isActivated());
}); });
} }
@ -94,7 +96,7 @@ public class BuiltInNodeMigrationRestartTest {
@Override @Override
public void setup(JenkinsRule jenkinsRule, LocalDataOnce recipe) throws Exception { public void setup(JenkinsRule jenkinsRule, LocalDataOnce recipe) throws Exception {
Description desc = jenkinsRule.getTestDescription(); Description desc = jenkinsRule.getTestDescription();
method = desc.getTestClass().getMethod((desc.getMethodName())); method = desc.getTestClass().getDeclaredMethod((desc.getMethodName()));
} }
@Override @Override

View File

@ -3,46 +3,49 @@ package jenkins.model;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import hudson.ExtensionList; import hudson.ExtensionList;
import java.net.URL; import java.net.URL;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
import jenkins.security.ResourceDomainConfiguration; import jenkins.security.ResourceDomainConfiguration;
import org.htmlunit.FailingHttpStatusCodeException; import org.htmlunit.FailingHttpStatusCodeException;
import org.htmlunit.Page; import org.htmlunit.Page;
import org.htmlunit.html.HtmlPage; import org.htmlunit.html.HtmlPage;
import org.junit.Assert; import org.junit.jupiter.api.BeforeEach;
import org.junit.Rule; import org.junit.jupiter.api.Test;
import org.junit.Test; import org.junit.jupiter.params.Parameter;
import org.junit.runner.RunWith; import org.junit.jupiter.params.ParameterizedClass;
import org.junit.runners.Parameterized; import org.junit.jupiter.params.provider.ValueSource;
import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.MockAuthorizationStrategy; import org.jvnet.hudson.test.MockAuthorizationStrategy;
import org.jvnet.hudson.test.junit.jupiter.WithJenkins;
import org.kohsuke.stapler.Dispatcher; import org.kohsuke.stapler.Dispatcher;
@RunWith(Parameterized.class) @ParameterizedClass
public class ErrorPageTest { @ValueSource(strings = { "/jenkins", "" })
@WithJenkins
class ErrorPageTest {
@Rule @Parameter
public JenkinsRule j = new JenkinsRule(); private String contextPath;
@Parameterized.Parameters private JenkinsRule j;
public static List<String> contexts() {
return Arrays.asList("/jenkins", "");
}
public ErrorPageTest(String context) { @BeforeEach
j.contextPath = context; void setUp(JenkinsRule rule) throws Throwable {
j = rule;
j.contextPath = contextPath;
j.restart();
} }
@Test @Test
@Issue("JENKINS-71087") @Issue("JENKINS-71087")
public void nice404ErrorPage() throws Exception { void nice404ErrorPage() throws Exception {
try (JenkinsRule.WebClient wc = j.createWebClient()) { try (JenkinsRule.WebClient wc = j.createWebClient()) {
Dispatcher.TRACE = false; Dispatcher.TRACE = false;
@ -151,11 +154,11 @@ public class ErrorPageTest {
@Test @Test
@Issue("JENKINS-71087") @Issue("JENKINS-71087")
public void kindaNice404ErrorPageOnResourceDomain() throws Exception { void kindaNice404ErrorPageOnResourceDomain() throws Exception {
final String resourceRoot; final String resourceRoot;
{ // Setup stolen from ResourceDomainTest { // Setup stolen from ResourceDomainTest
URL root = j.getURL(); // which always will use "localhost", see JenkinsRule#getURL() URL root = j.getURL(); // which always will use "localhost", see JenkinsRule#getURL()
Assert.assertTrue(root.toString().contains("localhost")); // to be safe assertTrue(root.toString().contains("localhost")); // to be safe
resourceRoot = root.toString().replace("localhost", "127.0.0.1"); resourceRoot = root.toString().replace("localhost", "127.0.0.1");
ResourceDomainConfiguration configuration = ExtensionList.lookupSingleton(ResourceDomainConfiguration.class); ResourceDomainConfiguration configuration = ExtensionList.lookupSingleton(ResourceDomainConfiguration.class);

View File

@ -2,17 +2,19 @@ package jenkins.model;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.Assert.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.Assume.assumeFalse; import static org.junit.jupiter.api.Assertions.fail;
import static org.junit.jupiter.api.Assumptions.assumeFalse;
import hudson.Functions; import hudson.Functions;
import hudson.init.InitMilestone; import hudson.init.InitMilestone;
import hudson.model.FreeStyleBuild; import hudson.model.FreeStyleBuild;
import hudson.model.FreeStyleProject; import hudson.model.FreeStyleProject;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
@ -21,47 +23,46 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.junit.After; import org.junit.jupiter.api.AfterEach;
import org.junit.Before; import org.junit.jupiter.api.BeforeEach;
import org.junit.ClassRule; import org.junit.jupiter.api.Disabled;
import org.junit.Ignore; import org.junit.jupiter.api.Test;
import org.junit.Rule; import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.Test; import org.junit.jupiter.api.io.TempDir;
import org.junit.rules.TemporaryFolder; import org.jvnet.hudson.reactor.ReactorException;
import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.LoggerRule; import org.jvnet.hudson.test.LogRecorder;
import org.jvnet.hudson.test.MockFolder; import org.jvnet.hudson.test.MockFolder;
import org.jvnet.hudson.test.RestartableJenkinsRule; import org.jvnet.hudson.test.junit.jupiter.JenkinsSessionExtension;
import org.jvnet.hudson.test.recipes.LocalData; import org.jvnet.hudson.test.recipes.LocalData;
/** /**
* Since JENKINS-50164, Jenkins#workspacesDir and Jenkins#buildsDir had their associated UI deleted. * Since JENKINS-50164, Jenkins#workspacesDir and Jenkins#buildsDir had their associated UI deleted.
* So instead of configuring through the UI, we now have to use sysprops for this. * So instead of configuring through the UI, we now have to use sysprops for this.
* <p> * <p>
* So this test class uses a {@link RestartableJenkinsRule} to check the behaviour of this sysprop being * So this test class uses a {@link JenkinsSessionExtension} to check the behaviour of this sysprop being
* present or not between two restarts. * present or not between two restarts.
*/ */
public class JenkinsBuildsAndWorkspacesDirectoriesTest { class JenkinsBuildsAndWorkspacesDirectoriesTest {
private static final String LOG_WHEN_CHANGING_BUILDS_DIR = "Changing builds directories from "; private static final String LOG_WHEN_CHANGING_BUILDS_DIR = "Changing builds directories from ";
private static final String LOG_WHEN_CHANGING_WORKSPACES_DIR = "Changing workspaces directories from "; private static final String LOG_WHEN_CHANGING_WORKSPACES_DIR = "Changing workspaces directories from ";
@Rule @RegisterExtension
public RestartableJenkinsRule story = new RestartableJenkinsRule(); private final JenkinsSessionExtension story = new JenkinsSessionExtension();
@Rule private final LogRecorder loggerRule = new LogRecorder();
public LoggerRule loggerRule = new LoggerRule();
@ClassRule @TempDir
public static TemporaryFolder tmp = new TemporaryFolder(); private static File tmp;
@Before @BeforeEach
public void before() { void before() {
clearSystemProperties(); clearSystemProperties();
} }
@After @AfterEach
public void after() { void after() {
clearSystemProperties(); clearSystemProperties();
} }
@ -72,7 +73,7 @@ public class JenkinsBuildsAndWorkspacesDirectoriesTest {
@Issue("JENKINS-53284") @Issue("JENKINS-53284")
@Test @Test
public void changeWorkspacesDirLog() throws Exception { void changeWorkspacesDirLog() throws Throwable {
loggerRule.record(Jenkins.class, Level.WARNING) loggerRule.record(Jenkins.class, Level.WARNING)
.record(Jenkins.class, Level.INFO).capture(1000); .record(Jenkins.class, Level.INFO).capture(1000);
@ -92,7 +93,7 @@ public class JenkinsBuildsAndWorkspacesDirectoriesTest {
@Issue("JENKINS-50164") @Issue("JENKINS-50164")
@Test @Test
public void badValueForBuildsDir() { void badValueForBuildsDir() throws Throwable {
story.then(rule -> { story.then(rule -> {
final List<String> badValues = new ArrayList<>(Arrays.asList( final List<String> badValues = new ArrayList<>(Arrays.asList(
"blah", "blah",
@ -108,14 +109,14 @@ public class JenkinsBuildsAndWorkspacesDirectoriesTest {
} // else perhaps running as root } // else perhaps running as root
for (String badValue : badValues) { for (String badValue : badValues) {
assertThrows(badValue + " should have been rejected", InvalidBuildsDir.class, () -> Jenkins.checkRawBuildsDir(badValue)); assertThrows(InvalidBuildsDir.class, () -> Jenkins.checkRawBuildsDir(badValue), badValue + " should have been rejected");
} }
}); });
} }
@Issue("JENKINS-50164") @Issue("JENKINS-50164")
@Test @Test
public void goodValueForBuildsDir() { void goodValueForBuildsDir() throws Throwable {
story.then(rule -> { story.then(rule -> {
final List<String> badValues = Arrays.asList( final List<String> badValues = Arrays.asList(
"$JENKINS_HOME/foo/$ITEM_FULL_NAME", "$JENKINS_HOME/foo/$ITEM_FULL_NAME",
@ -129,31 +130,29 @@ public class JenkinsBuildsAndWorkspacesDirectoriesTest {
@Issue("JENKINS-50164") @Issue("JENKINS-50164")
@Test @Test
public void jenkinsDoesNotStartWithBadSysProp() { void jenkinsDoesNotStartWithBadSysProp() throws Throwable {
loggerRule.record(Jenkins.class, Level.WARNING) loggerRule.record(Jenkins.class, Level.WARNING)
.record(Jenkins.class, Level.INFO) .record(Jenkins.class, Level.INFO)
.capture(100); .capture(100);
story.then(rule -> { story.then(rule -> {
assertTrue(story.j.getInstance().isDefaultBuildDir()); assertTrue(rule.getInstance().isDefaultBuildDir());
setBuildsDirProperty("/bluh"); setBuildsDirProperty("/bluh");
}); });
story.thenDoesNotStart(); assertThrows(ReactorException.class, () -> story.then(step -> fail("should have failed before reaching here.")));
} }
@Issue("JENKINS-50164") @Issue("JENKINS-50164")
@Test @Test
public void jenkinsDoesNotStartWithScrewedUpConfigXml() { void jenkinsDoesNotStartWithScrewedUpConfigXml() throws Throwable {
loggerRule.record(Jenkins.class, Level.WARNING) loggerRule.record(Jenkins.class, Level.WARNING)
.record(Jenkins.class, Level.INFO) .record(Jenkins.class, Level.INFO)
.capture(100); .capture(100);
story.then(rule -> { story.then(rule -> {
assertTrue(story.j.getInstance().isDefaultBuildDir()); assertTrue(rule.getInstance().isDefaultBuildDir());
// Now screw up the value by writing into the file directly, like one could do using external XML manipulation tools // Now screw up the value by writing into the file directly, like one could do using external XML manipulation tools
final Path configFile = rule.jenkins.getRootDir().toPath().resolve("config.xml"); final Path configFile = rule.jenkins.getRootDir().toPath().resolve("config.xml");
@ -162,12 +161,12 @@ public class JenkinsBuildsAndWorkspacesDirectoriesTest {
Files.writeString(configFile, screwedUp, StandardCharsets.UTF_8); Files.writeString(configFile, screwedUp, StandardCharsets.UTF_8);
}); });
story.thenDoesNotStart(); assertThrows(ReactorException.class, () -> story.then(step -> fail("should have failed before reaching here.")));
} }
@Issue("JENKINS-50164") @Issue("JENKINS-50164")
@Test @Test
public void buildsDir() throws Exception { void buildsDir() throws Throwable {
loggerRule.record(Jenkins.class, Level.WARNING) loggerRule.record(Jenkins.class, Level.WARNING)
.record(Jenkins.class, Level.INFO) .record(Jenkins.class, Level.INFO)
.capture(100); .capture(100);
@ -175,14 +174,14 @@ public class JenkinsBuildsAndWorkspacesDirectoriesTest {
story.then(step -> assertFalse(logWasFound("Using non default builds directories"))); story.then(step -> assertFalse(logWasFound("Using non default builds directories")));
story.then(steps -> { story.then(steps -> {
assertTrue(story.j.getInstance().isDefaultBuildDir()); assertTrue(steps.getInstance().isDefaultBuildDir());
setBuildsDirProperty("$JENKINS_HOME/plouf/$ITEM_FULL_NAME/bluh"); setBuildsDirProperty("$JENKINS_HOME/plouf/$ITEM_FULL_NAME/bluh");
assertFalse(JenkinsBuildsAndWorkspacesDirectoriesTest.this.logWasFound(LOG_WHEN_CHANGING_BUILDS_DIR)); assertFalse(JenkinsBuildsAndWorkspacesDirectoriesTest.this.logWasFound(LOG_WHEN_CHANGING_BUILDS_DIR));
}); });
story.then(step -> { story.then(step -> {
assertFalse(story.j.getInstance().isDefaultBuildDir()); assertFalse(step.getInstance().isDefaultBuildDir());
assertEquals("$JENKINS_HOME/plouf/$ITEM_FULL_NAME/bluh", story.j.getInstance().getRawBuildsDir()); assertEquals("$JENKINS_HOME/plouf/$ITEM_FULL_NAME/bluh", step.getInstance().getRawBuildsDir());
assertTrue(logWasFound("Changing builds directories from ")); assertTrue(logWasFound("Changing builds directories from "));
} }
); );
@ -193,7 +192,7 @@ public class JenkinsBuildsAndWorkspacesDirectoriesTest {
@Issue("JENKINS-50164") @Issue("JENKINS-50164")
@Test @Test
public void workspacesDir() throws Exception { void workspacesDir() throws Throwable {
loggerRule.record(Jenkins.class, Level.WARNING) loggerRule.record(Jenkins.class, Level.WARNING)
.record(Jenkins.class, Level.INFO) .record(Jenkins.class, Level.INFO)
.capture(1000); .capture(1000);
@ -201,33 +200,32 @@ public class JenkinsBuildsAndWorkspacesDirectoriesTest {
story.then(step -> assertFalse(logWasFound("Using non default workspaces directories"))); story.then(step -> assertFalse(logWasFound("Using non default workspaces directories")));
story.then(step -> { story.then(step -> {
assertTrue(story.j.getInstance().isDefaultWorkspaceDir()); assertTrue(step.getInstance().isDefaultWorkspaceDir());
final String workspacesDir = "bluh"; final String workspacesDir = "bluh";
setWorkspacesDirProperty(workspacesDir); setWorkspacesDirProperty(workspacesDir);
assertFalse(logWasFound("Changing workspaces directories from ")); assertFalse(logWasFound("Changing workspaces directories from "));
}); });
story.then(step -> { story.then(step -> {
assertFalse(story.j.getInstance().isDefaultWorkspaceDir()); assertFalse(step.getInstance().isDefaultWorkspaceDir());
assertEquals("bluh", story.j.getInstance().getRawWorkspaceDir()); assertEquals("bluh", step.getInstance().getRawWorkspaceDir());
assertTrue(logWasFound("Changing workspaces directories from ")); assertTrue(logWasFound("Changing workspaces directories from "));
}); });
story.then(step -> { story.then(step -> {
assertFalse(story.j.getInstance().isDefaultWorkspaceDir()); assertFalse(step.getInstance().isDefaultWorkspaceDir());
assertTrue(logWasFound("Using non default workspaces directories")); assertTrue(logWasFound("Using non default workspaces directories"));
} }
); );
} }
@Ignore("TODO calling restart seems to break Surefire") @Disabled("TODO calling restart seems to break Surefire")
@Issue("JENKINS-50164") @Issue("JENKINS-50164")
@LocalData @LocalData
@Test @Test
public void fromPreviousCustomSetup() { void fromPreviousCustomSetup() throws Throwable {
assumeFalse(Functions.isWindows(), "Default Windows lifecycle does not support restart.");
assumeFalse("Default Windows lifecycle does not support restart.", Functions.isWindows());
// check starting point and change config for next run // check starting point and change config for next run
final String newBuildsDirValueBySysprop = "/tmp/${ITEM_ROOTDIR}/bluh"; final String newBuildsDirValueBySysprop = "/tmp/${ITEM_ROOTDIR}/bluh";
@ -283,20 +281,19 @@ public class JenkinsBuildsAndWorkspacesDirectoriesTest {
@Test @Test
@Issue("JENKINS-17138") @Issue("JENKINS-17138")
public void externalBuildDirectoryRenameDelete() throws Exception { void externalBuildDirectoryRenameDelete() throws Throwable {
// Hack to get String builds usable in lambda below // Hack to get String builds usable in lambda below
final List<String> builds = new ArrayList<>(); final List<String> builds = new ArrayList<>();
story.then(steps -> { story.then(steps -> {
builds.add(tmp.newFolder().toString()); builds.add(newFolder(tmp, "junit").toString());
assertTrue(story.j.getInstance().isDefaultBuildDir()); assertTrue(steps.getInstance().isDefaultBuildDir());
setBuildsDirProperty(builds.get(0) + "/${ITEM_FULL_NAME}"); setBuildsDirProperty(builds.get(0) + "/${ITEM_FULL_NAME}");
}); });
story.then(steps -> { story.then(steps -> {
assertEquals(builds.get(0) + "/${ITEM_FULL_NAME}", story.j.jenkins.getRawBuildsDir()); assertEquals(builds.get(0) + "/${ITEM_FULL_NAME}", steps.jenkins.getRawBuildsDir());
FreeStyleProject p = story.j.jenkins.createProject(MockFolder.class, "d").createProject(FreeStyleProject.class, "prj"); FreeStyleProject p = steps.jenkins.createProject(MockFolder.class, "d").createProject(FreeStyleProject.class, "prj");
FreeStyleBuild b = p.scheduleBuild2(0).get(); FreeStyleBuild b = p.scheduleBuild2(0).get();
File oldBuildDir = new File(builds.get(0), "d/prj"); File oldBuildDir = new File(builds.get(0), "d/prj");
assertEquals(new File(oldBuildDir, b.getId()), b.getRootDir()); assertEquals(new File(oldBuildDir, b.getId()), b.getRootDir());
@ -310,4 +307,13 @@ public class JenkinsBuildsAndWorkspacesDirectoriesTest {
}); });
} }
private static File newFolder(File root, String... subDirs) throws IOException {
String subFolder = String.join("/", subDirs);
File result = new File(root, subFolder);
if (!result.mkdirs()) {
throw new IOException("Couldn't create folders " + root);
}
return result;
}
} }

View File

@ -3,14 +3,16 @@ package jenkins.model;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.Assert.assertNull; import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import hudson.model.FreeStyleProject; import hudson.model.FreeStyleProject;
import hudson.model.Label; import hudson.model.Label;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URL; import java.net.URL;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
@ -22,74 +24,44 @@ import org.htmlunit.html.HtmlForm;
import org.htmlunit.html.HtmlFormUtil; import org.htmlunit.html.HtmlFormUtil;
import org.htmlunit.html.HtmlInput; import org.htmlunit.html.HtmlInput;
import org.htmlunit.html.HtmlPage; import org.htmlunit.html.HtmlPage;
import org.junit.Rule; import org.junit.jupiter.api.Test;
import org.junit.Test; import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.junit.jupiter.JenkinsSessionExtension;
import org.jvnet.hudson.test.recipes.LocalData; import org.jvnet.hudson.test.recipes.LocalData;
/** /**
* @author Kohsuke Kawaguchi * @author Kohsuke Kawaguchi
*/ */
public class JenkinsLocationConfigurationTest { class JenkinsLocationConfigurationTest {
private String lastRootUrlReturned; private static String lastRootUrlReturned;
private boolean lastRootUrlSet; private static boolean lastRootUrlSet;
@Rule @RegisterExtension
public JenkinsRule j = new JenkinsRule() { public JenkinsSessionExtension session = new CustomJenkinsSessionExtension();
@Override
public URL getURL() throws IOException {
// first call for the "Running on xxx" log message, Jenkins not being set at that point
// and the second call is to set the rootUrl of the JLC inside the JenkinsRule#init
if (Jenkins.getInstanceOrNull() != null) {
// only useful for doNotAcceptNonHttpBasedRootURL_fromConfigXml
lastRootUrlReturned = JenkinsLocationConfiguration.getOrDie().getUrl();
lastRootUrlSet = true;
}
return super.getURL();
}
};
/** /**
* Makes sure the use of "localhost" in the Hudson URL reports a warning. * Makes sure the use of "localhost" in the Hudson URL reports a warning.
*/ */
@Test @Test
public void localhostWarning() throws Exception { void localhostWarning() throws Throwable {
HtmlPage p = j.createWebClient().goTo("configure"); session.then(j -> {
HtmlInput url = p.getFormByName("config").getInputByName("_.url"); HtmlPage p = j.createWebClient().goTo("configure");
url.setValue("http://localhost:1234/"); HtmlInput url = p.getFormByName("config").getInputByName("_.url");
assertThat(p.getDocumentElement().getTextContent(), containsString("instead of localhost")); url.setValue("http://localhost:1234/");
assertThat(p.getDocumentElement().getTextContent(), containsString("instead of localhost"));
});
} }
@Test @Test
@Issue("SECURITY-1471") @Issue("SECURITY-1471")
public void doNotAcceptNonHttpBasedRootURL_fromUI() throws Exception { void doNotAcceptNonHttpBasedRootURL_fromUI() throws Throwable {
// in JenkinsRule, the URL is set to the current URL session.then(j -> {
JenkinsLocationConfiguration.getOrDie().setUrl(null);
JenkinsRule.WebClient wc = j.createWebClient();
assertNull(JenkinsLocationConfiguration.getOrDie().getUrl());
settingRootURL("javascript:alert(123);//");
// no impact on the url in memory
assertNull(JenkinsLocationConfiguration.getOrDie().getUrl());
Path configFile = j.jenkins.getRootDir().toPath().resolve("jenkins.model.JenkinsLocationConfiguration.xml");
String configFileContent = Files.readString(configFile, StandardCharsets.UTF_8);
assertThat(configFileContent, containsString("JenkinsLocationConfiguration"));
assertThat(configFileContent, not(containsString("javascript:alert(123);//")));
}
@Test
@Issue("SECURITY-1471")
public void escapeHatch_acceptNonHttpBasedRootURL_fromUI() throws Exception {
boolean previousValue = JenkinsLocationConfiguration.DISABLE_URL_VALIDATION;
JenkinsLocationConfiguration.DISABLE_URL_VALIDATION = true;
try {
// in JenkinsRule, the URL is set to the current URL // in JenkinsRule, the URL is set to the current URL
JenkinsLocationConfiguration.getOrDie().setUrl(null); JenkinsLocationConfiguration.getOrDie().setUrl(null);
@ -97,100 +69,187 @@ public class JenkinsLocationConfigurationTest {
assertNull(JenkinsLocationConfiguration.getOrDie().getUrl()); assertNull(JenkinsLocationConfiguration.getOrDie().getUrl());
String expectedUrl = "weirdSchema:somethingAlsoWeird"; settingRootURL(j, "javascript:alert(123);//");
settingRootURL(expectedUrl);
// the method ensures there is an trailing slash // no impact on the url in memory
assertEquals(expectedUrl + "/", JenkinsLocationConfiguration.getOrDie().getUrl()); assertNull(JenkinsLocationConfiguration.getOrDie().getUrl());
Path configFile = j.jenkins.getRootDir().toPath().resolve("jenkins.model.JenkinsLocationConfiguration.xml"); Path configFile = j.jenkins.getRootDir().toPath().resolve("jenkins.model.JenkinsLocationConfiguration.xml");
String configFileContent = Files.readString(configFile, StandardCharsets.UTF_8); String configFileContent = Files.readString(configFile, StandardCharsets.UTF_8);
assertThat(configFileContent, containsString("JenkinsLocationConfiguration")); assertThat(configFileContent, containsString("JenkinsLocationConfiguration"));
assertThat(configFileContent, containsString(expectedUrl)); assertThat(configFileContent, not(containsString("javascript:alert(123);//")));
} });
finally { }
JenkinsLocationConfiguration.DISABLE_URL_VALIDATION = previousValue;
} @Test
@Issue("SECURITY-1471")
void escapeHatch_acceptNonHttpBasedRootURL_fromUI() throws Throwable {
session.then(j -> {
boolean previousValue = JenkinsLocationConfiguration.DISABLE_URL_VALIDATION;
JenkinsLocationConfiguration.DISABLE_URL_VALIDATION = true;
try {
// in JenkinsRule, the URL is set to the current URL
JenkinsLocationConfiguration.getOrDie().setUrl(null);
JenkinsRule.WebClient wc = j.createWebClient();
assertNull(JenkinsLocationConfiguration.getOrDie().getUrl());
String expectedUrl = "weirdSchema:somethingAlsoWeird";
settingRootURL(j, expectedUrl);
// the method ensures there is an trailing slash
assertEquals(expectedUrl + "/", JenkinsLocationConfiguration.getOrDie().getUrl());
Path configFile = j.jenkins.getRootDir().toPath().resolve("jenkins.model.JenkinsLocationConfiguration.xml");
String configFileContent = Files.readString(configFile, StandardCharsets.UTF_8);
assertThat(configFileContent, containsString("JenkinsLocationConfiguration"));
assertThat(configFileContent, containsString(expectedUrl));
} finally {
JenkinsLocationConfiguration.DISABLE_URL_VALIDATION = previousValue;
}
});
} }
@Test @Test
@Issue("SECURITY-1471") @Issue("SECURITY-1471")
@LocalData("xssThroughConfigXml") @LocalData("xssThroughConfigXml")
public void doNotAcceptNonHttpBasedRootURL_fromConfigXml() { void doNotAcceptNonHttpBasedRootURL_fromConfigXml() throws Throwable {
// in JenkinsRule, the URL is set to the current URL, even if coming from LocalData session.then(j -> {
// so we need to catch the last value before the getUrl from the JenkinsRule that will be used to set the rootUrl // in JenkinsRule, the URL is set to the current URL, even if coming from LocalData
assertNull(lastRootUrlReturned); // so we need to catch the last value before the getUrl from the JenkinsRule that will be used to set the rootUrl
assertTrue(lastRootUrlSet); assertNull(lastRootUrlReturned);
assertTrue(lastRootUrlSet);
assertThat(JenkinsLocationConfiguration.getOrDie().getUrl(), not(containsString("javascript"))); assertThat(JenkinsLocationConfiguration.getOrDie().getUrl(), not(containsString("javascript")));
});
} }
@Test @Test
@Issue("SECURITY-1471") @Issue("SECURITY-1471")
public void cannotInjectJavaScriptUsingRootUrl_inNewViewLink() throws Exception { void cannotInjectJavaScriptUsingRootUrl_inNewViewLink() throws Throwable {
JenkinsRule.WebClient wc = j.createWebClient(); session.then(j -> {
j.createFreeStyleProject(); JenkinsRule.WebClient wc = j.createWebClient();
j.createFreeStyleProject();
settingRootURL("javascript:alert(123);//"); settingRootURL(j, "javascript:alert(123);//");
// setup the victim // setup the victim
AtomicReference<Boolean> alertAppeared = new AtomicReference<>(false); AtomicReference<Boolean> alertAppeared = new AtomicReference<>(false);
wc.setAlertHandler((page, s) -> alertAppeared.set(true)); wc.setAlertHandler((page, s) -> alertAppeared.set(true));
HtmlPage page = wc.goTo(""); HtmlPage page = wc.goTo("");
HtmlAnchor newViewLink = page.getDocumentElement().getElementsByTagName("a").stream() HtmlAnchor newViewLink = page.getDocumentElement().getElementsByTagName("a").stream()
.filter(HtmlAnchor.class::isInstance).map(HtmlAnchor.class::cast) .filter(HtmlAnchor.class::isInstance).map(HtmlAnchor.class::cast)
.filter(a -> a.getHrefAttribute().endsWith("newView")) .filter(a -> a.getHrefAttribute().endsWith("newView"))
.findFirst().orElseThrow(AssertionError::new); .findFirst().orElseThrow(AssertionError::new);
// last verification // last verification
assertFalse(alertAppeared.get()); assertFalse(alertAppeared.get());
HtmlElementUtil.click(newViewLink); HtmlElementUtil.click(newViewLink);
assertFalse(alertAppeared.get()); assertFalse(alertAppeared.get());
});
} }
@Test @Test
@Issue("SECURITY-1471") @Issue("SECURITY-1471")
public void cannotInjectJavaScriptUsingRootUrl_inLabelAbsoluteLink() throws Exception { void cannotInjectJavaScriptUsingRootUrl_inLabelAbsoluteLink() throws Throwable {
String builtInLabel = "builtin-node"; session.then(j -> {
j.jenkins.setLabelString(builtInLabel); String builtInLabel = "builtin-node";
j.jenkins.setLabelString(builtInLabel);
JenkinsRule.WebClient wc = j.createWebClient(); JenkinsRule.WebClient wc = j.createWebClient();
settingRootURL("javascript:alert(123);//"); settingRootURL(j, "javascript:alert(123);//");
// setup the victim // setup the victim
AtomicReference<Boolean> alertAppeared = new AtomicReference<>(false); AtomicReference<Boolean> alertAppeared = new AtomicReference<>(false);
wc.setAlertHandler((page, s) -> alertAppeared.set(true)); wc.setAlertHandler((page, s) -> alertAppeared.set(true));
FreeStyleProject p = j.createFreeStyleProject(); FreeStyleProject p = j.createFreeStyleProject();
p.setAssignedLabel(Label.get(builtInLabel)); p.setAssignedLabel(Label.get(builtInLabel));
HtmlPage projectConfigurePage = wc.getPage(p, "/configure"); HtmlPage projectConfigurePage = wc.getPage(p, "/configure");
HtmlAnchor labelAnchor = projectConfigurePage.getDocumentElement().getElementsByTagName("a").stream() HtmlAnchor labelAnchor = projectConfigurePage.getDocumentElement().getElementsByTagName("a").stream()
.filter(HtmlAnchor.class::isInstance).map(HtmlAnchor.class::cast) .filter(HtmlAnchor.class::isInstance).map(HtmlAnchor.class::cast)
.filter(a -> a.getHrefAttribute().contains("/label/")) .filter(a -> a.getHrefAttribute().contains("/label/"))
.findFirst().orElseThrow(AssertionError::new); .findFirst().orElseThrow(AssertionError::new);
assertFalse(alertAppeared.get()); assertFalse(alertAppeared.get());
HtmlElementUtil.click(labelAnchor); HtmlElementUtil.click(labelAnchor);
assertFalse(alertAppeared.get()); assertFalse(alertAppeared.get());
String labelHref = labelAnchor.getHrefAttribute(); String labelHref = labelAnchor.getHrefAttribute();
assertThat(labelHref, not(containsString("javascript:alert(123)"))); assertThat(labelHref, not(containsString("javascript:alert(123)")));
String responseContent = projectConfigurePage.getWebResponse().getContentAsString(); String responseContent = projectConfigurePage.getWebResponse().getContentAsString();
assertThat(responseContent, not(containsString("javascript:alert(123)"))); assertThat(responseContent, not(containsString("javascript:alert(123)")));
});
} }
private void settingRootURL(String desiredRootUrl) throws Exception { private void settingRootURL(JenkinsRule j, String desiredRootUrl) throws Exception {
HtmlPage configurePage = j.createWebClient().goTo("configure"); HtmlPage configurePage = j.createWebClient().goTo("configure");
HtmlForm configForm = configurePage.getFormByName("config"); HtmlForm configForm = configurePage.getFormByName("config");
HtmlInput url = configForm.getInputByName("_.url"); HtmlInput url = configForm.getInputByName("_.url");
url.setValue(desiredRootUrl); url.setValue(desiredRootUrl);
HtmlFormUtil.submit(configForm); HtmlFormUtil.submit(configForm);
} }
private static final class CustomJenkinsSessionExtension extends JenkinsSessionExtension {
private int port;
private Description description;
@Override
public void beforeEach(ExtensionContext context) {
super.beforeEach(context);
description = Description.createTestDescription(
context.getTestClass().map(Class::getName).orElse(null),
context.getTestMethod().map(Method::getName).orElse(null),
context.getTestMethod().map(Method::getAnnotations).orElse(null));
}
@Override
public void then(Step s) throws Throwable {
CustomJenkinsRule r = new CustomJenkinsRule(getHome(), port);
r.apply(
new Statement() {
@Override
public void evaluate() throws Throwable {
port = r.getPort();
s.run(r);
}
},
description
).evaluate();
}
private static final class CustomJenkinsRule extends JenkinsRule {
CustomJenkinsRule(File home, int port) {
with(() -> home);
localPort = port;
}
int getPort() {
return localPort;
}
@Override
public URL getURL() throws IOException {
// first call for the "Running on xxx" log message, Jenkins not being set at that point
// and the second call is to set the rootUrl of the JLC inside the JenkinsRule#init
if (Jenkins.getInstanceOrNull() != null) {
// only useful for doNotAcceptNonHttpBasedRootURL_fromConfigXml
lastRootUrlReturned = JenkinsLocationConfiguration.getOrDie().getUrl();
lastRootUrlSet = true;
}
return super.getURL();
}
}
}
} }

View File

@ -13,23 +13,23 @@ import java.util.logging.LogRecord;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import jenkins.util.java.JavaUtils; import jenkins.util.java.JavaUtils;
import org.junit.Rule; import org.junit.jupiter.api.Test;
import org.junit.Test; import org.junit.jupiter.api.extension.RegisterExtension;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.MemoryAssert; import org.jvnet.hudson.test.MemoryAssert;
import org.jvnet.hudson.test.RealJenkinsRule; import org.jvnet.hudson.test.junit.jupiter.RealJenkinsExtension;
public class JenkinsLogRecordsTest { class JenkinsLogRecordsTest {
@Rule @RegisterExtension
public RealJenkinsRule rr = new RealJenkinsRule(); private final RealJenkinsExtension rr = new RealJenkinsExtension();
@Test @Test
public void logRecordsArePresentOnController() throws Throwable { void logRecordsArePresentOnController() throws Throwable {
rr.then(JenkinsLogRecordsTest::_logRecordsArePresentOnController); rr.then(JenkinsLogRecordsTest::_logRecordsArePresentOnController);
} }
private static void _logRecordsArePresentOnController(JenkinsRule r) throws Throwable { private static void _logRecordsArePresentOnController(JenkinsRule r) {
List<LogRecord> logRecords = Jenkins.logRecords; List<LogRecord> logRecords = Jenkins.logRecords;
assertThat(logRecords, not(empty())); assertThat(logRecords, not(empty()));
assertThat("Records are displayed in reverse order", assertThat("Records are displayed in reverse order",

View File

@ -8,8 +8,8 @@ import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.notNullValue;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import hudson.PluginWrapper; import hudson.PluginWrapper;
import hudson.cli.CLICommandInvoker; import hudson.cli.CLICommandInvoker;
@ -29,13 +29,14 @@ import org.hamcrest.Matcher;
import org.htmlunit.WebResponse; import org.htmlunit.WebResponse;
import org.htmlunit.html.HtmlForm; import org.htmlunit.html.HtmlForm;
import org.htmlunit.html.HtmlPage; import org.htmlunit.html.HtmlPage;
import org.junit.AfterClass; import org.junit.jupiter.api.AfterAll;
import org.junit.BeforeClass; import org.junit.jupiter.api.BeforeAll;
import org.junit.Rule; import org.junit.jupiter.api.BeforeEach;
import org.junit.Test; import org.junit.jupiter.api.Test;
import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.MockAuthorizationStrategy; import org.jvnet.hudson.test.MockAuthorizationStrategy;
import org.jvnet.hudson.test.junit.jupiter.WithJenkins;
import org.jvnet.hudson.test.recipes.WithPlugin; import org.jvnet.hudson.test.recipes.WithPlugin;
/** /**
@ -43,29 +44,32 @@ import org.jvnet.hudson.test.recipes.WithPlugin;
* with this property activated. * with this property activated.
*/ */
// TODO move tests to indicated test classes when we no longer need to set the system property // TODO move tests to indicated test classes when we no longer need to set the system property
public class JenkinsManagePermissionTest { @WithJenkins
class JenkinsManagePermissionTest {
@Rule private JenkinsRule j;
public JenkinsRule j = new JenkinsRule();
@BeforeClass @BeforeAll
public static void enableManagePermission() { static void enableManagePermission() {
System.setProperty("jenkins.security.ManagePermission", "true"); System.setProperty("jenkins.security.ManagePermission", "true");
} }
@AfterClass @BeforeEach
public static void disableManagePermission() { void setUp(JenkinsRule rule) {
System.clearProperty("jenkins.security.ManagePermission"); j = rule;
} }
@AfterAll
static void disableManagePermission() {
System.clearProperty("jenkins.security.ManagePermission");
}
// ----------------------------- // -----------------------------
// DisablePluginCommandTest // DisablePluginCommandTest
@Issue("JENKINS-60266") @Issue("JENKINS-60266")
@Test @Test
@WithPlugin({ "depender-0.0.2.hpi", "dependee-0.0.2.hpi"}) @WithPlugin({"depender-0.0.2.hpi", "dependee-0.0.2.hpi"})
public void managerCannotDisablePlugin() { void managerCannotDisablePlugin() {
//GIVEN a user with Jenkins.MANAGE permission //GIVEN a user with Jenkins.MANAGE permission
j.jenkins.setSecurityRealm(j.createDummySecurityRealm()); j.jenkins.setSecurityRealm(j.createDummySecurityRealm());
j.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy() j.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy()
@ -88,7 +92,6 @@ public class JenkinsManagePermissionTest {
return new CLICommandInvoker(j, new DisablePluginCommand()).asUser(user).invokeWithArgs(args); return new CLICommandInvoker(j, new DisablePluginCommand()).asUser(user).invokeWithArgs(args);
} }
private void assertPluginEnabled(String name) { private void assertPluginEnabled(String name) {
PluginWrapper plugin = j.getPluginManager().getPlugin(name); PluginWrapper plugin = j.getPluginManager().getPlugin(name);
assertThat(plugin, is(notNullValue())); assertThat(plugin, is(notNullValue()));
@ -102,7 +105,7 @@ public class JenkinsManagePermissionTest {
//ComputerTest //ComputerTest
@Issue("JENKINS-60266") @Issue("JENKINS-60266")
@Test @Test
public void dumpExportTableForbiddenWithoutAdminPermission() throws Exception { void dumpExportTableForbiddenWithoutAdminPermission() throws Exception {
final String READER = "reader"; final String READER = "reader";
final String MANAGER = "manager"; final String MANAGER = "manager";
j.jenkins.setSecurityRealm(j.createDummySecurityRealm()); j.jenkins.setSecurityRealm(j.createDummySecurityRealm());
@ -122,7 +125,7 @@ public class JenkinsManagePermissionTest {
// HudsonTest // HudsonTest
@Issue("JENKINS-60266") @Issue("JENKINS-60266")
@Test @Test
public void someGlobalConfigurationIsNotDisplayedWithManagePermission() throws Exception { void someGlobalConfigurationIsNotDisplayedWithManagePermission() throws Exception {
//GIVEN a user with Jenkins.MANAGE permission //GIVEN a user with Jenkins.MANAGE permission
j.jenkins.setSecurityRealm(j.createDummySecurityRealm()); j.jenkins.setSecurityRealm(j.createDummySecurityRealm());
j.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy() j.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy()
@ -146,7 +149,7 @@ public class JenkinsManagePermissionTest {
@Issue("JENKINS-60266") @Issue("JENKINS-60266")
@Test @Test
public void someGlobalConfigCanNotBeModifiedWithManagePermission() throws Exception { void someGlobalConfigCanNotBeModifiedWithManagePermission() throws Exception {
j.jenkins.addView(new MyView("testView", j.jenkins)); j.jenkins.addView(new MyView("testView", j.jenkins));
//GIVEN the Global Configuration Form, with some changes unsaved //GIVEN the Global Configuration Form, with some changes unsaved
@ -164,14 +167,14 @@ public class JenkinsManagePermissionTest {
.grant(Jenkins.MANAGE, Jenkins.READ).everywhere().toEveryone()); .grant(Jenkins.MANAGE, Jenkins.READ).everywhere().toEveryone());
j.submit(form); j.submit(form);
// THEN the changes on fields forbidden to a Jenkins.MANAGE permission are not saved // THEN the changes on fields forbidden to a Jenkins.MANAGE permission are not saved
assertEquals("shouldn't be allowed to change the number of executors", currentNumberExecutors, j.getInstance().getNumExecutors()); assertEquals(currentNumberExecutors, j.getInstance().getNumExecutors(), "shouldn't be allowed to change the number of executors");
assertEquals("shouldn't be allowed to change the shell executable", shell, getShell()); assertEquals(shell, getShell(), "shouldn't be allowed to change the shell executable");
assertEquals("shouldn't be allowed to change the primary view", view, j.getInstance().getPrimaryView()); assertEquals(view, j.getInstance().getPrimaryView(), "shouldn't be allowed to change the primary view");
} }
@Issue("JENKINS-60266") @Issue("JENKINS-60266")
@Test @Test
public void globalConfigAllowedWithManagePermission() throws Exception { void globalConfigAllowedWithManagePermission() throws Exception {
j.jenkins.setSecurityRealm(j.createDummySecurityRealm()); j.jenkins.setSecurityRealm(j.createDummySecurityRealm());
j.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy() j.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy()
.grant(Jenkins.MANAGE, Jenkins.READ).everywhere().toEveryone()); .grant(Jenkins.MANAGE, Jenkins.READ).everywhere().toEveryone());
@ -184,7 +187,7 @@ public class JenkinsManagePermissionTest {
@Issue("JENKINS-61457") @Issue("JENKINS-61457")
@Test @Test
public void managePermissionCanChangeUsageStatistics() throws Exception { void managePermissionCanChangeUsageStatistics() throws Exception {
j.jenkins.setSecurityRealm(j.createDummySecurityRealm()); j.jenkins.setSecurityRealm(j.createDummySecurityRealm());
j.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy() j.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy()
.grant(Jenkins.MANAGE, Jenkins.READ).everywhere().toEveryone()); .grant(Jenkins.MANAGE, Jenkins.READ).everywhere().toEveryone());
@ -233,8 +236,7 @@ public class JenkinsManagePermissionTest {
@Issue("JENKINS-63795") @Issue("JENKINS-63795")
@Test @Test
public void managePermissionShouldBeAllowedToRestart() throws IOException { void managePermissionShouldBeAllowedToRestart() throws IOException {
//GIVEN a Jenkins with 3 users : ADMINISTER, MANAGE and READ //GIVEN a Jenkins with 3 users : ADMINISTER, MANAGE and READ
HudsonPrivateSecurityRealm realm = new HudsonPrivateSecurityRealm(false, false, null); HudsonPrivateSecurityRealm realm = new HudsonPrivateSecurityRealm(false, false, null);
User adminUser = realm.createAccount("Administer", "G0d"); User adminUser = realm.createAccount("Administer", "G0d");

View File

@ -35,13 +35,13 @@ import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.isA; import static org.hamcrest.Matchers.isA;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.Assert.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.Assert.assertNull; import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.Assert.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.Assume.assumeFalse; import static org.junit.jupiter.api.Assumptions.assumeFalse;
import hudson.ExtensionList; import hudson.ExtensionList;
import hudson.Functions; import hudson.Functions;
@ -101,17 +101,17 @@ import org.htmlunit.WebRequest;
import org.htmlunit.WebResponse; import org.htmlunit.WebResponse;
import org.htmlunit.html.HtmlForm; import org.htmlunit.html.HtmlForm;
import org.htmlunit.html.HtmlPage; import org.htmlunit.html.HtmlPage;
import org.junit.Rule; import org.junit.jupiter.api.BeforeEach;
import org.junit.Test; import org.junit.jupiter.api.Tag;
import org.junit.experimental.categories.Category; import org.junit.jupiter.api.Test;
import org.junit.rules.TemporaryFolder; import org.junit.jupiter.api.io.TempDir;
import org.jvnet.hudson.reactor.ReactorException; import org.jvnet.hudson.reactor.ReactorException;
import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.JenkinsRule.WebClient; import org.jvnet.hudson.test.JenkinsRule.WebClient;
import org.jvnet.hudson.test.MockAuthorizationStrategy; import org.jvnet.hudson.test.MockAuthorizationStrategy;
import org.jvnet.hudson.test.SmokeTest;
import org.jvnet.hudson.test.TestExtension; import org.jvnet.hudson.test.TestExtension;
import org.jvnet.hudson.test.junit.jupiter.WithJenkins;
import org.jvnet.hudson.test.recipes.WithPlugin; import org.jvnet.hudson.test.recipes.WithPlugin;
import org.kohsuke.stapler.HttpResponse; import org.kohsuke.stapler.HttpResponse;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
@ -123,17 +123,23 @@ import org.mockito.Mockito;
* @see Jenkins * @see Jenkins
* @see JenkinsRule * @see JenkinsRule
*/ */
@Category(SmokeTest.class) @Tag("SmokeTest")
@WithJenkins
public class JenkinsTest { public class JenkinsTest {
@Rule public JenkinsRule j = new JenkinsRule(); @TempDir
private File tmp;
@Rule private JenkinsRule j;
public TemporaryFolder tmp = new TemporaryFolder();
@BeforeEach
void setUp(JenkinsRule rule) {
j = rule;
}
@Test @Test
@Issue("SECURITY-3498") @Issue("SECURITY-3498")
public void testPaneToggleCollapse() throws Exception { void testPaneToggleCollapse() {
try (WebClient wc = j.createWebClient()) { try (WebClient wc = j.createWebClient()) {
final FailingHttpStatusCodeException ex = assertThrows(FailingHttpStatusCodeException.class, () -> wc.goTo("toggleCollapse?paneId=foo")); final FailingHttpStatusCodeException ex = assertThrows(FailingHttpStatusCodeException.class, () -> wc.goTo("toggleCollapse?paneId=foo"));
// @POST responds 404 when the verb is wrong; @RequirePOST would respond 405. // @POST responds 404 when the verb is wrong; @RequirePOST would respond 405.
@ -143,12 +149,12 @@ public class JenkinsTest {
@Test @Test
@Issue("SECURITY-3073") @Issue("SECURITY-3073")
public void verifyUploadedFingerprintFilePermission() throws Exception { void verifyUploadedFingerprintFilePermission() throws Exception {
assumeFalse(Functions.isWindows()); assumeFalse(Functions.isWindows());
HtmlPage page = j.createWebClient().goTo("fingerprintCheck"); HtmlPage page = j.createWebClient().goTo("fingerprintCheck");
HtmlForm form = page.getForms().get(0); HtmlForm form = page.getForms().get(0);
File dir = tmp.newFolder(); File dir = newFolder(tmp, "junit");
File plugin = new File(dir, "htmlpublisher.jpi"); File plugin = new File(dir, "htmlpublisher.jpi");
// We're using a plugin to have a file above DiskFileItemFactory.DEFAULT_SIZE_THRESHOLD // We're using a plugin to have a file above DiskFileItemFactory.DEFAULT_SIZE_THRESHOLD
FileUtils.copyURLToFile(Objects.requireNonNull(getClass().getClassLoader().getResource("plugins/htmlpublisher.jpi")), plugin); FileUtils.copyURLToFile(Objects.requireNonNull(getClass().getClassLoader().getResource("plugins/htmlpublisher.jpi")), plugin);
@ -179,12 +185,12 @@ public class JenkinsTest {
@Issue("SECURITY-406") @Issue("SECURITY-406")
@Test @Test
public void testUserCreationFromUrlForAdmins() throws Exception { void testUserCreationFromUrlForAdmins() throws Exception {
WebClient wc = j.createWebClient(); WebClient wc = j.createWebClient();
assertNull("User not supposed to exist", User.getById("nonexistent", false)); assertNull(User.getById("nonexistent", false), "User not supposed to exist");
wc.assertFails("user/nonexistent", 404); wc.assertFails("user/nonexistent", 404);
assertNull("User not supposed to exist", User.getById("nonexistent", false)); assertNull(User.getById("nonexistent", false), "User not supposed to exist");
try { try {
User.ALLOW_USER_CREATION_VIA_URL = true; User.ALLOW_USER_CREATION_VIA_URL = true;
@ -192,7 +198,7 @@ public class JenkinsTest {
// expected to work // expected to work
wc.goTo("user/nonexistent2"); wc.goTo("user/nonexistent2");
assertNotNull("User supposed to exist", User.getById("nonexistent2", false)); assertNotNull(User.getById("nonexistent2", false), "User supposed to exist");
} finally { } finally {
User.ALLOW_USER_CREATION_VIA_URL = false; User.ALLOW_USER_CREATION_VIA_URL = false;
@ -200,7 +206,7 @@ public class JenkinsTest {
} }
@Test @Test
public void testIsDisplayNameUniqueTrue() throws Exception { void testIsDisplayNameUniqueTrue() throws Exception {
final String curJobName = "curJobName"; final String curJobName = "curJobName";
final String jobName = "jobName"; final String jobName = "jobName";
FreeStyleProject curProject = j.createFreeStyleProject(curJobName); FreeStyleProject curProject = j.createFreeStyleProject(curJobName);
@ -215,7 +221,7 @@ public class JenkinsTest {
} }
@Test @Test
public void testIsDisplayNameUniqueFalse() throws Exception { void testIsDisplayNameUniqueFalse() throws Exception {
final String curJobName = "curJobName"; final String curJobName = "curJobName";
final String jobName = "jobName"; final String jobName = "jobName";
final String displayName = "displayName"; final String displayName = "displayName";
@ -231,7 +237,7 @@ public class JenkinsTest {
} }
@Test @Test
public void testIsDisplayNameUniqueSameAsCurrentJob() throws Exception { void testIsDisplayNameUniqueSameAsCurrentJob() throws Exception {
final String curJobName = "curJobName"; final String curJobName = "curJobName";
final String displayName = "currentProjectDisplayName"; final String displayName = "currentProjectDisplayName";
@ -244,7 +250,7 @@ public class JenkinsTest {
} }
@Test @Test
public void testIsNameUniqueTrue() throws Exception { void testIsNameUniqueTrue() throws Exception {
final String curJobName = "curJobName"; final String curJobName = "curJobName";
final String jobName = "jobName"; final String jobName = "jobName";
j.createFreeStyleProject(curJobName); j.createFreeStyleProject(curJobName);
@ -255,7 +261,7 @@ public class JenkinsTest {
} }
@Test @Test
public void testIsNameUniqueFalse() throws Exception { void testIsNameUniqueFalse() throws Exception {
final String curJobName = "curJobName"; final String curJobName = "curJobName";
final String jobName = "jobName"; final String jobName = "jobName";
j.createFreeStyleProject(curJobName); j.createFreeStyleProject(curJobName);
@ -266,7 +272,7 @@ public class JenkinsTest {
} }
@Test @Test
public void testIsNameUniqueSameAsCurrentJob() throws Exception { void testIsNameUniqueSameAsCurrentJob() throws Exception {
final String curJobName = "curJobName"; final String curJobName = "curJobName";
final String jobName = "jobName"; final String jobName = "jobName";
j.createFreeStyleProject(curJobName); j.createFreeStyleProject(curJobName);
@ -278,7 +284,7 @@ public class JenkinsTest {
} }
@Test @Test
public void testDoCheckDisplayNameUnique() throws Exception { void testDoCheckDisplayNameUnique() throws Exception {
final String curJobName = "curJobName"; final String curJobName = "curJobName";
final String jobName = "jobName"; final String jobName = "jobName";
FreeStyleProject curProject = j.createFreeStyleProject(curJobName); FreeStyleProject curProject = j.createFreeStyleProject(curJobName);
@ -293,7 +299,7 @@ public class JenkinsTest {
} }
@Test @Test
public void testDoCheckDisplayNameSameAsDisplayName() throws Exception { void testDoCheckDisplayNameSameAsDisplayName() throws Exception {
final String curJobName = "curJobName"; final String curJobName = "curJobName";
final String jobName = "jobName"; final String jobName = "jobName";
final String displayName = "displayName"; final String displayName = "displayName";
@ -309,7 +315,7 @@ public class JenkinsTest {
} }
@Test @Test
public void testDoCheckDisplayNameSameAsJobName() throws Exception { void testDoCheckDisplayNameSameAsJobName() throws Exception {
final String curJobName = "curJobName"; final String curJobName = "curJobName";
final String jobName = "jobName"; final String jobName = "jobName";
final String displayName = "displayName"; final String displayName = "displayName";
@ -325,7 +331,7 @@ public class JenkinsTest {
} }
@Test @Test
public void testDoCheckViewName_GoodName() throws Exception { void testDoCheckViewName_GoodName() {
String[] viewNames = new String[] { String[] viewNames = new String[] {
"", "",
"Jenkins", "Jenkins",
@ -339,7 +345,7 @@ public class JenkinsTest {
} }
@Test @Test
public void testDoCheckViewName_NotGoodName() throws Exception { void testDoCheckViewName_NotGoodName() {
String[] viewNames = new String[] { String[] viewNames = new String[] {
"Jenkins?", "Jenkins?",
"Jenkins*", "Jenkins*",
@ -365,8 +371,9 @@ public class JenkinsTest {
/** /**
* Makes sure access to "/foobar" for UnprotectedRootAction gets through. * Makes sure access to "/foobar" for UnprotectedRootAction gets through.
*/ */
@Test @Issue("JENKINS-14113") @Test
public void testUnprotectedRootAction() throws Exception { @Issue("JENKINS-14113")
void testUnprotectedRootAction() throws Exception {
j.jenkins.setSecurityRealm(j.createDummySecurityRealm()); j.jenkins.setSecurityRealm(j.createDummySecurityRealm());
j.jenkins.setAuthorizationStrategy(new FullControlOnceLoggedInAuthorizationStrategy()); j.jenkins.setAuthorizationStrategy(new FullControlOnceLoggedInAuthorizationStrategy());
WebClient wc = j.createWebClient(); WebClient wc = j.createWebClient();
@ -381,7 +388,7 @@ public class JenkinsTest {
} }
@Test @Test
public void testDoScript() throws Exception { void testDoScript() throws Exception {
j.jenkins.setSecurityRealm(j.createDummySecurityRealm()); j.jenkins.setSecurityRealm(j.createDummySecurityRealm());
j.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy(). j.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy().
grant(Jenkins.ADMINISTER).everywhere().to("alice"). grant(Jenkins.ADMINISTER).everywhere().to("alice").
@ -411,7 +418,7 @@ public class JenkinsTest {
@Test @Test
@Issue("JENKINS-58548") @Issue("JENKINS-58548")
public void testDoScriptTextDoesNotOutputExtraWhitespace() throws Exception { void testDoScriptTextDoesNotOutputExtraWhitespace() throws Exception {
j.jenkins.setSecurityRealm(j.createDummySecurityRealm()); j.jenkins.setSecurityRealm(j.createDummySecurityRealm());
WebClient wc = j.createWebClient().login("admin"); WebClient wc = j.createWebClient().login("admin");
TextPage page = wc.getPage(new WebRequest(wc.createCrumbedUrl("scriptText?script=print 'hello'"), HttpMethod.POST)); TextPage page = wc.getPage(new WebRequest(wc.createCrumbedUrl("scriptText?script=print 'hello'"), HttpMethod.POST));
@ -419,7 +426,7 @@ public class JenkinsTest {
} }
@Test @Test
public void testDoEval() throws Exception { void testDoEval() throws Exception {
j.jenkins.setSecurityRealm(j.createDummySecurityRealm()); j.jenkins.setSecurityRealm(j.createDummySecurityRealm());
j.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy(). j.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy().
grant(Jenkins.ADMINISTER).everywhere().to("alice"). grant(Jenkins.ADMINISTER).everywhere().to("alice").
@ -435,15 +442,15 @@ public class JenkinsTest {
wc.withBasicApiToken(User.getById("bob", true)); wc.withBasicApiToken(User.getById("bob", true));
Page page = eval(wc); Page page = eval(wc);
assertEquals("bob has only READ", assertEquals(HttpURLConnection.HTTP_FORBIDDEN,
HttpURLConnection.HTTP_FORBIDDEN, page.getWebResponse().getStatusCode(),
page.getWebResponse().getStatusCode()); "bob has only READ");
wc.withBasicApiToken(User.getById("charlie", true)); wc.withBasicApiToken(User.getById("charlie", true));
page = eval(wc); page = eval(wc);
assertEquals("charlie has ADMINISTER and READ", assertEquals(HttpURLConnection.HTTP_OK,
HttpURLConnection.HTTP_OK, page.getWebResponse().getStatusCode(),
page.getWebResponse().getStatusCode()); "charlie has ADMINISTER and READ");
} }
private Page eval(WebClient wc) throws Exception { private Page eval(WebClient wc) throws Exception {
@ -491,8 +498,9 @@ public class JenkinsTest {
} }
} }
@Test @Issue("JENKINS-20866") @Test
public void testErrorPageShouldBeAnonymousAccessible() throws Exception { @Issue("JENKINS-20866")
void testErrorPageShouldBeAnonymousAccessible() throws Exception {
HudsonPrivateSecurityRealm s = new HudsonPrivateSecurityRealm(false, false, null); HudsonPrivateSecurityRealm s = new HudsonPrivateSecurityRealm(false, false, null);
User alice = s.createAccount("alice", "alice"); User alice = s.createAccount("alice", "alice");
j.jenkins.setSecurityRealm(s); j.jenkins.setSecurityRealm(s);
@ -507,7 +515,7 @@ public class JenkinsTest {
.withThrowExceptionOnFailingStatusCode(false); .withThrowExceptionOnFailingStatusCode(false);
HtmlPage p = wc.goTo("error/reportError"); HtmlPage p = wc.goTo("error/reportError");
assertEquals(p.asNormalizedText(), HttpURLConnection.HTTP_BAD_REQUEST, p.getWebResponse().getStatusCode()); // not 403 forbidden assertEquals(HttpURLConnection.HTTP_BAD_REQUEST, p.getWebResponse().getStatusCode(), p.asNormalizedText()); // not 403 forbidden
assertTrue(p.getWebResponse().getContentAsString().contains("My car is black")); assertTrue(p.getWebResponse().getContentAsString().contains("My car is black"));
} }
@ -534,8 +542,9 @@ public class JenkinsTest {
} }
} }
@Test @Issue("JENKINS-23551") @Test
public void testComputerListenerNotifiedOnRestart() { @Issue("JENKINS-23551")
void testComputerListenerNotifiedOnRestart() {
// Simulate restart calling listeners // Simulate restart calling listeners
for (RestartListener listener : RestartListener.all()) for (RestartListener listener : RestartListener.all())
listener.onRestart(); listener.onRestart();
@ -549,7 +558,7 @@ public class JenkinsTest {
public static final ComputerListener listenerMock = Mockito.mock(ComputerListener.class); public static final ComputerListener listenerMock = Mockito.mock(ComputerListener.class);
@Test @Test
public void runScriptOnOfflineComputer() throws Exception { void runScriptOnOfflineComputer() throws Exception {
DumbSlave slave = j.createSlave(true); DumbSlave slave = j.createSlave(true);
j.disconnectSlave(slave); j.disconnectSlave(slave);
@ -568,7 +577,7 @@ public class JenkinsTest {
@Test @Test
@Issue("JENKINS-38487") @Issue("JENKINS-38487")
public void startupShouldNotFailOnIOExceptionOnlineListener() { void startupShouldNotFailOnIOExceptionOnlineListener() {
// We do nothing, IOExceptionOnOnlineListener & JenkinsRule should cause the // We do nothing, IOExceptionOnOnlineListener & JenkinsRule should cause the
// boot failure if the issue is not fixed. // boot failure if the issue is not fixed.
@ -589,7 +598,7 @@ public class JenkinsTest {
@Test @Test
@Issue("JENKINS-57111") @Issue("JENKINS-57111")
public void startupShouldNotFailOnRuntimeExceptionOnlineListener() { void startupShouldNotFailOnRuntimeExceptionOnlineListener() {
// We do nothing, RuntimeExceptionOnOnlineListener & JenkinsRule should cause the // We do nothing, RuntimeExceptionOnOnlineListener & JenkinsRule should cause the
// boot failure if the issue is not fixed. // boot failure if the issue is not fixed.
assertEquals(1, RuntimeExceptionOnOnlineListener.onOnlineCount); assertEquals(1, RuntimeExceptionOnOnlineListener.onOnlineCount);
@ -608,7 +617,7 @@ public class JenkinsTest {
} }
@Test @Test
public void getComputers() throws Exception { void getComputers() throws Exception {
List<Slave> agents = new ArrayList<>(); List<Slave> agents = new ArrayList<>();
for (String n : List.of("zestful", "bilking", "grouchiest")) { for (String n : List.of("zestful", "bilking", "grouchiest")) {
agents.add(j.createSlave(n, null, null)); agents.add(j.createSlave(n, null, null));
@ -622,7 +631,7 @@ public class JenkinsTest {
@Issue("JENKINS-42577") @Issue("JENKINS-42577")
@Test @Test
public void versionIsSavedInSave() throws Exception { void versionIsSavedInSave() throws Exception {
Jenkins.VERSION = "1.0"; Jenkins.VERSION = "1.0";
j.jenkins.save(); j.jenkins.save();
VersionNumber storedVersion = Jenkins.getStoredVersion(); VersionNumber storedVersion = Jenkins.getStoredVersion();
@ -635,27 +644,28 @@ public class JenkinsTest {
assertNull(nullVersion); assertNull(nullVersion);
} }
// Sources: https://github.com/Vlatombe/jenkins-47406
@Issue("JENKINS-47406") @Issue("JENKINS-47406")
@Test @Test
@WithPlugin("jenkins-47406.hpi") // Sources: https://github.com/Vlatombe/jenkins-47406 @WithPlugin("jenkins-47406.hpi")
public void jobCreatedByInitializerIsRetained() { void jobCreatedByInitializerIsRetained() {
assertNotNull("JENKINS-47406 should exist", j.jenkins.getItem("JENKINS-47406")); assertNotNull(j.jenkins.getItem("JENKINS-47406"), "JENKINS-47406 should exist");
} }
@Issue("SECURITY-2047") @Issue("SECURITY-2047")
@Test @Test
public void testLogin123() throws Exception { void testLogin123() {
j.jenkins.setSecurityRealm(j.createDummySecurityRealm()); j.jenkins.setSecurityRealm(j.createDummySecurityRealm());
j.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy()); j.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy());
WebClient wc = j.createWebClient(); WebClient wc = j.createWebClient();
FailingHttpStatusCodeException e = assertThrows("Page should be protected.", FailingHttpStatusCodeException.class, () -> wc.goTo("login123")); FailingHttpStatusCodeException e = assertThrows(FailingHttpStatusCodeException.class, () -> wc.goTo("login123"), "Page should be protected.");
assertThat(e.getStatusCode(), is(403)); assertThat(e.getStatusCode(), is(403));
} }
@Issue("SECURITY-2047") @Issue("SECURITY-2047")
@Test @Test
public void testLogin123WithRead() throws Exception { void testLogin123WithRead() throws Exception {
j.jenkins.setSecurityRealm(j.createDummySecurityRealm()); j.jenkins.setSecurityRealm(j.createDummySecurityRealm());
j.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy(). j.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy().
grant(Jenkins.READ).everywhere().to("bob")); grant(Jenkins.READ).everywhere().to("bob"));
@ -668,7 +678,7 @@ public class JenkinsTest {
} }
@Test @Test
public void testLogin() throws Exception { void testLogin() throws Exception {
j.jenkins.setSecurityRealm(j.createDummySecurityRealm()); j.jenkins.setSecurityRealm(j.createDummySecurityRealm());
j.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy(). j.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy().
grant(Jenkins.READ).everywhere().to("bob")); grant(Jenkins.READ).everywhere().to("bob"));
@ -681,7 +691,7 @@ public class JenkinsTest {
@Issue("JENKINS-68055") @Issue("JENKINS-68055")
@Test @Test
public void testTrimLabelsRetainsLabelExpressions() throws Exception { void testTrimLabelsRetainsLabelExpressions() throws Exception {
Node n = j.createOnlineSlave(); Node n = j.createOnlineSlave();
n.setLabelString("test expression"); n.setLabelString("test expression");
@ -695,11 +705,11 @@ public class JenkinsTest {
} }
@Test @Test
public void reloadShouldNotSaveConfig() throws Exception { void reloadShouldNotSaveConfig() throws Exception {
SaveableListenerImpl saveListener = ExtensionList.lookupSingleton(SaveableListenerImpl.class); SaveableListenerImpl saveListener = ExtensionList.lookupSingleton(SaveableListenerImpl.class);
saveListener.reset(); saveListener.reset();
j.jenkins.reload(); j.jenkins.reload();
assertFalse("Jenkins object should not have been saved.", saveListener.wasCalled()); assertFalse(saveListener.wasCalled(), "Jenkins object should not have been saved.");
} }
@TestExtension("reloadShouldNotSaveConfig") @TestExtension("reloadShouldNotSaveConfig")
@ -741,7 +751,7 @@ public class JenkinsTest {
} }
@Test @Test
public void checkInitialView() { void checkInitialView() {
assertTrue(CheckInitialViewExtension.hasPrimaryView); assertTrue(CheckInitialViewExtension.hasPrimaryView);
} }
@ -772,7 +782,7 @@ public class JenkinsTest {
} }
@Test @Test
public void reloadViews() throws Exception { void reloadViews() throws Exception {
assertThat(j.jenkins.getPrimaryView(), isA(AllView.class)); assertThat(j.jenkins.getPrimaryView(), isA(AllView.class));
assertThat(j.jenkins.getViews(), contains(isA(AllView.class))); assertThat(j.jenkins.getViews(), contains(isA(AllView.class)));
Files.writeString(j.jenkins.getConfigFile().getFile().toPath(), "<broken"); Files.writeString(j.jenkins.getConfigFile().getFile().toPath(), "<broken");
@ -782,4 +792,13 @@ public class JenkinsTest {
assertThat(j.jenkins.getViews(), contains(isA(AllView.class))); assertThat(j.jenkins.getViews(), contains(isA(AllView.class)));
} }
private static File newFolder(File root, String... subDirs) throws IOException {
String subFolder = String.join("/", subDirs);
File result = new File(root, subFolder);
if (!result.mkdirs()) {
throw new IOException("Couldn't create folders " + root);
}
return result;
}
} }

View File

@ -2,27 +2,31 @@ package jenkins.model;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.hasSize;
import static org.junit.Assert.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.NonNull;
import hudson.model.Descriptor; import hudson.model.Descriptor;
import hudson.model.Slave; import hudson.model.Slave;
import hudson.slaves.ComputerLauncher; import hudson.slaves.ComputerLauncher;
import java.io.IOException; import java.io.IOException;
import org.junit.Rule; import java.io.Serial;
import org.junit.Test; import org.junit.jupiter.api.Test;
import org.jvnet.hudson.test.JenkinsSessionRule; import org.junit.jupiter.api.extension.RegisterExtension;
import org.jvnet.hudson.test.junit.jupiter.JenkinsSessionExtension;
public class NodesRestartTest { class NodesRestartTest {
@Rule
public JenkinsSessionRule s = new JenkinsSessionRule(); @RegisterExtension
private final JenkinsSessionExtension s = new JenkinsSessionExtension();
// The point of this implementation is to override readResolve so that Slave#readResolve doesn't get called. // The point of this implementation is to override readResolve so that Slave#readResolve doesn't get called.
public static class DummyAgent extends Slave { public static class DummyAgent extends Slave {
@SuppressWarnings(value = "checkstyle:redundantmodifier")
public DummyAgent(@NonNull String name, String remoteFS, ComputerLauncher launcher) throws Descriptor.FormException, IOException { public DummyAgent(@NonNull String name, String remoteFS, ComputerLauncher launcher) throws Descriptor.FormException, IOException {
super(name, remoteFS, launcher); super(name, remoteFS, launcher);
} }
@Serial
@Override @Override
protected Object readResolve() { protected Object readResolve() {
return this; return this;
@ -30,7 +34,7 @@ public class NodesRestartTest {
} }
@Test @Test
public void checkNodeRestart() throws Throwable { void checkNodeRestart() throws Throwable {
s.then(r -> { s.then(r -> {
assertThat(r.jenkins.getNodes(), hasSize(0)); assertThat(r.jenkins.getNodes(), hasSize(0));
var node = new DummyAgent("my-node", "temp", r.createComputerLauncher(null)); var node = new DummyAgent("my-node", "temp", r.createComputerLauncher(null));

View File

@ -28,8 +28,8 @@ import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.hamcrest.xml.HasXPath.hasXPath; import static org.hamcrest.xml.HasXPath.hasXPath;
import static org.junit.Assert.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.Assert.assertNull; import static org.junit.jupiter.api.Assertions.assertNull;
import hudson.ExtensionComponent; import hudson.ExtensionComponent;
import hudson.model.User; import hudson.model.User;
@ -45,21 +45,22 @@ import org.htmlunit.WebRequest;
import org.htmlunit.html.HtmlPage; import org.htmlunit.html.HtmlPage;
import org.htmlunit.html.HtmlTextInput; import org.htmlunit.html.HtmlTextInput;
import org.htmlunit.xml.XmlPage; import org.htmlunit.xml.XmlPage;
import org.junit.Rule; import org.junit.jupiter.api.Test;
import org.junit.Test; import org.junit.jupiter.api.extension.RegisterExtension;
import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.JenkinsSessionRule;
import org.jvnet.hudson.test.MockAuthorizationStrategy; import org.jvnet.hudson.test.MockAuthorizationStrategy;
import org.jvnet.hudson.test.TestExtension; import org.jvnet.hudson.test.TestExtension;
import org.jvnet.hudson.test.junit.jupiter.JenkinsSessionExtension;
public class BasicHeaderApiTokenAuthenticatorTest { class BasicHeaderApiTokenAuthenticatorTest {
@Rule
public JenkinsSessionRule sessions = new JenkinsSessionRule(); @RegisterExtension
private final JenkinsSessionExtension sessions = new JenkinsSessionExtension();
@Test @Test
@Issue("SECURITY-896") @Issue("SECURITY-896")
public void legacyToken_regularCase() throws Throwable { void legacyToken_regularCase() throws Throwable {
AtomicReference<String> token = new AtomicReference<>(); AtomicReference<String> token = new AtomicReference<>();
sessions.then(j -> { sessions.then(j -> {
enableLegacyTokenGenerationOnUserCreation(); enableLegacyTokenGenerationOnUserCreation();
@ -109,7 +110,7 @@ public class BasicHeaderApiTokenAuthenticatorTest {
*/ */
@Test @Test
@Issue("SECURITY-896") @Issue("SECURITY-896")
public void legacyToken_withoutLastGrantedAuthorities() throws Throwable { void legacyToken_withoutLastGrantedAuthorities() throws Throwable {
AtomicReference<String> token = new AtomicReference<>(); AtomicReference<String> token = new AtomicReference<>();
sessions.then(j -> { sessions.then(j -> {
enableLegacyTokenGenerationOnUserCreation(); enableLegacyTokenGenerationOnUserCreation();

View File

@ -24,10 +24,13 @@
package jenkins.security; package jenkins.security;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertAll;
import hudson.remoting.ClassFilter; import hudson.remoting.ClassFilter;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.util.logging.Level; import java.util.logging.Level;
import javax.script.ScriptEngineManager; import javax.script.ScriptEngineManager;
import javax.script.ScriptException; import javax.script.ScriptException;
@ -36,61 +39,75 @@ import jenkins.util.BuildListenerAdapter;
import jenkins.util.TreeString; import jenkins.util.TreeString;
import jenkins.util.TreeStringBuilder; import jenkins.util.TreeStringBuilder;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.junit.Rule; import org.junit.jupiter.api.BeforeEach;
import org.junit.Test; import org.junit.jupiter.api.Tag;
import org.junit.experimental.categories.Category; import org.junit.jupiter.api.Test;
import org.junit.rules.ErrorCollector; import org.junit.jupiter.api.io.CleanupMode;
import org.junit.rules.TemporaryFolder; import org.junit.jupiter.api.io.TempDir;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.LoggerRule; import org.jvnet.hudson.test.LogRecorder;
import org.jvnet.hudson.test.SmokeTest; import org.jvnet.hudson.test.junit.jupiter.WithJenkins;
import org.jvnet.hudson.test.recipes.WithPlugin; import org.jvnet.hudson.test.recipes.WithPlugin;
@Category(SmokeTest.class) @Tag("SmokeTest")
public class CustomClassFilterTest { @WithJenkins
class CustomClassFilterTest {
static { static {
System.setProperty("hudson.remoting.ClassFilter", "javax.script.SimpleBindings,!jenkins.util.TreeString"); System.setProperty("hudson.remoting.ClassFilter", "javax.script.SimpleBindings,!jenkins.util.TreeString");
} }
@Rule private final LogRecorder logging = new LogRecorder().record("jenkins.security", Level.FINER);
public JenkinsRule r = new JenkinsRule();
@Rule @TempDir(cleanup = CleanupMode.NEVER)
public ErrorCollector errors = new ErrorCollector(); private File tmp;
@Rule private JenkinsRule r;
public LoggerRule logging = new LoggerRule().record("jenkins.security", Level.FINER);
@BeforeEach
void setUp(JenkinsRule rule) {
r = rule;
}
@Rule
public TemporaryFolder tmp = new TemporaryFolder();
@WithPlugin("custom-class-filter.jpi") @WithPlugin("custom-class-filter.jpi")
@Test @Test
public void smokes() throws Exception { void smokes() {
assertBlacklisted("enabled via system property", SimpleBindings.class, false); assertAll(
assertBlacklisted("enabled via plugin", ScriptException.class, false); () -> assertBlacklisted("enabled via system property", SimpleBindings.class, false),
assertBlacklisted("disabled by ClassFilter.STANDARD", ScriptEngineManager.class, true); () -> assertBlacklisted("enabled via plugin", ScriptException.class, false),
assertBlacklisted("part of Jenkins core, so why not?", BuildListenerAdapter.class, false); () -> assertBlacklisted("disabled by ClassFilter.STANDARD", ScriptEngineManager.class, true),
// As an aside, the following appear totally unused anyway! () -> assertBlacklisted("part of Jenkins core, so why not?", BuildListenerAdapter.class, false),
assertBlacklisted("disabled via system property", TreeString.class, true); // As an aside, the following appear totally unused anyway!
assertBlacklisted("disabled via plugin", TreeStringBuilder.class, true); () -> assertBlacklisted("disabled via system property", TreeString.class, true),
() -> assertBlacklisted("disabled via plugin", TreeStringBuilder.class, true)
);
} }
@Test @Test
public void dynamicLoad() throws Exception { void dynamicLoad() {
assertBlacklisted("not yet enabled via plugin", ScriptException.class, true); assertAll(
assertBlacklisted("not yet disabled via plugin", TreeStringBuilder.class, false); () -> assertBlacklisted("not yet enabled via plugin", ScriptException.class, true),
File jpi = tmp.newFile("custom-class-filter.jpi"); () -> assertBlacklisted("not yet disabled via plugin", TreeStringBuilder.class, false),
FileUtils.copyURLToFile(CustomClassFilterTest.class.getResource("/plugins/custom-class-filter.jpi"), jpi); () -> {
r.jenkins.pluginManager.dynamicLoad(jpi); File jpi = newFile(tmp, "custom-class-filter.jpi");
assertBlacklisted("enabled via plugin", ScriptException.class, false); FileUtils.copyURLToFile(CustomClassFilterTest.class.getResource("/plugins/custom-class-filter.jpi"), jpi);
assertBlacklisted("disabled via plugin", TreeStringBuilder.class, true); r.jenkins.pluginManager.dynamicLoad(jpi);
},
() -> assertBlacklisted("enabled via plugin", ScriptException.class, false),
() -> assertBlacklisted("disabled via plugin", TreeStringBuilder.class, true)
);
} }
private void assertBlacklisted(String message, Class<?> c, boolean blacklisted) { private void assertBlacklisted(String message, Class<?> c, boolean blacklisted) {
String name = c.getName(); String name = c.getName();
errors.checkThat(name + ": " + message, ClassFilter.DEFAULT.isBlacklisted(c) || ClassFilter.DEFAULT.isBlacklisted(name), is(blacklisted)); assertThat(name + ": " + message, ClassFilter.DEFAULT.isBlacklisted(c) || ClassFilter.DEFAULT.isBlacklisted(name), is(blacklisted));
}
private static File newFile(File parent, String child) throws IOException {
File result = new File(parent, child);
result.createNewFile();
return result;
} }
} }

View File

@ -7,16 +7,22 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import jenkins.model.Jenkins; import jenkins.model.Jenkins;
import org.junit.Rule; import org.junit.jupiter.api.AfterEach;
import org.junit.Test; import org.junit.jupiter.api.BeforeEach;
import org.junit.runner.RunWith; import org.junit.jupiter.api.Test;
import org.junit.runners.Parameterized; import org.junit.jupiter.api.extension.RegisterExtension;
import org.jvnet.hudson.test.FlagRule; import org.junit.jupiter.params.Parameter;
import org.junit.jupiter.params.ParameterizedClass;
import org.junit.jupiter.params.provider.MethodSource;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.MockAuthorizationStrategy; import org.jvnet.hudson.test.MockAuthorizationStrategy;
import org.jvnet.hudson.test.junit.jupiter.JenkinsSessionExtension;
import org.jvnet.hudson.test.junit.jupiter.WithJenkins;
@RunWith(Parameterized.class) @WithJenkins
public class JettySameSiteCookieSetupTest { @ParameterizedClass
@MethodSource("sameSite")
class JettySameSiteCookieSetupTest {
private static final Map<String, String> FLAG_TO_SAMESITE_COOKIE = new HashMap<>() {{ private static final Map<String, String> FLAG_TO_SAMESITE_COOKIE = new HashMap<>() {{
put("", null); put("", null);
@ -25,35 +31,49 @@ public class JettySameSiteCookieSetupTest {
put(null, "lax"); put(null, "lax");
}}; }};
@Rule @RegisterExtension
public JenkinsRule j = new JenkinsRule(); private final JenkinsSessionExtension session = new JenkinsSessionExtension();
@Rule private String sameSiteCookie;
public FlagRule<String> sameSiteCookie;
private final String sameSiteValue; @Parameter
private String sameSiteValue;
public JettySameSiteCookieSetupTest(String sameSiteValue) { static Set<String> sameSite() {
this.sameSiteValue = sameSiteValue;
sameSiteCookie = FlagRule.systemProperty(JettySameSiteCookieSetup.class.getName() + ".sameSiteDefault", sameSiteValue);
}
@Parameterized.Parameters
public static Set<String> sameSite() {
return FLAG_TO_SAMESITE_COOKIE.keySet(); return FLAG_TO_SAMESITE_COOKIE.keySet();
} }
@Test @BeforeEach
public void testJettyFlagSetsSameSiteCookieProperty() throws Exception { void setUp() {
String expected = FLAG_TO_SAMESITE_COOKIE.get(this.sameSiteValue); if (sameSiteValue != null) {
j.jenkins.setSecurityRealm(j.createDummySecurityRealm()); sameSiteCookie = System.setProperty(JettySameSiteCookieSetup.class.getName() + ".sameSiteDefault", sameSiteValue);
j.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy().grant(Jenkins.ADMINISTER).everywhere().to("admin")); } else {
sameSiteCookie = System.clearProperty(JettySameSiteCookieSetup.class.getName() + ".sameSiteDefault");
try (JenkinsRule.WebClient wc = j.createWebClient()) {
wc.login("admin", "admin", true);
assertThat(wc.getCookieManager().getCookie("JSESSIONID").getSameSite(), is(expected));
assertThat(wc.getCookieManager().getCookie("remember-me").getSameSite(), is(expected));
} }
} }
@AfterEach
void tearDown() {
if (sameSiteCookie != null) {
System.setProperty(JettySameSiteCookieSetup.class.getName() + ".sameSiteDefault", sameSiteCookie);
} else {
System.clearProperty(JettySameSiteCookieSetup.class.getName() + ".sameSiteDefault");
}
}
@Test
void testJettyFlagSetsSameSiteCookieProperty() throws Throwable {
String expected = FLAG_TO_SAMESITE_COOKIE.get(sameSiteValue);
session.then(j -> {
j.jenkins.setSecurityRealm(j.createDummySecurityRealm());
j.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy().grant(Jenkins.ADMINISTER).everywhere().to("admin"));
try (JenkinsRule.WebClient wc = j.createWebClient()) {
wc.login("admin", "admin", true);
assertThat(wc.getCookieManager().getCookie("JSESSIONID").getSameSite(), is(expected));
assertThat(wc.getCookieManager().getCookie("remember-me").getSameSite(), is(expected));
}
});
}
} }

View File

@ -2,33 +2,39 @@ package jenkins.security;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import hudson.slaves.DumbSlave; import hudson.slaves.DumbSlave;
import java.io.IOException; import java.io.IOException;
import java.io.Serializable;
import java.util.logging.Level; import java.util.logging.Level;
import org.codehaus.groovy.runtime.MethodClosure; import org.codehaus.groovy.runtime.MethodClosure;
import org.junit.Rule; import org.junit.jupiter.api.BeforeEach;
import org.junit.Test; import org.junit.jupiter.api.Test;
import org.jvnet.hudson.test.InboundAgentRule; import org.junit.jupiter.api.extension.RegisterExtension;
import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.LoggerRule; import org.jvnet.hudson.test.LogRecorder;
import org.jvnet.hudson.test.junit.jupiter.InboundAgentExtension;
import org.jvnet.hudson.test.junit.jupiter.WithJenkins;
/** /**
* @author Kohsuke Kawaguchi * @author Kohsuke Kawaguchi
*/ */
@Issue("SECURITY-218") @Issue("SECURITY-218")
public class Security218Test implements Serializable { @WithJenkins
@Rule class Security218Test {
public transient JenkinsRule j = new JenkinsRule();
@Rule @RegisterExtension
public transient InboundAgentRule inboundAgents = new InboundAgentRule(); private final InboundAgentExtension inboundAgents = new InboundAgentExtension();
@Rule private final LogRecorder logging = new LogRecorder().record(ClassFilterImpl.class, Level.FINE);
public LoggerRule logging = new LoggerRule().record(ClassFilterImpl.class, Level.FINE);
private JenkinsRule j;
@BeforeEach
void setUp(JenkinsRule rule) {
j = rule;
}
/** /**
* Makes sure SECURITY-218 fix also applies to agents. * Makes sure SECURITY-218 fix also applies to agents.
@ -36,7 +42,7 @@ public class Security218Test implements Serializable {
* This test is for regular static agent * This test is for regular static agent
*/ */
@Test @Test
public void dumbSlave() throws Exception { void dumbSlave() throws Exception {
check(j.createOnlineSlave()); check(j.createOnlineSlave());
} }
@ -46,8 +52,8 @@ public class Security218Test implements Serializable {
* This test is for JNLP agent * This test is for JNLP agent
*/ */
@Test @Test
public void jnlpSlave() throws Exception { void jnlpSlave() throws Exception {
DumbSlave a = (DumbSlave) inboundAgents.createAgent(j, InboundAgentRule.Options.newBuilder().secret().build()); DumbSlave a = (DumbSlave) inboundAgents.createAgent(j, InboundAgentExtension.Options.newBuilder().build());
try { try {
j.createWebClient().goTo("computer/" + a.getNodeName() + "/jenkins-agent.jnlp?encrypt=true", "application/octet-stream"); j.createWebClient().goTo("computer/" + a.getNodeName() + "/jenkins-agent.jnlp?encrypt=true", "application/octet-stream");
check(a); check(a);
@ -63,9 +69,9 @@ public class Security218Test implements Serializable {
@SuppressWarnings("ConstantConditions") @SuppressWarnings("ConstantConditions")
private void check(DumbSlave s) { private void check(DumbSlave s) {
IOException e = assertThrows( IOException e = assertThrows(
"Expected the connection to die",
IOException.class, IOException.class,
() -> s.getComputer().getChannel().call(new EvilReturnValue())); () -> s.getComputer().getChannel().call(new EvilReturnValue()),
"Expected the connection to die");
assertThat(e.getMessage(), containsString(MethodClosure.class.getName())); assertThat(e.getMessage(), containsString(MethodClosure.class.getName()));
} }

View File

@ -7,10 +7,10 @@ import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.Assert.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.Assert.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import hudson.ExtensionList; import hudson.ExtensionList;
import hudson.model.Computer; import hudson.model.Computer;
@ -38,37 +38,38 @@ import org.apache.commons.io.IOUtils;
import org.hamcrest.Description; import org.hamcrest.Description;
import org.hamcrest.Matcher; import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher; import org.hamcrest.TypeSafeMatcher;
import org.junit.Rule; import org.junit.jupiter.api.Test;
import org.junit.Test; import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.rules.TemporaryFolder; import org.junit.jupiter.api.io.TempDir;
import org.jvnet.hudson.test.InboundAgentRule;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.RealJenkinsRule; import org.jvnet.hudson.test.junit.jupiter.InboundAgentExtension;
import org.jvnet.hudson.test.junit.jupiter.RealJenkinsExtension;
import org.kohsuke.args4j.Argument; import org.kohsuke.args4j.Argument;
import org.kohsuke.stapler.Stapler; import org.kohsuke.stapler.Stapler;
public class Security3430Test { class Security3430Test {
@Rule
public RealJenkinsRule jj = new RealJenkinsRule().withLogger(JarURLValidatorImpl.class, Level.FINEST);
@Rule @RegisterExtension
public InboundAgentRule agents = new InboundAgentRule(); private final RealJenkinsExtension jj = new RealJenkinsExtension().withLogger(JarURLValidatorImpl.class, Level.FINEST);
@Rule @RegisterExtension
public TemporaryFolder tmp = new TemporaryFolder(); private final InboundAgentExtension agents = new InboundAgentExtension();
@TempDir
private File tmp;
@Test @Test
public void runWithOldestSupportedAgentJar() throws Throwable { void runWithOldestSupportedAgentJar() throws Throwable {
runWithRemoting(RemotingVersionInfo.getMinimumSupportedVersion().toString(), "/old-remoting/remoting-minimum-supported.jar", true); runWithRemoting(RemotingVersionInfo.getMinimumSupportedVersion().toString(), "/old-remoting/remoting-minimum-supported.jar", true);
} }
@Test @Test
public void runWithPreviousAgentJar() throws Throwable { void runWithPreviousAgentJar() throws Throwable {
runWithRemoting("3256.v88a_f6e922152", "/old-remoting/remoting-before-SECURITY-3430-fix.jar", true); runWithRemoting("3256.v88a_f6e922152", "/old-remoting/remoting-before-SECURITY-3430-fix.jar", true);
} }
@Test @Test
public void runWithCurrentAgentJar() throws Throwable { void runWithCurrentAgentJar() throws Throwable {
runWithRemoting(Launcher.VERSION, null, false); runWithRemoting(Launcher.VERSION, null, false);
} }
@ -93,19 +94,19 @@ public class Security3430Test {
private void createAgent(String name, String remotingResourcePath) throws Throwable { private void createAgent(String name, String remotingResourcePath) throws Throwable {
if (remotingResourcePath != null) { if (remotingResourcePath != null) {
var jar = tmp.newFile(name + ".jar"); var jar = newFile(tmp, name + ".jar");
FileUtils.copyURLToFile(Security3430Test.class.getResource(remotingResourcePath), jar); FileUtils.copyURLToFile(Security3430Test.class.getResource(remotingResourcePath), jar);
// TODO awkward, especially as InboundAgentRule.getAgentArguments is private; // TODO awkward, especially as InboundAgentRule.getAgentArguments is private;
// would be helpful to have an option for a specific agent JAR: // would be helpful to have an option for a specific agent JAR:
var opts = InboundAgentRule.Options.newBuilder().name(name).skipStart().build(); var opts = InboundAgentExtension.Options.newBuilder().name(name).skipStart().build();
agents.createAgent(jj, opts); agents.createAgent(jj, opts);
agents.start(new InboundAgentRule.AgentArguments(jar, jj.getUrl().toString(), name, jj.runRemotely(Security3430Test::getJnlpMac, name), 1, List.of()), opts); agents.start(new InboundAgentExtension.AgentArguments(jar, jj.getUrl().toString(), name, jj.runRemotely(Security3430Test::getJnlpMac, name), 1, List.of()), opts);
} else { } else {
agents.createAgent(jj, InboundAgentRule.Options.newBuilder().name(name).build()); agents.createAgent(jj, InboundAgentExtension.Options.newBuilder().name(name).build());
} }
} }
private static String getJnlpMac(JenkinsRule r, String name) throws Throwable { private static String getJnlpMac(JenkinsRule r, String name) {
return ((SlaveComputer) r.jenkins.getComputer(name)).getJnlpMac(); return ((SlaveComputer) r.jenkins.getComputer(name)).getJnlpMac();
} }
@ -314,4 +315,10 @@ public class Security3430Test {
mismatchDescription.appendText(item.getMessage()); mismatchDescription.appendText(item.getMessage());
} }
} }
private static File newFile(File parent, String child) throws IOException {
File result = new File(parent, child);
result.createNewFile();
return result;
}
} }

View File

@ -2,47 +2,46 @@ package jenkins.security;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertThrows;
import java.util.List; import java.util.List;
import jenkins.security.security3501Test.Security3501RootAction; import jenkins.security.security3501Test.Security3501RootAction;
import org.htmlunit.FailingHttpStatusCodeException; import org.htmlunit.FailingHttpStatusCodeException;
import org.junit.Assert; import org.junit.jupiter.api.BeforeEach;
import org.junit.Rule; import org.junit.jupiter.api.Test;
import org.junit.Test; import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.runner.RunWith; import org.junit.jupiter.params.Parameter;
import org.junit.runners.Parameterized; import org.junit.jupiter.params.ParameterizedClass;
import org.junit.jupiter.params.provider.ValueSource;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.RealJenkinsRule; import org.jvnet.hudson.test.junit.jupiter.RealJenkinsExtension;
@RunWith(Parameterized.class) @ParameterizedClass
public class Security3501Test { @ValueSource(strings = { "/jenkins", "" })
// Workaround for https://github.com/jenkinsci/jenkins-test-harness/issues/933 class Security3501Test {
private final String contextPath;
@Rule @Parameter
public RealJenkinsRule jj = new RealJenkinsRule().addSyntheticPlugin(new RealJenkinsRule.SyntheticPlugin(Security3501RootAction.class.getPackage()).shortName("Security3501RootAction")); private String contextPath;
@Parameterized.Parameters @RegisterExtension
public static List<String> contexts() { private final RealJenkinsExtension jj = new RealJenkinsExtension().addSyntheticPlugin(new RealJenkinsExtension.SyntheticPlugin(Security3501RootAction.class.getPackage()).shortName("Security3501RootAction"));
return List.of("/jenkins", "");
}
public Security3501Test(String contextPath) { @BeforeEach
void setUp() {
jj.withPrefix(contextPath); jj.withPrefix(contextPath);
this.contextPath = contextPath;
} }
@Test @Test
public void testRedirects() throws Throwable { void testRedirects() throws Throwable {
jj.then(new TestRedirectsStep(contextPath)); jj.then(new TestRedirectsStep(contextPath));
} }
private record TestRedirectsStep(String context) implements RealJenkinsRule.Step { private record TestRedirectsStep(String context) implements RealJenkinsExtension.Step {
public void run(JenkinsRule j) throws Exception { public void run(JenkinsRule j) throws Exception {
List<String> prohibitedPaths = List.of("%5C%5Cexample.org", "%5C/example.org", "/%5Cexample.org", "//example.org", "https://example.org", "\\example.org"); List<String> prohibitedPaths = List.of("%5C%5Cexample.org", "%5C/example.org", "/%5Cexample.org", "//example.org", "https://example.org", "\\example.org");
for (String path : prohibitedPaths) { for (String path : prohibitedPaths) {
try (JenkinsRule.WebClient wc = j.createWebClient().withRedirectEnabled(false)) { try (JenkinsRule.WebClient wc = j.createWebClient().withRedirectEnabled(false)) {
final FailingHttpStatusCodeException fhsce = Assert.assertThrows(FailingHttpStatusCodeException.class, () -> wc.goTo("redirects/content?path=" + path)); final FailingHttpStatusCodeException fhsce = assertThrows(FailingHttpStatusCodeException.class, () -> wc.goTo("redirects/content?path=" + path));
assertThat(fhsce.getStatusCode(), is(404)); assertThat(fhsce.getStatusCode(), is(404));
} }
} }
@ -50,7 +49,7 @@ public class Security3501Test {
List<String> allowedPaths = List.of("foo", "foo/bar"); List<String> allowedPaths = List.of("foo", "foo/bar");
for (String path : allowedPaths) { for (String path : allowedPaths) {
try (JenkinsRule.WebClient wc = j.createWebClient().withRedirectEnabled(false)) { try (JenkinsRule.WebClient wc = j.createWebClient().withRedirectEnabled(false)) {
final FailingHttpStatusCodeException fhsce = Assert.assertThrows(FailingHttpStatusCodeException.class, () -> wc.goTo("redirects/content?path=" + path)); final FailingHttpStatusCodeException fhsce = assertThrows(FailingHttpStatusCodeException.class, () -> wc.goTo("redirects/content?path=" + path));
assertThat(fhsce.getStatusCode(), is(302)); assertThat(fhsce.getStatusCode(), is(302));
assertThat(fhsce.getResponse().getResponseHeaderValue("Location"), is(context + "/redirects/" + path)); assertThat(fhsce.getResponse().getResponseHeaderValue("Location"), is(context + "/redirects/" + path));
} }

View File

@ -28,9 +28,9 @@ import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.Assume.assumeNoException; import static org.junit.jupiter.api.Assumptions.assumeTrue;
import hudson.EnvVars; import hudson.EnvVars;
import hudson.Launcher; import hudson.Launcher;
@ -48,21 +48,21 @@ import java.net.URLStreamHandler;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import org.junit.Ignore; import org.junit.jupiter.api.Disabled;
import org.junit.Rule; import org.junit.jupiter.api.Test;
import org.junit.Test; import org.junit.jupiter.api.extension.RegisterExtension;
import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsSessionRule;
import org.jvnet.hudson.test.TestExtension; import org.jvnet.hudson.test.TestExtension;
import org.jvnet.hudson.test.junit.jupiter.JenkinsSessionExtension;
public class Security637Test { class Security637Test {
@Rule @RegisterExtension
public JenkinsSessionRule sessions = new JenkinsSessionRule(); private final JenkinsSessionExtension sessions = new JenkinsSessionExtension();
@Test @Test
@Issue("SECURITY-637") @Issue("SECURITY-637")
public void urlSafeDeserialization_handler_inSameJVMRemotingContext() throws Throwable { void urlSafeDeserialization_handler_inSameJVMRemotingContext() throws Throwable {
sessions.then(j -> { sessions.then(j -> {
DumbSlave slave = j.createOnlineSlave(null, new EnvVars("JAVA_TOOL_OPTIONS", "--add-opens=java.base/java.net=ALL-UNNAMED")); DumbSlave slave = j.createOnlineSlave(null, new EnvVars("JAVA_TOOL_OPTIONS", "--add-opens=java.base/java.net=ALL-UNNAMED"));
String unsafeHandlerClassName = slave.getChannel().call(new URLHandlerCallable(new URL("https://www.google.com/"))); String unsafeHandlerClassName = slave.getChannel().call(new URLHandlerCallable(new URL("https://www.google.com/")));
@ -89,23 +89,22 @@ public class Security637Test {
} }
} }
@Ignore("TODO these map to different IPs now") @Disabled("TODO these map to different IPs now")
@Test @Test
@Issue("SECURITY-637") @Issue("SECURITY-637")
public void urlDnsEquivalence() throws Throwable { void urlDnsEquivalence() throws Throwable {
sessions.then(j -> { sessions.then(j ->
// due to the DNS resolution they are equal // due to the DNS resolution they are equal
assertEquals( assertEquals(
new URI("https://jenkins.io").toURL(), new URI("https://jenkins.io").toURL(),
new URI("https://www.jenkins.io").toURL() new URI("https://www.jenkins.io").toURL()
); ));
});
} }
@Ignore("TODO these map to different IPs now") @Disabled("TODO these map to different IPs now")
@Test @Test
@Issue("SECURITY-637") @Issue("SECURITY-637")
public void urlSafeDeserialization_urlBuiltInAgent_inSameJVMRemotingContext() throws Throwable { void urlSafeDeserialization_urlBuiltInAgent_inSameJVMRemotingContext() throws Throwable {
sessions.then(j -> { sessions.then(j -> {
DumbSlave slave = j.createOnlineSlave(); DumbSlave slave = j.createOnlineSlave();
@ -132,10 +131,10 @@ public class Security637Test {
} }
} }
@Ignore("TODO these map to different IPs now") @Disabled("TODO these map to different IPs now")
@Test @Test
@Issue("SECURITY-637") @Issue("SECURITY-637")
public void urlSafeDeserialization_urlBuiltInMaster_inSameJVMRemotingContext() throws Throwable { void urlSafeDeserialization_urlBuiltInMaster_inSameJVMRemotingContext() throws Throwable {
sessions.then(j -> { sessions.then(j -> {
DumbSlave slave = j.createOnlineSlave(); DumbSlave slave = j.createOnlineSlave();
@ -171,7 +170,7 @@ public class Security637Test {
@Test @Test
@Issue("SECURITY-637") @Issue("SECURITY-637")
public void urlSafeDeserialization_inXStreamContext() throws Throwable { void urlSafeDeserialization_inXStreamContext() throws Throwable {
sessions.then(j -> { sessions.then(j -> {
FreeStyleProject project = j.createFreeStyleProject("project-with-url"); FreeStyleProject project = j.createFreeStyleProject("project-with-url");
URLJobProperty URLJobProperty = new URLJobProperty( URLJobProperty URLJobProperty = new URLJobProperty(
@ -193,7 +192,7 @@ public class Security637Test {
try { try {
handlerField.setAccessible(true); handlerField.setAccessible(true);
} catch (RuntimeException e) { } catch (RuntimeException e) {
assumeNoException(e); assumeTrue(false, e.getMessage());
} }
URLJobProperty urlJobProperty = project.getProperty(URLJobProperty.class); URLJobProperty urlJobProperty = project.getProperty(URLJobProperty.class);
@ -212,6 +211,7 @@ public class Security637Test {
private Set<URL> urlSet; private Set<URL> urlSet;
@SuppressWarnings(value = "checkstyle:redundantmodifier")
public URLJobProperty(URL... urls) { public URLJobProperty(URL... urls) {
this.urlSet = new HashSet<>(); this.urlSet = new HashSet<>();
Collections.addAll(urlSet, urls); Collections.addAll(urlSet, urls);

View File

@ -24,8 +24,8 @@
package jenkins.security; package jenkins.security;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertNull; import static org.junit.jupiter.api.Assertions.assertNull;
import hudson.model.User; import hudson.model.User;
import hudson.security.ACL; import hudson.security.ACL;
@ -35,51 +35,57 @@ import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ScheduledThreadPoolExecutor;
import org.junit.Rule; import jenkins.model.Jenkins;
import org.junit.Test; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.recipes.PresetData; import org.jvnet.hudson.test.MockAuthorizationStrategy;
import org.jvnet.hudson.test.junit.jupiter.WithJenkins;
import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
/** /**
* @author Patrick McKeown * @author Patrick McKeown
*/ */
public class SecurityContextExecutorServiceTest { @WithJenkins
class SecurityContextExecutorServiceTest {
private final int NUM_THREADS = 10; private static final int NUM_THREADS = 10;
private ExecutorService wrappedService = null; private ExecutorService wrappedService = null;
private SecurityContext systemContext = null; private SecurityContext systemContext = null;
private SecurityContext userContext = null; private SecurityContext userContext = null;
private SecurityContext nullContext = null; private SecurityContext nullContext = null;
private volatile SecurityContext runnableThreadContext; private SecurityContext runnableThreadContext;
@Rule
public JenkinsRule j = new JenkinsRule() {
@Override
public void before() throws Throwable {
setPluginManager(null);
super.before();
ScheduledThreadPoolExecutor service = new ScheduledThreadPoolExecutor(NUM_THREADS); private JenkinsRule j;
// Create a system level context with ACL.SYSTEM2
systemContext = ACL.impersonate2(ACL.SYSTEM2);
User u = User.get("bob"); @BeforeEach
// Create a sample user context void setUp(JenkinsRule rule) {
userContext = new NonSerializableSecurityContext(u.impersonate2()); j = rule;
// Create a null context JenkinsRule.DummySecurityRealm realm = j.createDummySecurityRealm();
SecurityContextHolder.clearContext(); j.jenkins.setSecurityRealm(realm);
nullContext = SecurityContextHolder.getContext(); j.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy()
.grant(Jenkins.ADMINISTER).everywhere().toAuthenticated());
// Create a wrapped service ScheduledThreadPoolExecutor service = new ScheduledThreadPoolExecutor(NUM_THREADS);
wrappedService = new SecurityContextExecutorService(service); // Create a system level context with ACL.SYSTEM2
} systemContext = ACL.impersonate2(ACL.SYSTEM2);
};
User u = User.get("bob");
// Create a sample user context
userContext = new NonSerializableSecurityContext(u.impersonate2());
// Create a null context
SecurityContextHolder.clearContext();
nullContext = SecurityContextHolder.getContext();
// Create a wrapped service
wrappedService = new SecurityContextExecutorService(service);
}
@Test @Test
@PresetData(PresetData.DataSet.NO_ANONYMOUS_READACCESS) void testRunnableAgainstAllContexts() throws Exception {
public void testRunnableAgainstAllContexts() throws Exception {
Runnable r = () -> runnableThreadContext = SecurityContextHolder.getContext(); Runnable r = () -> runnableThreadContext = SecurityContextHolder.getContext();
SecurityContextHolder.setContext(systemContext); SecurityContextHolder.setContext(systemContext);
Future systemResult = wrappedService.submit(r); Future systemResult = wrappedService.submit(r);
@ -104,8 +110,7 @@ public class SecurityContextExecutorServiceTest {
} }
@Test @Test
@PresetData(PresetData.DataSet.NO_ANONYMOUS_READACCESS) void testCallableAgainstAllContexts() throws Exception {
public void testCallableAgainstAllContexts() throws Exception {
Callable<SecurityContext> c = SecurityContextHolder::getContext; Callable<SecurityContext> c = SecurityContextHolder::getContext;
SecurityContextHolder.setContext(systemContext); SecurityContextHolder.setContext(systemContext);
Future<SecurityContext> result = wrappedService.submit(c); Future<SecurityContext> result = wrappedService.submit(c);
@ -124,8 +129,7 @@ public class SecurityContextExecutorServiceTest {
} }
@Test @Test
@PresetData(PresetData.DataSet.NO_ANONYMOUS_READACCESS) void testCallableCollectionAgainstAllContexts() throws Exception {
public void testCallableCollectionAgainstAllContexts() throws Exception {
Collection<Callable<SecurityContext>> callables = new ArrayList<>(); Collection<Callable<SecurityContext>> callables = new ArrayList<>();
Callable<SecurityContext> c = SecurityContextHolder::getContext; Callable<SecurityContext> c = SecurityContextHolder::getContext;
callables.add(c); callables.add(c);
@ -156,8 +160,7 @@ public class SecurityContextExecutorServiceTest {
} }
@Test @Test
@PresetData(PresetData.DataSet.NO_ANONYMOUS_READACCESS) void testFailedRunnableResetsContext() {
public void testFailedRunnableResetsContext() {
Runnable r = () -> { Runnable r = () -> {
SecurityContextHolder.setContext(nullContext); SecurityContextHolder.setContext(nullContext);
throw new RuntimeException("Simulate a failure"); throw new RuntimeException("Simulate a failure");

View File

@ -29,10 +29,10 @@ import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.not;
import static org.hamcrest.xml.HasXPath.hasXPath; import static org.hamcrest.xml.HasXPath.hasXPath;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.Assert.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import hudson.model.User; import hudson.model.User;
import java.io.File; import java.io.File;
@ -50,23 +50,23 @@ import org.htmlunit.html.HtmlPage;
import org.htmlunit.html.HtmlSpan; import org.htmlunit.html.HtmlSpan;
import org.htmlunit.util.NameValuePair; import org.htmlunit.util.NameValuePair;
import org.htmlunit.xml.XmlPage; import org.htmlunit.xml.XmlPage;
import org.junit.Rule; import org.junit.jupiter.api.Test;
import org.junit.Test; import org.junit.jupiter.api.extension.RegisterExtension;
import org.jvnet.hudson.test.For; import org.jvnet.hudson.test.For;
import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.JenkinsRule.WebClient; import org.jvnet.hudson.test.JenkinsRule.WebClient;
import org.jvnet.hudson.test.JenkinsSessionRule; import org.jvnet.hudson.test.junit.jupiter.JenkinsSessionExtension;
@For(ApiTokenStats.class) @For(ApiTokenStats.class)
public class ApiTokenStatsRestartTest { class ApiTokenStatsRestartTest {
@Rule @RegisterExtension
public JenkinsSessionRule sessions = new JenkinsSessionRule(); private final JenkinsSessionExtension sessions = new JenkinsSessionExtension();
@Test @Test
@Issue("SECURITY-1072") @Issue("SECURITY-1072")
public void roundtripWithRestart() throws Throwable { void roundtripWithRestart() throws Throwable {
AtomicReference<String> tokenValue = new AtomicReference<>(); AtomicReference<String> tokenValue = new AtomicReference<>();
AtomicReference<String> tokenUuid = new AtomicReference<>(); AtomicReference<String> tokenUuid = new AtomicReference<>();
String TOKEN_NAME = "New Token Name"; String TOKEN_NAME = "New Token Name";
@ -119,7 +119,7 @@ public class ApiTokenStatsRestartTest {
assertThat(useCounterSpan.getTextContent(), containsString("" + NUM_CALL_WITH_TOKEN)); assertThat(useCounterSpan.getTextContent(), containsString("" + NUM_CALL_WITH_TOKEN));
File apiTokenStatsFile = new File(u.getUserFolder(), "apiTokenStats.xml"); File apiTokenStatsFile = new File(u.getUserFolder(), "apiTokenStats.xml");
assertTrue("apiTokenStats.xml file should exist", apiTokenStatsFile.exists()); assertTrue(apiTokenStatsFile.exists(), "apiTokenStats.xml file should exist");
}); });
sessions.then(j -> { sessions.then(j -> {
@ -159,7 +159,7 @@ public class ApiTokenStatsRestartTest {
assertThat(xmlPage, hasXPath("//authority", is("authenticated"))); assertThat(xmlPage, hasXPath("//authority", is("authenticated")));
} }
private static void checkUserIsNotConnected(WebClient wc) throws Exception { private static void checkUserIsNotConnected(WebClient wc) {
FailingHttpStatusCodeException e = assertThrows(FailingHttpStatusCodeException.class, () -> wc.goToXml("whoAmI/api/xml")); FailingHttpStatusCodeException e = assertThrows(FailingHttpStatusCodeException.class, () -> wc.goToXml("whoAmI/api/xml"));
assertEquals(401, e.getStatusCode()); assertEquals(401, e.getStatusCode());
} }

View File

@ -24,31 +24,31 @@
package jenkins.security.seed; package jenkins.security.seed;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import hudson.model.User; import hudson.model.User;
import java.net.URI; import java.net.URI;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import org.htmlunit.HttpMethod; import org.htmlunit.HttpMethod;
import org.htmlunit.WebRequest; import org.htmlunit.WebRequest;
import org.junit.Rule; import org.junit.jupiter.api.Test;
import org.junit.Test; import org.junit.jupiter.api.extension.RegisterExtension;
import org.jvnet.hudson.test.For; import org.jvnet.hudson.test.For;
import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.JenkinsSessionRule; import org.jvnet.hudson.test.junit.jupiter.JenkinsSessionExtension;
@For(UserSeedProperty.class) @For(UserSeedProperty.class)
public class UserSeedPropertyRestartTest { class UserSeedPropertyRestartTest {
@Rule @RegisterExtension
public JenkinsSessionRule sessions = new JenkinsSessionRule(); private final JenkinsSessionExtension sessions = new JenkinsSessionExtension();
@Test @Test
@Issue("SECURITY-901") @Issue("SECURITY-901")
public void initialSeedIsSaved() throws Throwable { void initialSeedIsSaved() throws Throwable {
AtomicReference<String> initialSeedRef = new AtomicReference<>(); AtomicReference<String> initialSeedRef = new AtomicReference<>();
sessions.then(j -> { sessions.then(j -> {
@ -68,7 +68,7 @@ public class UserSeedPropertyRestartTest {
@Test @Test
@Issue("SECURITY-901") @Issue("SECURITY-901")
public void renewSeedSavesTheChange() throws Throwable { void renewSeedSavesTheChange() throws Throwable {
AtomicReference<String> initialSeedRef = new AtomicReference<>(); AtomicReference<String> initialSeedRef = new AtomicReference<>();
AtomicReference<String> seedRef = new AtomicReference<>(); AtomicReference<String> seedRef = new AtomicReference<>();

View File

@ -1,26 +1,32 @@
package jenkins.security.stapler; package jenkins.security.stapler;
import static org.junit.Assume.assumeFalse; import static org.junit.jupiter.api.Assumptions.assumeFalse;
import hudson.Functions; import hudson.Functions;
import org.junit.Rule; import org.junit.jupiter.api.BeforeEach;
import org.junit.Test; import org.junit.jupiter.api.Test;
import org.jvnet.hudson.test.For; import org.jvnet.hudson.test.For;
import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.junit.jupiter.WithJenkins;
import org.jvnet.hudson.test.recipes.WithPlugin; import org.jvnet.hudson.test.recipes.WithPlugin;
@Issue("SECURITY-400") @Issue("SECURITY-400")
@For({StaplerDispatchable.class, StaplerAccessibleType.class}) @For({StaplerDispatchable.class, StaplerAccessibleType.class})
public class JenkinsSupportAnnotationsTest { @WithJenkins
class JenkinsSupportAnnotationsTest {
@Rule private JenkinsRule j;
public JenkinsRule j = new JenkinsRule();
@BeforeEach
void setUp(JenkinsRule rule) {
j = rule;
}
@Test @Test
@WithPlugin("annotations-test.hpi") @WithPlugin("annotations-test.hpi")
public void testPluginWithAnnotations() throws Exception { void testPluginWithAnnotations() throws Exception {
assumeFalse("TODO: Implement this test on Windows", Functions.isWindows()); assumeFalse(Functions.isWindows(), "TODO: Implement this test on Windows");
// test fails if TypedFilter ignores @StaplerDispatchable // test fails if TypedFilter ignores @StaplerDispatchable
j.createWebClient().goTo("annotationsTest/whatever", ""); j.createWebClient().goTo("annotationsTest/whatever", "");

View File

@ -57,80 +57,88 @@ import java.net.URISyntaxException;
import java.util.Collection; import java.util.Collection;
import jenkins.security.MasterToSlaveCallable; import jenkins.security.MasterToSlaveCallable;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.junit.Before; import org.junit.jupiter.api.BeforeEach;
import org.junit.Rule; import org.junit.jupiter.api.Test;
import org.junit.Test; import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.rules.TemporaryFolder; import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.api.io.TempDir;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.SimpleCommandLauncher; import org.jvnet.hudson.test.SimpleCommandLauncher;
import org.jvnet.hudson.test.TestBuilder; import org.jvnet.hudson.test.TestBuilder;
import org.jvnet.hudson.test.TestExtension; import org.jvnet.hudson.test.TestExtension;
import org.jvnet.hudson.test.junit.jupiter.JenkinsSessionExtension;
/** /**
* Tests for old Remoting agent versions * Tests for old Remoting agent versions
*/ */
public class OldRemotingAgentTest { class OldRemotingAgentTest {
@Rule @RegisterExtension
public JenkinsRule j = new JenkinsRuleWithOldAgent(); private final JenkinsSessionExtension session = new JenkinsExtensionWithOldAgent();
@Rule @TempDir
public TemporaryFolder tmpDir = new TemporaryFolder(); private File tmpDir;
private File agentJar; private static File agentJar;
@Before @BeforeEach
public void extractAgent() throws Exception { void extractAgent() throws Exception {
agentJar = new File(tmpDir.getRoot(), "old-agent.jar"); agentJar = new File(tmpDir, "old-agent.jar");
FileUtils.copyURLToFile(OldRemotingAgentTest.class.getResource("/old-remoting/remoting-minimum-supported.jar"), agentJar); FileUtils.copyURLToFile(OldRemotingAgentTest.class.getResource("/old-remoting/remoting-minimum-supported.jar"), agentJar);
} }
@Test @Test
@Issue("JENKINS-48761") @Issue("JENKINS-48761")
public void shouldBeAbleToConnectAgentWithMinimumSupportedVersion() throws Exception { void shouldBeAbleToConnectAgentWithMinimumSupportedVersion() throws Throwable {
Label agentLabel = new LabelAtom("old-agent"); session.then(j -> {
Slave agent = j.createOnlineSlave(agentLabel); Label agentLabel = new LabelAtom("old-agent");
boolean isUnix = agent.getComputer().isUnix(); Slave agent = j.createOnlineSlave(agentLabel);
assertThat("Received wrong agent version. A minimum supported version is expected", boolean isUnix = agent.getComputer().isUnix();
agent.getComputer().getSlaveVersion(), assertThat("Received wrong agent version. A minimum supported version is expected",
equalTo(RemotingVersionInfo.getMinimumSupportedVersion().toString())); agent.getComputer().getSlaveVersion(),
equalTo(RemotingVersionInfo.getMinimumSupportedVersion().toString()));
// Just ensure we are able to run something on the agent // Just ensure we are able to run something on the agent
FreeStyleProject project = j.createFreeStyleProject("foo"); FreeStyleProject project = j.createFreeStyleProject("foo");
project.setAssignedLabel(agentLabel); project.setAssignedLabel(agentLabel);
project.getBuildersList().add(isUnix ? new Shell("echo Hello") : new BatchFile("echo 'hello'")); project.getBuildersList().add(isUnix ? new Shell("echo Hello") : new BatchFile("echo 'hello'"));
j.buildAndAssertSuccess(project); j.buildAndAssertSuccess(project);
// Run agent monitors // Run agent monitors
NodeMonitorAssert.assertMonitors(NodeMonitor.getAll(), agent.getComputer()); NodeMonitorAssert.assertMonitors(NodeMonitor.getAll(), agent.getComputer());
});
} }
@Issue("JENKINS-55257") @Issue("JENKINS-55257")
@Test @Test
public void remoteConsoleNote() throws Exception { void remoteConsoleNote() throws Throwable {
Slave agent = j.createOnlineSlave(); session.then(j -> {
FreeStyleProject project = j.createFreeStyleProject(); Slave agent = j.createOnlineSlave();
project.setAssignedLabel(agent.getSelfLabel()); FreeStyleProject project = j.createFreeStyleProject();
project.getBuildersList().add(new TestBuilder() { project.setAssignedLabel(agent.getSelfLabel());
@Override project.getBuildersList().add(new TestBuilder() {
public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { @Override
build.getWorkspace().act(new RemoteConsoleNotePrinter(listener)); public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException {
return true; build.getWorkspace().act(new RemoteConsoleNotePrinter(listener));
return true;
}
});
FreeStyleBuild b = j.buildAndAssertSuccess(project);
StringWriter sw = new StringWriter();
// The note will not actually work by default; we just want to ensure that the attempt is ignored without breaking the build.
// But for purposes of testing, check that the note really made it into the log.
boolean insecureOriginal = ConsoleNote.INSECURE;
ConsoleNote.INSECURE = true;
try {
b.getLogText().writeHtmlTo(0, sw);
} finally {
ConsoleNote.INSECURE = insecureOriginal;
} }
assertThat(sw.toString(), containsString("@@@ANNOTATED@@@"));
}); });
FreeStyleBuild b = j.buildAndAssertSuccess(project);
StringWriter sw = new StringWriter();
// The note will not actually work by default; we just want to ensure that the attempt is ignored without breaking the build.
// But for purposes of testing, check that the note really made it into the log.
boolean insecureOriginal = ConsoleNote.INSECURE;
ConsoleNote.INSECURE = true;
try {
b.getLogText().writeHtmlTo(0, sw);
} finally {
ConsoleNote.INSECURE = insecureOriginal;
}
assertThat(sw.toString(), containsString("@@@ANNOTATED@@@"));
} }
private static final class RemoteConsoleNotePrinter extends MasterToSlaveCallable<Void, IOException> { private static final class RemoteConsoleNotePrinter extends MasterToSlaveCallable<Void, IOException> {
@ -160,17 +168,56 @@ public class OldRemotingAgentTest {
} }
//TODO: move the logic to JTH //TODO: move the logic to JTH
private class JenkinsRuleWithOldAgent extends JenkinsRule { private static final class JenkinsExtensionWithOldAgent extends JenkinsSessionExtension {
private int port;
private Description description;
@Override @Override
public ComputerLauncher createComputerLauncher(EnvVars env) throws URISyntaxException, IOException { public void beforeEach(ExtensionContext context) {
super.beforeEach(context);
description = Description.createTestDescription(
context.getTestClass().map(Class::getName).orElse(null),
context.getTestMethod().map(Method::getName).orElse(null),
context.getTestMethod().map(Method::getAnnotations).orElse(null));
}
// EnvVars are ignored, simple Command Launcher does not offer this API in public @Override
int sz = this.jenkins.getNodes().size(); public void then(Step s) throws Throwable {
return new SimpleCommandLauncher(String.format("\"%s/bin/java\" %s -jar \"%s\"", CustomJenkinsRule r = new CustomJenkinsRule(getHome(), port);
System.getProperty("java.home"), r.apply(
SLAVE_DEBUG_PORT > 0 ? " -Xdebug -Xrunjdwp:transport=dt_socket,server=y,address=" + (SLAVE_DEBUG_PORT + sz) : "", new Statement() {
agentJar.getAbsolutePath())); @Override
public void evaluate() throws Throwable {
port = r.getPort();
s.run(r);
}
},
description
).evaluate();
}
private static final class CustomJenkinsRule extends JenkinsRule {
CustomJenkinsRule(File home, int port) {
with(() -> home);
localPort = port;
}
int getPort() {
return localPort;
}
@Override
public ComputerLauncher createComputerLauncher(EnvVars env) throws URISyntaxException, IOException {
// EnvVars are ignored, simple Command Launcher does not offer this API in public
int sz = this.jenkins.getNodes().size();
return new SimpleCommandLauncher(String.format("\"%s/bin/java\" %s -jar \"%s\"",
System.getProperty("java.home"),
SLAVE_DEBUG_PORT > 0 ? " -Xdebug -Xrunjdwp:transport=dt_socket,server=y,address=" + (SLAVE_DEBUG_PORT + sz) : "",
agentJar.getAbsolutePath()));
}
} }
} }

View File

@ -12,69 +12,124 @@ import hudson.tasks.BatchFile;
import hudson.tasks.Shell; import hudson.tasks.Shell;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.junit.Before; import org.junit.jupiter.api.AfterEach;
import org.junit.Rule; import org.junit.jupiter.api.BeforeEach;
import org.junit.Test; import org.junit.jupiter.api.Test;
import org.junit.rules.TemporaryFolder; import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.rules.TestRule; import org.junit.jupiter.api.extension.RegisterExtension;
import org.jvnet.hudson.test.FlagRule; import org.junit.jupiter.api.io.TempDir;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.SimpleCommandLauncher; import org.jvnet.hudson.test.SimpleCommandLauncher;
import org.jvnet.hudson.test.junit.jupiter.JenkinsSessionExtension;
/** /**
* Test for the escape hatch for unsupported Remoting agent versions * Test for the escape hatch for unsupported Remoting agent versions
*/ */
public class UnsupportedRemotingAgentEscapeHatchTest { class UnsupportedRemotingAgentEscapeHatchTest {
@Rule public JenkinsRule j = new JenkinsRuleWithUnsupportedAgent(); @RegisterExtension
private final JenkinsSessionExtension session = new JenkinsExtensionWithUnsupportedAgent();
@Rule public TemporaryFolder tmpDir = new TemporaryFolder(); @TempDir
private File tmpDir;
@Rule private String allowUnsupportedRemotingVersions;
public TestRule allowUnsupportedRemotingVersions = FlagRule.systemProperty(
SlaveComputer.class.getName() + ".allowUnsupportedRemotingVersions",
Boolean.toString(true));
private File agentJar; private static File agentJar;
@Before @BeforeEach
public void extractAgent() throws Exception { void setUp() throws Exception {
agentJar = new File(tmpDir.getRoot(), "unsupported-agent.jar"); allowUnsupportedRemotingVersions = System.setProperty(SlaveComputer.class.getName() + ".allowUnsupportedRemotingVersions", "true");
agentJar = new File(tmpDir, "unsupported-agent.jar");
FileUtils.copyURLToFile(UnsupportedRemotingAgentEscapeHatchTest.class.getResource("/old-remoting/remoting-unsupported.jar"), agentJar); FileUtils.copyURLToFile(UnsupportedRemotingAgentEscapeHatchTest.class.getResource("/old-remoting/remoting-unsupported.jar"), agentJar);
} }
@AfterEach
void tearDown() {
if (allowUnsupportedRemotingVersions != null) {
System.setProperty(SlaveComputer.class.getName() + ".allowUnsupportedRemotingVersions", allowUnsupportedRemotingVersions);
} else {
System.clearProperty(SlaveComputer.class.getName() + ".allowUnsupportedRemotingVersions");
}
}
@Issue("JENKINS-50211") @Issue("JENKINS-50211")
@Test @Test
public void shouldBeAbleToConnectAgentWithUnsupportedVersionWithEscapeHatch() throws Exception { void shouldBeAbleToConnectAgentWithUnsupportedVersionWithEscapeHatch() throws Throwable {
Slave agent = j.createOnlineSlave(); session.then(j -> {
assertThat(agent.toComputer().getLog(), containsString("The Remoting version is older than the minimum required version")); Slave agent = j.createOnlineSlave();
assertThat(agent.toComputer().getLog(), containsString("The connection will be allowed, but compatibility is NOT guaranteed")); assertThat(agent.toComputer().getLog(), containsString("The Remoting version is older than the minimum required version"));
assertThat(agent.toComputer().getLog(), containsString("The connection will be allowed, but compatibility is NOT guaranteed"));
// Ensure we are able to run something on the agent // Ensure we are able to run something on the agent
FreeStyleProject project = j.createFreeStyleProject("foo"); FreeStyleProject project = j.createFreeStyleProject("foo");
project.setAssignedLabel(agent.getSelfLabel()); project.setAssignedLabel(agent.getSelfLabel());
project.getBuildersList().add(agent.getComputer().isUnix() project.getBuildersList().add(agent.getComputer().isUnix()
? new Shell("echo Hello") ? new Shell("echo Hello")
: new BatchFile("echo 'hello'")); : new BatchFile("echo 'hello'"));
j.buildAndAssertSuccess(project); j.buildAndAssertSuccess(project);
});
} }
private class JenkinsRuleWithUnsupportedAgent extends JenkinsRule { private static class JenkinsExtensionWithUnsupportedAgent extends JenkinsSessionExtension {
private int port;
private Description description;
@Override @Override
public ComputerLauncher createComputerLauncher(EnvVars env) throws URISyntaxException, IOException { public void beforeEach(ExtensionContext context) {
int sz = this.jenkins.getNodes().size(); super.beforeEach(context);
return new SimpleCommandLauncher( description = Description.createTestDescription(
String.format( context.getTestClass().map(Class::getName).orElse(null),
"\"%s/bin/java\" %s -jar \"%s\"", context.getTestMethod().map(Method::getName).orElse(null),
System.getProperty("java.home"), context.getTestMethod().map(Method::getAnnotations).orElse(null));
SLAVE_DEBUG_PORT > 0 }
? " -Xdebug -Xrunjdwp:transport=dt_socket,server=y,address="
+ (SLAVE_DEBUG_PORT + sz) @Override
: "", public void then(Step s) throws Throwable {
agentJar.getAbsolutePath())); CustomJenkinsRule r = new CustomJenkinsRule(getHome(), port);
r.apply(
new Statement() {
@Override
public void evaluate() throws Throwable {
port = r.getPort();
s.run(r);
}
},
description
).evaluate();
}
private static final class CustomJenkinsRule extends JenkinsRule {
CustomJenkinsRule(File home, int port) {
with(() -> home);
localPort = port;
}
int getPort() {
return localPort;
}
@Override
public ComputerLauncher createComputerLauncher(EnvVars env) throws URISyntaxException, IOException {
int sz = this.jenkins.getNodes().size();
return new SimpleCommandLauncher(
String.format(
"\"%s/bin/java\" %s -jar \"%s\"",
System.getProperty("java.home"),
SLAVE_DEBUG_PORT > 0
? " -Xdebug -Xrunjdwp:transport=dt_socket,server=y,address="
+ (SLAVE_DEBUG_PORT + sz)
: "",
agentJar.getAbsolutePath()));
}
} }
} }
} }

View File

@ -3,64 +3,113 @@ package jenkins.slaves;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.instanceOf;
import static org.junit.Assert.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import hudson.EnvVars; import hudson.EnvVars;
import hudson.model.Slave; import hudson.model.Slave;
import hudson.slaves.ComputerLauncher; import hudson.slaves.ComputerLauncher;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.junit.Before; import org.junit.jupiter.api.BeforeEach;
import org.junit.Rule; import org.junit.jupiter.api.Test;
import org.junit.Test; import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.rules.TemporaryFolder; import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.api.io.TempDir;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.SimpleCommandLauncher; import org.jvnet.hudson.test.SimpleCommandLauncher;
import org.jvnet.hudson.test.junit.jupiter.JenkinsSessionExtension;
/** /**
* Test for unsupported Remoting agent versions * Test for unsupported Remoting agent versions
*/ */
public class UnsupportedRemotingAgentTest { class UnsupportedRemotingAgentTest {
@Rule public JenkinsRule j = new JenkinsRuleWithUnsupportedAgent(); @RegisterExtension
private final JenkinsSessionExtension session = new JenkinsExtensionWithUnsupportedAgent();
@Rule public TemporaryFolder tmpDir = new TemporaryFolder(); @TempDir
private File tmpDir;
private File agentJar; private static File agentJar;
@Before @BeforeEach
public void extractAgent() throws Exception { void extractAgent() throws Exception {
agentJar = new File(tmpDir.getRoot(), "unsupported-agent.jar"); agentJar = new File(tmpDir, "unsupported-agent.jar");
FileUtils.copyURLToFile(UnsupportedRemotingAgentTest.class.getResource("/old-remoting/remoting-unsupported.jar"), agentJar); FileUtils.copyURLToFile(UnsupportedRemotingAgentTest.class.getResource("/old-remoting/remoting-unsupported.jar"), agentJar);
} }
@Issue("JENKINS-50211") @Issue("JENKINS-50211")
@Test @Test
public void shouldNotBeAbleToConnectAgentWithUnsupportedVersion() throws Exception { void shouldNotBeAbleToConnectAgentWithUnsupportedVersion() throws Throwable {
Slave agent = j.createSlave(); session.then(j -> {
ExecutionException e = assertThrows(ExecutionException.class, () -> agent.toComputer().connect(false).get()); Slave agent = j.createSlave();
assertThat(e.getCause(), instanceOf(IOException.class)); ExecutionException e = assertThrows(ExecutionException.class, () -> agent.toComputer().connect(false).get());
assertThat(e.getMessage(), containsString("Agent failed to connect")); assertThat(e.getCause(), instanceOf(IOException.class));
assertThat(agent.toComputer().getLog(), containsString("Rejecting the connection because the Remoting version is older than the minimum required version")); assertThat(e.getMessage(), containsString("Agent failed to connect"));
assertThat(agent.toComputer().getLog(), containsString("Rejecting the connection because the Remoting version is older than the minimum required version"));
});
} }
private class JenkinsRuleWithUnsupportedAgent extends JenkinsRule { private static class JenkinsExtensionWithUnsupportedAgent extends JenkinsSessionExtension {
private int port;
private Description description;
@Override @Override
public ComputerLauncher createComputerLauncher(EnvVars env) throws URISyntaxException, IOException { public void beforeEach(ExtensionContext context) {
int sz = this.jenkins.getNodes().size(); super.beforeEach(context);
return new SimpleCommandLauncher( description = Description.createTestDescription(
String.format( context.getTestClass().map(Class::getName).orElse(null),
"\"%s/bin/java\" %s -jar \"%s\"", context.getTestMethod().map(Method::getName).orElse(null),
System.getProperty("java.home"), context.getTestMethod().map(Method::getAnnotations).orElse(null));
SLAVE_DEBUG_PORT > 0 }
? " -Xdebug -Xrunjdwp:transport=dt_socket,server=y,address="
+ (SLAVE_DEBUG_PORT + sz) @Override
: "", public void then(Step s) throws Throwable {
agentJar.getAbsolutePath())); CustomJenkinsRule r = new CustomJenkinsRule(getHome(), port);
r.apply(
new Statement() {
@Override
public void evaluate() throws Throwable {
port = r.getPort();
s.run(r);
}
},
description
).evaluate();
}
private static final class CustomJenkinsRule extends JenkinsRule {
CustomJenkinsRule(File home, int port) {
with(() -> home);
localPort = port;
}
int getPort() {
return localPort;
}
@Override
public ComputerLauncher createComputerLauncher(EnvVars env) throws URISyntaxException, IOException {
int sz = this.jenkins.getNodes().size();
return new SimpleCommandLauncher(
String.format(
"\"%s/bin/java\" %s -jar \"%s\"",
System.getProperty("java.home"),
SLAVE_DEBUG_PORT > 0
? " -Xdebug -Xrunjdwp:transport=dt_socket,server=y,address="
+ (SLAVE_DEBUG_PORT + sz)
: "",
agentJar.getAbsolutePath()));
}
} }
} }
} }

View File

@ -24,8 +24,8 @@
package jenkins.slaves.restarter; package jenkins.slaves.restarter;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assume.assumeFalse; import static org.junit.jupiter.api.Assumptions.assumeFalse;
import hudson.Functions; import hudson.Functions;
import hudson.model.Slave; import hudson.model.Slave;
@ -33,52 +33,51 @@ import hudson.slaves.DumbSlave;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level; import java.util.logging.Level;
import jenkins.security.MasterToSlaveCallable; import jenkins.security.MasterToSlaveCallable;
import org.junit.Rule; import org.junit.jupiter.api.Test;
import org.junit.Test; import org.junit.jupiter.api.extension.RegisterExtension;
import org.jvnet.hudson.test.InboundAgentRule;
import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsSessionRule; import org.jvnet.hudson.test.LogRecorder;
import org.jvnet.hudson.test.LoggerRule; import org.jvnet.hudson.test.junit.jupiter.InboundAgentExtension;
import org.jvnet.hudson.test.junit.jupiter.JenkinsSessionExtension;
public class JnlpSlaveRestarterInstallerTest { class JnlpSlaveRestarterInstallerTest {
@Rule @RegisterExtension
public JenkinsSessionRule rr = new JenkinsSessionRule(); private final JenkinsSessionExtension rr = new JenkinsSessionExtension();
@Rule @RegisterExtension
public InboundAgentRule inboundAgents = new InboundAgentRule(); private final InboundAgentExtension inboundAgents = new InboundAgentExtension();
@Rule private final LogRecorder logging = new LogRecorder().record(JnlpSlaveRestarterInstaller.class, Level.FINE).capture(10);
public LoggerRule logging = new LoggerRule().record(JnlpSlaveRestarterInstaller.class, Level.FINE).capture(10);
@Issue("JENKINS-19055") @Issue("JENKINS-19055")
@Test @Test
public void tcpReconnection() throws Throwable { void tcpReconnection() throws Throwable {
// TODO Enable when test is reliable on Windows agents of ci.jenkins.io // TODO Enable when test is reliable on Windows agents of ci.jenkins.io
// When builds switched from ACI containers to virtual machines, this test consistently failed // When builds switched from ACI containers to virtual machines, this test consistently failed
// When the test is run on local Windows computers, it passes // When the test is run on local Windows computers, it passes
// Disable the test on ci.jenkins.io and friends when running Windows // Disable the test on ci.jenkins.io and friends when running Windows
// Do not disable for Windows developers generally // Do not disable for Windows developers generally
assumeFalse("TODO: Test fails on Windows VM", Functions.isWindows() && System.getenv("CI") != null); assumeFalse(Functions.isWindows() && System.getenv("CI") != null, "TODO: Test fails on Windows VM");
reconnection(false); reconnection(false);
} }
@Issue("JENKINS-66446") @Issue("JENKINS-66446")
@Test @Test
public void webSocketReconnection() throws Throwable { void webSocketReconnection() throws Throwable {
// TODO Enable when test is reliable on Windows agents of ci.jenkins.io // TODO Enable when test is reliable on Windows agents of ci.jenkins.io
// When builds switched from ACI containers to virtual machines, this test consistently failed // When builds switched from ACI containers to virtual machines, this test consistently failed
// When the test is run on local Windows computers, it passes // When the test is run on local Windows computers, it passes
// Disable the test on ci.jenkins.io and friends when running Windows // Disable the test on ci.jenkins.io and friends when running Windows
// Do not disable for Windows developers generally // Do not disable for Windows developers generally
assumeFalse("TODO: Test fails on Windows VM", Functions.isWindows() && System.getenv("CI") != null); assumeFalse(Functions.isWindows() && System.getenv("CI") != null, "TODO: Test fails on Windows VM");
reconnection(true); reconnection(true);
} }
private void reconnection(boolean webSocket) throws Throwable { private void reconnection(boolean webSocket) throws Throwable {
AtomicBoolean canWork = new AtomicBoolean(); AtomicBoolean canWork = new AtomicBoolean();
rr.then(r -> { rr.then(r -> {
InboundAgentRule.Options.Builder builder = InboundAgentRule.Options.newBuilder().name("remote").secret(); InboundAgentExtension.Options.Builder builder = InboundAgentExtension.Options.newBuilder().name("remote");
if (webSocket) { if (webSocket) {
builder.webSocket(); builder.webSocket();
} }

View File

@ -1,21 +1,21 @@
package jenkins.triggers; package jenkins.triggers;
import static org.junit.Assert.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import hudson.model.FreeStyleProject; import hudson.model.FreeStyleProject;
import org.junit.Rule; import org.junit.jupiter.api.Test;
import org.junit.Test; import org.junit.jupiter.api.extension.RegisterExtension;
import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsSessionRule; import org.jvnet.hudson.test.junit.jupiter.JenkinsSessionExtension;
public class ReverseBuildTriggerAfterRestartTest { class ReverseBuildTriggerAfterRestartTest {
@Rule @RegisterExtension
public JenkinsSessionRule rule = new JenkinsSessionRule(); private final JenkinsSessionExtension rule = new JenkinsSessionExtension();
@Issue("JENKINS-67237") @Issue("JENKINS-67237")
@Test @Test
public void testExecutionOfReverseBuildTriggersAfterRestart() throws Throwable { void testExecutionOfReverseBuildTriggersAfterRestart() throws Throwable {
String nameOfUpstreamProject = "upstreamProject"; String nameOfUpstreamProject = "upstreamProject";
String nameOfDownstreamProject = "downstreamProject"; String nameOfDownstreamProject = "downstreamProject";

View File

@ -1,19 +1,21 @@
package jenkins.util; package jenkins.util;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.Rule; import org.junit.jupiter.api.Test;
import org.junit.Test; import org.junit.jupiter.api.extension.RegisterExtension;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.RealJenkinsRule; import org.jvnet.hudson.test.RealJenkinsRule;
import org.jvnet.hudson.test.junit.jupiter.RealJenkinsExtension;
public class SetContextClassLoaderTest { class SetContextClassLoaderTest {
@Rule public RealJenkinsRule rr = new RealJenkinsRule(); @RegisterExtension
private final RealJenkinsExtension rr = new RealJenkinsExtension();
@Test @Test
public void positive() throws Throwable { void positive() throws Throwable {
rr.then(SetContextClassLoaderTest::_positive); rr.then(SetContextClassLoaderTest::_positive);
} }
@ -24,7 +26,7 @@ public class SetContextClassLoaderTest {
} }
@Test @Test
public void negative() throws Throwable { void negative() throws Throwable {
rr.then(SetContextClassLoaderTest::_negative); rr.then(SetContextClassLoaderTest::_negative);
} }

View File

@ -29,8 +29,8 @@ import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assume.assumeTrue; import static org.junit.jupiter.api.Assumptions.assumeTrue;
import jakarta.servlet.ServletContextEvent; import jakarta.servlet.ServletContextEvent;
import java.time.Duration; import java.time.Duration;
@ -51,7 +51,9 @@ import org.jvnet.hudson.test.junit.jupiter.WithJenkins;
*/ */
@WithJenkins @WithJenkins
class SystemPropertiesTest { class SystemPropertiesTest {
private final LogRecorder logging = new LogRecorder().record(SystemProperties.class, Level.WARNING); private final LogRecorder logging = new LogRecorder().record(SystemProperties.class, Level.WARNING);
private JenkinsRule j; private JenkinsRule j;
@BeforeEach @BeforeEach
@ -105,7 +107,7 @@ class SystemPropertiesTest {
} }
@Test @Test
public void duration() { void duration() {
System.setProperty("foo.bar", "1s"); System.setProperty("foo.bar", "1s");
assertEquals(Duration.ofSeconds(1), SystemProperties.getDuration("foo.bar")); assertEquals(Duration.ofSeconds(1), SystemProperties.getDuration("foo.bar"));
System.setProperty("foo.bar", "2m"); System.setProperty("foo.bar", "2m");
@ -130,7 +132,7 @@ class SystemPropertiesTest {
} }
@Test @Test
public void invalid() { void invalid() {
logging.capture(10); logging.capture(10);
System.setProperty("abc.def", "invalid"); System.setProperty("abc.def", "invalid");
assertThat(SystemProperties.getDuration("abc.def"), Matchers.nullValue()); assertThat(SystemProperties.getDuration("abc.def"), Matchers.nullValue());

View File

@ -24,13 +24,16 @@
package lib.form; package lib.form;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import hudson.model.RootAction;
import net.sf.json.JSONObject; import net.sf.json.JSONObject;
import org.htmlunit.html.HtmlPage; import org.htmlunit.html.HtmlPage;
import org.junit.Rule; import org.junit.jupiter.api.BeforeEach;
import org.junit.Test; import org.junit.jupiter.api.Test;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.TestExtension;
import org.jvnet.hudson.test.junit.jupiter.WithJenkins;
import org.kohsuke.stapler.HttpResponse; import org.kohsuke.stapler.HttpResponse;
import org.kohsuke.stapler.HttpResponses; import org.kohsuke.stapler.HttpResponses;
import org.kohsuke.stapler.StaplerRequest2; import org.kohsuke.stapler.StaplerRequest2;
@ -38,17 +41,25 @@ import org.kohsuke.stapler.StaplerRequest2;
/** /**
* Tests the handling of @nameRef in the form tree. * Tests the handling of @nameRef in the form tree.
*/ */
public class NameRefTest { @WithJenkins
class NameRefTest {
@Rule public JenkinsRule r = new JenkinsRuleWithJelly(); private JenkinsRule r;
@Test public void test() throws Exception { @BeforeEach
void setUp(JenkinsRule rule) {
r = rule;
}
@Test
void test() throws Exception {
r.jenkins.setCrumbIssuer(null); r.jenkins.setCrumbIssuer(null);
HtmlPage p = r.createWebClient().goTo("self/test1"); HtmlPage p = r.createWebClient().goTo("self/test1");
r.submit(p.getFormByName("config")); r.submit(p.getFormByName("config"));
} }
public static class JenkinsRuleWithJelly extends JenkinsRule { @TestExtension
public static class RootActionImpl implements RootAction {
public HttpResponse doSubmitTest1(StaplerRequest2 req) throws Exception { public HttpResponse doSubmitTest1(StaplerRequest2 req) throws Exception {
JSONObject f = req.getSubmittedForm(); JSONObject f = req.getSubmittedForm();
@ -58,6 +69,20 @@ public class NameRefTest {
return HttpResponses.ok(); return HttpResponses.ok();
} }
@Override
public String getIconFileName() {
return null;
}
@Override
public String getDisplayName() {
return null;
}
@Override
public String getUrlName() {
return "self";
}
} }
} }

View File

@ -56,7 +56,7 @@ import org.jvnet.hudson.test.junit.jupiter.WithJenkins;
class RenderOnDemandTest { class RenderOnDemandTest {
private JenkinsRule j; private JenkinsRule j;
private LogRecorder logging = new LogRecorder().record(RenderOnDemandClosure.class, Level.FINE); private final LogRecorder logging = new LogRecorder().record(RenderOnDemandClosure.class, Level.FINE);
@BeforeEach @BeforeEach
void setUp(JenkinsRule rule) { void setUp(JenkinsRule rule) {
@ -83,7 +83,7 @@ class RenderOnDemandTest {
@Disabled("just informational") @Disabled("just informational")
@Issue("JENKINS-16341") @Issue("JENKINS-16341")
@Test @Test
public void testMemoryConsumption() throws Exception { void testMemoryConsumption() throws Exception {
var wc = j.createWebClient(); var wc = j.createWebClient();
callTestBehaviour(wc); // prime caches callTestBehaviour(wc); // prime caches
int total = 0; int total = 0;

View File

@ -4,22 +4,23 @@ import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.not;
import org.junit.Rule;
import org.junit.Test;
import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.RealJenkinsRule; import org.jvnet.hudson.test.junit.jupiter.RealJenkinsExtension;
public class SymbolJenkinsTest { class SymbolJenkinsTest {
@Rule
public RealJenkinsRule rjr = new RealJenkinsRule() @RegisterExtension
private final RealJenkinsExtension rjr = new RealJenkinsExtension()
.addPlugins("plugins/design-library.jpi", "plugins/prism-api.jpi", "plugins/bootstrap5-api.jpi"); .addPlugins("plugins/design-library.jpi", "plugins/prism-api.jpi", "plugins/bootstrap5-api.jpi");
@Test @Test
@Issue("JENKINS-73243") @Issue("JENKINS-73243")
@DisplayName("When resolving a symbol where the tooltip contains '$' no error is thrown") @DisplayName("When resolving a symbol where the tooltip contains '$' no error is thrown")
public void dollarInToolTipSucceeds() throws Throwable { void dollarInToolTipSucceeds() throws Throwable {
rjr.then(SymbolJenkinsTest::_dollarInTooltipSucceeds); rjr.then(SymbolJenkinsTest::_dollarInTooltipSucceeds);
} }
@ -34,7 +35,7 @@ public class SymbolJenkinsTest {
@Test @Test
@DisplayName("When resolving a symbol from a missing plugin, the placeholder is generated instead") @DisplayName("When resolving a symbol from a missing plugin, the placeholder is generated instead")
public void missingSymbolFromPluginDefaultsToPlaceholder() throws Throwable { void missingSymbolFromPluginDefaultsToPlaceholder() throws Throwable {
rjr.then(SymbolJenkinsTest::_missingSymbolFromPluginDefaultsToPlaceholder); rjr.then(SymbolJenkinsTest::_missingSymbolFromPluginDefaultsToPlaceholder);
} }
@ -49,7 +50,7 @@ public class SymbolJenkinsTest {
@Test @Test
@DisplayName("Resolving a valid symbol from an installed plugin does not return the placeholder") @DisplayName("Resolving a valid symbol from an installed plugin does not return the placeholder")
public void resolvingSymbolFromPlugin() throws Throwable { void resolvingSymbolFromPlugin() throws Throwable {
rjr.then(SymbolJenkinsTest::_resolvingSymbolFromPlugin); rjr.then(SymbolJenkinsTest::_resolvingSymbolFromPlugin);
} }

View File

@ -5,42 +5,46 @@ import static org.hamcrest.CoreMatchers.endsWith;
import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.startsWith; import static org.hamcrest.CoreMatchers.startsWith;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import hudson.ExtensionList; import hudson.ExtensionList;
import hudson.model.InvisibleAction; import hudson.model.InvisibleAction;
import hudson.model.RootAction; import hudson.model.RootAction;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.htmlunit.Page; import org.htmlunit.Page;
import org.htmlunit.ScriptException; import org.htmlunit.ScriptException;
import org.htmlunit.html.HtmlPage; import org.htmlunit.html.HtmlPage;
import org.junit.Rule; import org.junit.jupiter.api.BeforeEach;
import org.junit.Test; import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith; import org.junit.jupiter.params.Parameter;
import org.junit.runners.Parameterized; import org.junit.jupiter.params.ParameterizedClass;
import org.junit.jupiter.params.provider.ValueSource;
import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.TestExtension; import org.jvnet.hudson.test.TestExtension;
import org.jvnet.hudson.test.junit.jupiter.WithJenkins;
import org.kohsuke.stapler.bind.JavaScriptMethod; import org.kohsuke.stapler.bind.JavaScriptMethod;
import org.kohsuke.stapler.bind.WithWellKnownURL; import org.kohsuke.stapler.bind.WithWellKnownURL;
@RunWith(Parameterized.class) @ParameterizedClass
public class BindTest { @ValueSource(strings = { "/jenkins", "" })
@Rule @WithJenkins
public JenkinsRule j = new JenkinsRule(); class BindTest {
@Parameterized.Parameters @Parameter
public static List<String> contexts() { private String contextPath;
return Arrays.asList("/jenkins", "");
} private JenkinsRule j;
@BeforeEach
void setUp(JenkinsRule rule) throws Throwable {
j = rule;
public BindTest(String contextPath) {
j.contextPath = contextPath; j.contextPath = contextPath;
j.restart();
} }
@Test @Test
public void bindNormal() throws Exception { void bindNormal() throws Exception {
final RootActionImpl root = ExtensionList.lookupSingleton(RootActionImpl.class); final RootActionImpl root = ExtensionList.lookupSingleton(RootActionImpl.class);
try (JenkinsRule.WebClient wc = j.createWebClient()) { try (JenkinsRule.WebClient wc = j.createWebClient()) {
final HtmlPage htmlPage = wc.goTo(root.getUrlName()); final HtmlPage htmlPage = wc.goTo(root.getUrlName());
@ -61,7 +65,7 @@ public class BindTest {
} }
@Test @Test
public void bindWithWellKnownURL() throws Exception { void bindWithWellKnownURL() throws Exception {
final RootActionWithWellKnownURL root = ExtensionList.lookupSingleton(RootActionWithWellKnownURL.class); final RootActionWithWellKnownURL root = ExtensionList.lookupSingleton(RootActionWithWellKnownURL.class);
try (JenkinsRule.WebClient wc = j.createWebClient()) { try (JenkinsRule.WebClient wc = j.createWebClient()) {
final HtmlPage htmlPage = wc.goTo(root.getUrlName()); final HtmlPage htmlPage = wc.goTo(root.getUrlName());
@ -80,7 +84,7 @@ public class BindTest {
} }
@Test @Test
public void bindWithWellKnownURLWithQuotes() throws Exception { void bindWithWellKnownURLWithQuotes() throws Exception {
final RootActionWithWellKnownURLWithQuotes root = ExtensionList.lookupSingleton(RootActionWithWellKnownURLWithQuotes.class); final RootActionWithWellKnownURLWithQuotes root = ExtensionList.lookupSingleton(RootActionWithWellKnownURLWithQuotes.class);
try (JenkinsRule.WebClient wc = j.createWebClient()) { try (JenkinsRule.WebClient wc = j.createWebClient()) {
final HtmlPage htmlPage = wc.goTo(root.getUrlName()); final HtmlPage htmlPage = wc.goTo(root.getUrlName());
@ -99,7 +103,7 @@ public class BindTest {
} }
@Test @Test
public void bindNull() throws Exception { void bindNull() throws Exception {
final RootActionImpl root = ExtensionList.lookupSingleton(RootActionImpl.class); final RootActionImpl root = ExtensionList.lookupSingleton(RootActionImpl.class);
try (JenkinsRule.WebClient wc = j.createWebClient()) { try (JenkinsRule.WebClient wc = j.createWebClient()) {
final ScriptException exception = assertThrows(ScriptException.class, () -> wc.goTo(root.getUrlName() + "/null")); final ScriptException exception = assertThrows(ScriptException.class, () -> wc.goTo(root.getUrlName() + "/null"));
@ -118,7 +122,7 @@ public class BindTest {
} }
@Test @Test
public void bindUnsafe() throws Exception { void bindUnsafe() throws Exception {
final RootActionImpl root = ExtensionList.lookupSingleton(RootActionImpl.class); final RootActionImpl root = ExtensionList.lookupSingleton(RootActionImpl.class);
try (JenkinsRule.WebClient wc = j.createWebClient()) { try (JenkinsRule.WebClient wc = j.createWebClient()) {
final HtmlPage htmlPage = wc.goTo(root.getUrlName() + "/unsafe-var"); final HtmlPage htmlPage = wc.goTo(root.getUrlName() + "/unsafe-var");
@ -137,7 +141,7 @@ public class BindTest {
} }
@Test @Test
public void bindInlineNull() throws Exception { void bindInlineNull() throws Exception {
final RootActionImpl root = ExtensionList.lookupSingleton(RootActionImpl.class); final RootActionImpl root = ExtensionList.lookupSingleton(RootActionImpl.class);
try (JenkinsRule.WebClient wc = j.createWebClient()) { try (JenkinsRule.WebClient wc = j.createWebClient()) {
final HtmlPage htmlPage = wc.goTo(root.getUrlName() + "/inline-null"); final HtmlPage htmlPage = wc.goTo(root.getUrlName() + "/inline-null");