Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion test/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,7 @@ THE SOFTWARE.
<artifactId>maven-surefire-plugin</artifactId>
<!-- Version specified in grandparent POM -->
<configuration>
<groups>org.jvnet.hudson.test.SmokeTest</groups>
<groups>SmokeTest</groups>
</configuration>
</plugin>
</plugins>
Expand Down
194 changes: 123 additions & 71 deletions test/src/test/java/hudson/ClassicPluginStrategyTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,82 +25,67 @@

package hudson;

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;

import hudson.model.Hudson;
import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.Collection;
import java.util.Enumeration;
import java.util.LinkedHashSet;
import java.util.Set;
import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.jupiter.api.Tag;
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.JenkinsRecipe;
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;

/**
* @author Alan Harder
*/
@Category(SmokeTest.class)
public class ClassicPluginStrategyTest {
@Tag("SmokeTest")
class ClassicPluginStrategyTest {

@Rule
public JenkinsRule j = new JenkinsRule() {
@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);
}
};
@RegisterExtension
private final JenkinsSessionExtension session = new CustomPluginManagerExtension();

/**
* Test finding resources via DependencyClassLoader.
*/
@LocalData
@Test
public void testDependencyClassLoader() throws Exception {
// Test data has: foo3 depends on foo2,foo1; foo2 depends on foo1
// (thus findResources from foo3 can find foo1 resources via 2 dependency paths)
PluginWrapper p = j.jenkins.getPluginManager().getPlugin("foo3");
String res;

// In the current impl, the dependencies are the parent ClassLoader so resources
// are found there before checking the plugin itself. Adjust the expected results
// below if this is ever changed to check the plugin first.
Enumeration<URL> en = p.classLoader.getResources("test-resource");
for (int i = 0; en.hasMoreElements(); i++) {
res = en.nextElement().toString();
if (i < 2)
assertTrue("In current impl, " + res + "should be foo1 or foo2",
res.contains("/foo1/") || res.contains("/foo2/"));
else
assertTrue("In current impl, " + res + "should be foo3", res.contains("/foo3/"));
}
res = p.classLoader.getResource("test-resource").toString();
assertTrue("In current impl, " + res + " should be foo1 or foo2",
res.contains("/foo1/") || res.contains("/foo2/"));
void testDependencyClassLoader() throws Throwable {
session.then(j -> {
// Test data has: foo3 depends on foo2,foo1; foo2 depends on foo1
// (thus findResources from foo3 can find foo1 resources via 2 dependency paths)
PluginWrapper p = j.jenkins.getPluginManager().getPlugin("foo3");
String res;

// In the current impl, the dependencies are the parent ClassLoader so resources
// are found there before checking the plugin itself. Adjust the expected results
// below if this is ever changed to check the plugin first.
Enumeration<URL> en = p.classLoader.getResources("test-resource");
for (int i = 0; en.hasMoreElements(); i++) {
res = en.nextElement().toString();
if (i < 2)
assertTrue(res.contains("/foo1/") || res.contains("/foo2/"),
"In current impl, " + res + "should be foo1 or foo2");
else
assertTrue(res.contains("/foo3/"), "In current impl, " + res + "should be foo3");
}
res = p.classLoader.getResource("test-resource").toString();
assertTrue(res.contains("/foo1/") || res.contains("/foo2/"),
"In current impl, " + res + " should be foo1 or foo2");
});
}

/**
Expand All @@ -110,17 +95,19 @@ public void testDependencyClassLoader() throws Exception {
@LocalData
@Issue("JENKINS-18654")
@Test
public void testDisabledDependencyClassLoader() throws Exception {
PluginWrapper p = j.jenkins.getPluginManager().getPlugin("foo4");

Enumeration<URL> en = p.classLoader.getResources("test-resource");
for (int i = 0; en.hasMoreElements(); i++) {
String res = en.nextElement().toString();
if (i == 0)
assertTrue("expected foo4, found " + res, res.contains("/foo4/"));
else
fail("disabled dependency should not be included");
}
void testDisabledDependencyClassLoader() throws Throwable {
session.then(j -> {
PluginWrapper p = j.jenkins.getPluginManager().getPlugin("foo4");

Enumeration<URL> en = p.classLoader.getResources("test-resource");
for (int i = 0; en.hasMoreElements(); i++) {
String res = en.nextElement().toString();
if (i == 0)
assertTrue(res.contains("/foo4/"), "expected foo4, found " + res);
else
fail("disabled dependency should not be included");
}
});
}

/**
Expand All @@ -130,12 +117,77 @@ public void testDisabledDependencyClassLoader() throws Exception {
@LocalData
@Issue("JENKINS-27289")
@Test
public void testMaskResourceClassLoader() throws Exception {
PluginWrapper pw = j.jenkins.getPluginManager().getPlugin("foo1");
Class<?> clazz = pw.classLoader.loadClass("org.apache.http.impl.io.SocketInputBuffer");
ClassLoader cl = clazz.getClassLoader();
URL url = cl.getResource("org/apache/http/impl/io/SocketInputBuffer.class");
assertNotNull(url);
assertTrue("expected to find the class from foo1 plugin", url.toString().contains("plugins/foo1"));
void testMaskResourceClassLoader() throws Throwable {
session.then(j -> {
PluginWrapper pw = j.jenkins.getPluginManager().getPlugin("foo1");
Class<?> clazz = pw.classLoader.loadClass("org.apache.http.impl.io.SocketInputBuffer");
ClassLoader cl = clazz.getClassLoader();
URL url = cl.getResource("org/apache/http/impl/io/SocketInputBuffer.class");
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);
}
}
}
}
44 changes: 29 additions & 15 deletions test/src/test/java/hudson/CustomPluginManagerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,26 +29,29 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

import jakarta.servlet.ServletContext;
import java.io.File;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import jenkins.model.Jenkins;
import org.junit.Rule;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRecipe;
import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.junit.jupiter.JenkinsSessionExtension;
import org.jvnet.hudson.test.recipes.WithPlugin;

/**
* Tests for the use of a custom plugin manager in custom wars.
*/
public class CustomPluginManagerTest {
@Rule public final JenkinsRule r = new JenkinsRule();
class CustomPluginManagerTest {

@RegisterExtension
private final JenkinsSessionExtension session = new JenkinsSessionExtension();

// TODO: Move to jenkins-test-harness
@JenkinsRecipe(WithCustomLocalPluginManager.RuleRunnerImpl.class)
Expand All @@ -65,7 +68,6 @@ public void setup(JenkinsRule jenkinsRule, WithCustomLocalPluginManager recipe)
jenkinsRule.useLocalPluginManager = true;
oldValue = System.getProperty(PluginManager.CUSTOM_PLUGIN_MANAGER);
System.setProperty(PluginManager.CUSTOM_PLUGIN_MANAGER, recipe.value().getName());

}

@Override
Expand All @@ -79,9 +81,11 @@ public void tearDown(JenkinsRule jenkinsRule, WithCustomLocalPluginManager recip
}
}

private void check(Class<? extends CustomPluginManager> klass) {
assertTrue("Correct plugin manager installed", klass.isAssignableFrom(r.getPluginManager().getClass()));
assertNotNull("Plugin 'htmlpublisher' installed", r.jenkins.getPlugin("htmlpublisher"));
private void check(Class<? extends CustomPluginManager> klass) throws Throwable {
session.then(r -> {
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.
Expand All @@ -91,11 +95,13 @@ interface CustomPluginManager {
@Issue("JENKINS-34681")
@WithPlugin("htmlpublisher.jpi")
@WithCustomLocalPluginManager(CustomPluginManager1.class)
@Test public void customPluginManager1() {
@Test
void customPluginManager1() throws Throwable {
check(CustomPluginManager1.class);
}

public static class CustomPluginManager1 extends LocalPluginManager implements CustomPluginManager {
@SuppressWarnings("checkstyle:redundantmodifier")
public CustomPluginManager1(Jenkins jenkins) {
super(jenkins);
}
Expand All @@ -104,11 +110,13 @@ public CustomPluginManager1(Jenkins jenkins) {
@Issue("JENKINS-34681")
@WithPlugin("htmlpublisher.jpi")
@WithCustomLocalPluginManager(CustomPluginManager2.class)
@Test public void customPluginManager2() {
@Test
void customPluginManager2() throws Throwable {
check(CustomPluginManager2.class);
}

public static class CustomPluginManager2 extends LocalPluginManager implements CustomPluginManager {
@SuppressWarnings("checkstyle:redundantmodifier")
public CustomPluginManager2(ServletContext ctx, File root) {
super(ctx, root);
}
Expand All @@ -117,11 +125,13 @@ public CustomPluginManager2(ServletContext ctx, File root) {
@Issue("JENKINS-34681")
@WithPlugin("htmlpublisher.jpi")
@WithCustomLocalPluginManager(CustomPluginManager3.class)
@Test public void customPluginManager3() {
@Test
void customPluginManager3() throws Throwable {
check(CustomPluginManager3.class);
}

public static class CustomPluginManager3 extends LocalPluginManager implements CustomPluginManager {
@SuppressWarnings("checkstyle:redundantmodifier")
public CustomPluginManager3(File root) {
super(root);
}
Expand All @@ -130,11 +140,15 @@ public CustomPluginManager3(File root) {
@Issue("JENKINS-34681")
@WithPlugin("htmlpublisher.jpi")
@WithCustomLocalPluginManager(BadCustomPluginManager.class)
@Test public void badCustomPluginManager() {
assertThat("Custom plugin manager not installed", r.getPluginManager(), not(instanceOf(CustomPluginManager.class)));
@Test
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 {
@SuppressWarnings("checkstyle:redundantmodifier")
public BadCustomPluginManager(File root, ServletContext ctx) {
super(ctx, root);
}
Expand Down
Loading
Loading