diff --git a/core/src/main/java/hudson/PluginWrapper.java b/core/src/main/java/hudson/PluginWrapper.java index c0542c9a58..5932f0777e 100644 --- a/core/src/main/java/hudson/PluginWrapper.java +++ b/core/src/main/java/hudson/PluginWrapper.java @@ -576,7 +576,7 @@ public class PluginWrapper implements Comparable, ModelObject { if (dependency == null) { PluginWrapper failedDependency = NOTICE.getPlugin(d.shortName); if (failedDependency != null) { - dependencyErrors.add(Messages.PluginWrapper_failed_to_load_dependency(failedDependency.getLongName(), d.version)); + dependencyErrors.add(Messages.PluginWrapper_failed_to_load_dependency(failedDependency.getLongName(), failedDependency.getVersion())); break; } else { dependencyErrors.add(Messages.PluginWrapper_missing(d.shortName, d.version)); diff --git a/core/src/test/java/hudson/PluginWrapperTest.java b/core/src/test/java/hudson/PluginWrapperTest.java index f9ffe3dd4e..56504cd0bd 100644 --- a/core/src/test/java/hudson/PluginWrapperTest.java +++ b/core/src/test/java/hudson/PluginWrapperTest.java @@ -1,11 +1,34 @@ package hudson; -import org.junit.Test; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.jar.Attributes; +import java.util.jar.Manifest; +import jenkins.model.Jenkins; +import org.junit.Before; +import org.junit.Test; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class PluginWrapperTest { + @Before + public void before() throws Exception { + Jenkins.VERSION = "2.0"; // Some value needed - tests will overwrite if necessary + } + @Test public void dependencyTest() { String version = "plugin:0.0.2"; @@ -23,4 +46,138 @@ public class PluginWrapperTest { assertEquals("0.0.2", dependency.version); assertEquals(true, dependency.optional); } -} \ No newline at end of file + + @Test + public void jenkinsCoreTooOld() throws Exception { + PluginWrapper pw = pluginWrapper("fake").requiredCoreVersion("3.0").buildLoaded(); + try { + pw.resolvePluginDependencies(); + fail(); + } catch (IOException ex) { + assertContians(ex, "fake v42 failed to load", "update Jenkins from v2.0 to v3.0"); + } + } + + @Test + public void dependencyNotInstalled() throws Exception { + PluginWrapper pw = pluginWrapper("dependee").deps("dependency:42").buildLoaded(); + try { + pw.resolvePluginDependencies(); + fail(); + } catch (IOException ex) { + assertContians(ex, "dependee v42 failed to load", "dependency v42 is missing. To fix, install v42 or later"); + } + } + + @Test + public void dependencyOutdated() throws Exception { + pluginWrapper("dependency").version("3").buildLoaded(); + PluginWrapper pw = pluginWrapper("dependee").deps("dependency:5").buildLoaded(); + try { + pw.resolvePluginDependencies(); + fail(); + } catch (IOException ex) { + assertContians(ex, "dependee v42 failed to load", "dependency v3 is older than required. To fix, install v5 or later"); + } + } + + @Test + public void dependencyFailedToLoad() throws Exception { + pluginWrapper("dependency").version("5").buildFailed(); + PluginWrapper pw = pluginWrapper("dependee").deps("dependency:3").buildLoaded(); + try { + pw.resolvePluginDependencies(); + fail(); + } catch (IOException ex) { + assertContians(ex, "dependee v42 failed to load", "dependency v5 failed to load. Fix this plugin first"); + } + } + + private void assertContians(Throwable ex, String... patterns) { + String msg = ex.getMessage(); + for (String pattern : patterns) { + assertThat(msg, containsString(pattern)); + } + } + + private PluginWrapperBuilder pluginWrapper(String name) { + return new PluginWrapperBuilder(name); + } + + // per test + private final HashMap plugins = new HashMap<>(); + private final PluginManager pm = mock(PluginManager.class); + { + when(pm.getPlugin(any(String.class))).thenAnswer(new Answer() { + @Override public PluginWrapper answer(InvocationOnMock invocation) throws Throwable { + return plugins.get(invocation.getArguments()[0]); + } + }); + } + private final class PluginWrapperBuilder { + private String name; + private String version = "42"; + private String requiredCoreVersion = "1.0"; + private List deps = new ArrayList<>(); + private List optDeps = new ArrayList<>(); + + private PluginWrapperBuilder(String name) { + this.name = name; + } + + public PluginWrapperBuilder version(String version) { + this.version = version; + return this; + } + + public PluginWrapperBuilder requiredCoreVersion(String requiredCoreVersion) { + this.requiredCoreVersion = requiredCoreVersion; + return this; + } + + public PluginWrapperBuilder deps(String... deps) { + for (String dep: deps) { + this.deps.add(new PluginWrapper.Dependency(dep)); + } + return this; + } + + public PluginWrapperBuilder optDeps(String... optDeps) { + for (String dep: optDeps) { + this.optDeps.add(new PluginWrapper.Dependency(dep)); + } + return this; + } + + private PluginWrapper buildLoaded() { + PluginWrapper pw = build(); + plugins.put(name, pw); + return pw; + } + + private PluginWrapper buildFailed() { + PluginWrapper pw = build(); + PluginWrapper.NOTICE.addPlugin(pw); + return pw; + } + + private PluginWrapper build() { + Manifest manifest = mock(Manifest.class); + Attributes attributes = new Attributes(); + attributes.put(new Attributes.Name("Short-Name"), name); + attributes.put(new Attributes.Name("Jenkins-Version"), requiredCoreVersion); + attributes.put(new Attributes.Name("Plugin-Version"), version); + when(manifest.getMainAttributes()).thenReturn(attributes); + return new PluginWrapper( + pm, + new File("/tmp/" + name + ".jpi"), + manifest, + null, + null, + new File("/tmp/" + name + ".jpi.disabled"), + deps, + optDeps + ); + } + } +}