]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-3516 Check minimal sonar version required by installed plugins
authorDavid Gageot <david@gageot.net>
Mon, 18 Jun 2012 09:47:54 +0000 (11:47 +0200)
committerDavid Gageot <david@gageot.net>
Mon, 18 Jun 2012 10:39:50 +0000 (12:39 +0200)
Plugin manifest declares the minimal required version of sonar.
This version is verified at server startup. It prevents plugins from
failing for API incompatibility reasons.
Startup fails with a meaningful message.

sonar-core/src/main/java/org/sonar/core/plugins/DefaultPluginMetadata.java
sonar-core/src/main/java/org/sonar/core/plugins/PluginInstaller.java
sonar-core/src/test/java/org/sonar/core/plugins/DefaultPluginMetadataTest.java
sonar-core/src/test/java/org/sonar/core/plugins/PluginInstallerTest.java
sonar-core/src/test/resources/org/sonar/core/plugins/PluginInstallerTest/shouldCopyRuleExtensionsOnServerSide/checkstyle-extension.xml [deleted file]
sonar-core/src/test/resources/org/sonar/core/plugins/checkstyle-extension.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/plugins/sonar-switch-off-violations-plugin-1.1.jar [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/plugins/PluginDeployer.java
sonar-server/src/test/java/org/sonar/server/plugins/PluginDeployerTest.java
sonar-server/src/test/resources/org/sonar/server/plugins/PluginDeployerTest/should_fail_on_plugin_depending_on_more_recent_sonar/extensions/plugins/sonar-switch-off-violations-plugin-1.1.jar [new file with mode: 0644]

index f9f65033cd81d69b2a044bb4acfc4e99da5b8968..22ff29fadb955d42dd7fb4dd83f372addb3c4b7d 100644 (file)
  */
 package org.sonar.core.plugins;
 
+import com.google.common.base.CharMatcher;
+import com.google.common.base.Splitter;
+import com.google.common.collect.ComparisonChain;
+import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 import org.apache.commons.lang.StringUtils;
 import org.apache.commons.lang.builder.ToStringBuilder;
@@ -35,6 +39,7 @@ public class DefaultPluginMetadata implements PluginMetadata, Comparable<PluginM
   private String[] pathsToInternalDeps = new String[0];
   private String key;
   private String version;
+  private String sonarVersion;
   private String name;
   private String mainClass;
   private String description;
@@ -166,6 +171,46 @@ public class DefaultPluginMetadata implements PluginMetadata, Comparable<PluginM
     return this;
   }
 
+  public String getSonarVersion() {
+    return sonarVersion;
+  }
+
+  public DefaultPluginMetadata setSonarVersion(String sonarVersion) {
+    this.sonarVersion = sonarVersion;
+    return this;
+  }
+
+  /**
+   * Find out if this plugin is compatible with a given version of Sonar.
+   * The version of sonar must be greater than or equal to the minimal version
+   * needed by the plugin.
+   *
+   * @param sonarVersion
+   * @return <code>true</code> if the plugin is compatible
+   */
+  public boolean isCompatibleWith(String sonarVersion) {
+    if (null == this.sonarVersion) {
+      return true; // Plugins without sonar version are so old, they are compatible with a version containing this code
+    }
+    if (null == sonarVersion) {
+      return true;
+    }
+
+    return ComparisonChain.start()
+        .compare(part(sonarVersion, 0), part(this.sonarVersion, 0))
+        .compare(part(sonarVersion, 1), part(this.sonarVersion, 1))
+        .compare(part(sonarVersion, 2), part(this.sonarVersion, 2))
+        .result() >= 0;
+  }
+
+  private static int part(String version, int index) {
+    Iterable<String> parts = Splitter.on('.').split(version);
+    String part = Iterables.get(parts, index, "0");
+    String onlyDigits = CharMatcher.DIGIT.retainFrom(part);
+
+    return Integer.parseInt(onlyDigits);
+  }
+
   public String getHomepage() {
     return homepage;
   }
index 5566a0e0ae09a2e49958b86dbd9379ee0e051e4a..d0289f4a82ffb8a6d0415e8a5311aa72fe6d01d0 100644 (file)
@@ -116,6 +116,7 @@ public class PluginInstaller {
       metadata.setOrganizationUrl(manifest.getOrganizationUrl());
       metadata.setMainClass(manifest.getMainClass());
       metadata.setVersion(manifest.getVersion());
+      metadata.setSonarVersion(manifest.getSonarVersion());
       metadata.setHomepage(manifest.getHomepage());
       metadata.setPathsToInternalDeps(manifest.getDependencies());
       metadata.setUseChildFirstClassLoader(manifest.isUseChildFirstClassLoader());
index 27cf28eea34e66e4f9178ffb9da5e5f3144111aa..02053827323b52f038142f357b15fdf9a010478b 100644 (file)
  */
 package org.sonar.core.plugins;
 
-import org.hamcrest.core.Is;
 import org.junit.Test;
 import org.sonar.api.platform.PluginMetadata;
 
 import java.io.File;
 import java.util.Arrays;
+import java.util.List;
 
-import static org.hamcrest.CoreMatchers.*;
-import static org.junit.Assert.assertThat;
+import static com.google.common.collect.Ordering.natural;
+import static org.fest.assertions.Assertions.assertThat;
 
 public class DefaultPluginMetadataTest {
 
@@ -41,19 +41,25 @@ public class DefaultPluginMetadataTest {
         .setMainClass("org.Main")
         .setOrganization("SonarSource")
         .setOrganizationUrl("http://sonarsource.org")
-        .setVersion("1.1");
-
-    assertThat(metadata.getKey(), Is.is("checkstyle"));
-    assertThat(metadata.getLicense(), Is.is("LGPL"));
-    assertThat(metadata.getDescription(), Is.is("description"));
-    assertThat(metadata.getHomepage(), Is.is("http://home"));
-    assertThat(metadata.getMainClass(), Is.is("org.Main"));
-    assertThat(metadata.getOrganization(), Is.is("SonarSource"));
-    assertThat(metadata.getOrganizationUrl(), Is.is("http://sonarsource.org"));
-    assertThat(metadata.getVersion(), Is.is("1.1"));
-    assertThat(metadata.getBasePlugin(), nullValue());
-    assertThat(metadata.getFile(), not(nullValue()));
-    assertThat(metadata.getDeployedFiles().size(), is(0));
+        .setVersion("1.1")
+        .setSonarVersion("3.0")
+        .setUseChildFirstClassLoader(true)
+        .setCore(false);
+
+    assertThat(metadata.getKey()).isEqualTo("checkstyle");
+    assertThat(metadata.getLicense()).isEqualTo("LGPL");
+    assertThat(metadata.getDescription()).isEqualTo("description");
+    assertThat(metadata.getHomepage()).isEqualTo("http://home");
+    assertThat(metadata.getMainClass()).isEqualTo("org.Main");
+    assertThat(metadata.getOrganization()).isEqualTo("SonarSource");
+    assertThat(metadata.getOrganizationUrl()).isEqualTo("http://sonarsource.org");
+    assertThat(metadata.getVersion()).isEqualTo("1.1");
+    assertThat(metadata.getSonarVersion()).isEqualTo("3.0");
+    assertThat(metadata.isUseChildFirstClassLoader()).isTrue();
+    assertThat(metadata.isCore()).isFalse();
+    assertThat(metadata.getBasePlugin()).isNull();
+    assertThat(metadata.getFile()).isNotNull();
+    assertThat(metadata.getDeployedFiles()).isEmpty();
   }
 
   @Test
@@ -61,16 +67,16 @@ public class DefaultPluginMetadataTest {
     DefaultPluginMetadata metadata = DefaultPluginMetadata.create(new File("sonar-checkstyle-plugin.jar"))
         .addDeployedFile(new File("foo.jar"))
         .addDeployedFile(new File("bar.jar"));
-    assertThat(metadata.getDeployedFiles().size(), is(2));
+
+    assertThat(metadata.getDeployedFiles()).hasSize(2);
   }
 
   @Test
   public void testInternalPathToDependencies() {
     DefaultPluginMetadata metadata = DefaultPluginMetadata.create(new File("sonar-checkstyle-plugin.jar"))
-        .setPathsToInternalDeps(new String[]{"META-INF/lib/commons-lang.jar", "META-INF/lib/commons-io.jar"});
-    assertThat(metadata.getPathsToInternalDeps().length, is(2));
-    assertThat(metadata.getPathsToInternalDeps()[0], is("META-INF/lib/commons-lang.jar"));
-    assertThat(metadata.getPathsToInternalDeps()[1], is("META-INF/lib/commons-io.jar"));
+        .setPathsToInternalDeps(new String[] {"META-INF/lib/commons-lang.jar", "META-INF/lib/commons-io.jar"});
+
+    assertThat(metadata.getPathsToInternalDeps()).containsOnly("META-INF/lib/commons-lang.jar", "META-INF/lib/commons-io.jar");
   }
 
   @Test
@@ -78,23 +84,49 @@ public class DefaultPluginMetadataTest {
     DefaultPluginMetadata checkstyle = DefaultPluginMetadata.create(new File("sonar-checkstyle-plugin.jar")).setKey("checkstyle");
     PluginMetadata pmd = DefaultPluginMetadata.create(new File("sonar-pmd-plugin.jar")).setKey("pmd");
 
-    assertThat(checkstyle.equals(pmd), is(false));
-    assertThat(checkstyle.equals(checkstyle), is(true));
-    assertThat(checkstyle.equals(DefaultPluginMetadata.create(new File("sonar-checkstyle-plugin.jar")).setKey("checkstyle")), is(true));
+    assertThat(checkstyle).isEqualTo(checkstyle);
+    assertThat(checkstyle).isEqualTo(DefaultPluginMetadata.create(new File("sonar-checkstyle-plugin.jar")).setKey("checkstyle"));
+    assertThat(checkstyle).isNotEqualTo(pmd);
   }
 
   @Test
   public void shouldCompare() {
-    PluginMetadata checkstyle = DefaultPluginMetadata.create(new File("sonar-checkstyle-plugin.jar"))
+    DefaultPluginMetadata checkstyle = DefaultPluginMetadata.create(new File("sonar-checkstyle-plugin.jar"))
         .setKey("checkstyle")
         .setName("Checkstyle");
-    PluginMetadata pmd = DefaultPluginMetadata.create(new File("sonar-pmd-plugin.jar"))
+    DefaultPluginMetadata pmd = DefaultPluginMetadata.create(new File("sonar-pmd-plugin.jar"))
         .setKey("pmd")
         .setName("PMD");
+    List<DefaultPluginMetadata> plugins = Arrays.asList(pmd, checkstyle);
+
+    assertThat(natural().sortedCopy(plugins)).onProperty("key").containsExactly("checkstyle", "pmd");
+  }
+
+  @Test
+  public void should_check_compatibility_with_sonar_version() {
+    assertThat(pluginWithVersion("1.1").isCompatibleWith("1.1")).isTrue();
+    assertThat(pluginWithVersion("1.1").isCompatibleWith("1.1.0")).isTrue();
+    assertThat(pluginWithVersion("1.0").isCompatibleWith("1.0.0")).isTrue();
+
+    assertThat(pluginWithVersion("1.0").isCompatibleWith("1.1")).isTrue();
+    assertThat(pluginWithVersion("1.1.1").isCompatibleWith("1.1.2")).isTrue();
+    assertThat(pluginWithVersion("2.0").isCompatibleWith("2.1.0")).isTrue();
+
+    assertThat(pluginWithVersion("1.1").isCompatibleWith("1.0")).isFalse();
+    assertThat(pluginWithVersion("2.0.1").isCompatibleWith("2.0.0")).isFalse();
+    assertThat(pluginWithVersion("2.10").isCompatibleWith("2.1")).isFalse();
+    assertThat(pluginWithVersion("10.10").isCompatibleWith("2.2")).isFalse();
+
+    assertThat(pluginWithVersion("1.1-SNAPSHOT").isCompatibleWith("1.0")).isFalse();
+    assertThat(pluginWithVersion("1.1-SNAPSHOT").isCompatibleWith("1.1")).isTrue();
+    assertThat(pluginWithVersion("1.1-SNAPSHOT").isCompatibleWith("1.2")).isTrue();
+    assertThat(pluginWithVersion("1.0.1-SNAPSHOT").isCompatibleWith("1.0")).isFalse();
+
+    assertThat(pluginWithVersion(null).isCompatibleWith("0")).isTrue();
+    assertThat(pluginWithVersion(null).isCompatibleWith("3.1")).isTrue();
+  }
 
-    PluginMetadata[] array = {pmd, checkstyle};
-    Arrays.sort(array);
-    assertThat(array[0].getKey(), is("checkstyle"));
-    assertThat(array[1].getKey(), is("pmd"));
+  static DefaultPluginMetadata pluginWithVersion(String version) {
+    return DefaultPluginMetadata.create(null).setSonarVersion(version);
   }
 }
index 9afc9c9de17a52e233abb77c71459d1f86a9f9e3..e9a893c48bebe783943310980c90fe951632bd24 100644 (file)
 package org.sonar.core.plugins;
 
 import org.apache.commons.io.FileUtils;
+import org.junit.ClassRule;
 import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
 
 import java.io.File;
 import java.io.IOException;
 
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.nullValue;
-import static org.junit.Assert.assertThat;
+import static org.fest.assertions.Assertions.assertThat;
 
 public class PluginInstallerTest {
 
-  private PluginInstaller extractor= new PluginInstaller();
+  private PluginInstaller extractor = new PluginInstaller();
+
+  @ClassRule
+  public static TemporaryFolder temporaryFolder = new TemporaryFolder();
 
   @Test
   public void shouldExtractMetadata() {
     DefaultPluginMetadata metadata = extractor.extractMetadata(getFile("sonar-checkstyle-plugin-2.8.jar"), true);
-    assertThat(metadata.getKey(), is("checkstyle"));
-    assertThat(metadata.getBasePlugin(), nullValue());
-    assertThat(metadata.getName(), is("Checkstyle"));
-    assertThat(metadata.isCore(), is(true));
-    assertThat(metadata.getFile().getName(), is("sonar-checkstyle-plugin-2.8.jar"));
+
+    assertThat(metadata.getKey()).isEqualTo("checkstyle");
+    assertThat(metadata.getBasePlugin()).isNull();
+    assertThat(metadata.getName()).isEqualTo("Checkstyle");
+    assertThat(metadata.isCore()).isEqualTo(true);
+    assertThat(metadata.getFile().getName()).isEqualTo("sonar-checkstyle-plugin-2.8.jar");
+    assertThat(metadata.getVersion()).isEqualTo("2.8");
+  }
+
+  @Test
+  public void should_read_sonar_version() {
+    DefaultPluginMetadata metadata = extractor.extractMetadata(getFile("sonar-switch-off-violations-plugin-1.1.jar"), false);
+
+    assertThat(metadata.getVersion()).isEqualTo("1.1");
+    assertThat(metadata.getSonarVersion()).isEqualTo("2.5");
   }
 
   @Test
   public void shouldExtractDeprecatedMetadata() {
     DefaultPluginMetadata metadata = extractor.extractMetadata(getFile("sonar-emma-plugin-0.3.jar"), false);
-    assertThat(metadata.getKey(), is("emma"));
-    assertThat(metadata.getBasePlugin(), nullValue());
-    assertThat(metadata.getName(), is("Emma"));
+
+    assertThat(metadata.getKey()).isEqualTo("emma");
+    assertThat(metadata.getBasePlugin()).isNull();
+    assertThat(metadata.getName()).isEqualTo("Emma");
   }
 
   @Test
   public void shouldExtractExtensionMetadata() {
     DefaultPluginMetadata metadata = extractor.extractMetadata(getFile("sonar-checkstyle-extensions-plugin-0.1-SNAPSHOT.jar"), true);
-    assertThat(metadata.getKey(), is("checkstyleextensions"));
-    assertThat(metadata.getBasePlugin(), is("checkstyle"));
+
+    assertThat(metadata.getKey()).isEqualTo("checkstyleextensions");
+    assertThat(metadata.getBasePlugin()).isEqualTo("checkstyle");
   }
 
   @Test
   public void shouldCopyAndExtractDependencies() throws IOException {
-    File toDir = new File("target/test-tmp/PluginInstallerTest/shouldCopyAndExtractDependencies");
-    FileUtils.forceMkdir(toDir);
-    FileUtils.cleanDirectory(toDir);
+    File toDir = temporaryFolder.newFolder();
 
     DefaultPluginMetadata metadata = extractor.install(getFile("sonar-checkstyle-plugin-2.8.jar"), true, null, toDir);
 
-    assertThat(metadata.getKey(), is("checkstyle"));
-    assertThat(new File(toDir, "sonar-checkstyle-plugin-2.8.jar").exists(), is(true));
-    assertThat(new File(toDir, "META-INF/lib/checkstyle-5.1.jar").exists(), is(true));
+    assertThat(metadata.getKey()).isEqualTo("checkstyle");
+    assertThat(new File(toDir, "sonar-checkstyle-plugin-2.8.jar")).exists();
+    assertThat(new File(toDir, "META-INF/lib/checkstyle-5.1.jar")).exists();
   }
 
   @Test
   public void shouldExtractOnlyDependencies() throws IOException {
-    File toDir = new File("target/test-tmp/PluginInstallerTest/shouldExtractOnlyDependencies");
-    FileUtils.forceMkdir(toDir);
-    FileUtils.cleanDirectory(toDir);
+    File toDir = temporaryFolder.newFolder();
 
     extractor.install(getFile("sonar-checkstyle-plugin-2.8.jar"), true, null, toDir);
 
-    assertThat(new File(toDir, "sonar-checkstyle-plugin-2.8.jar").exists(), is(true));
-    assertThat(new File(toDir, "META-INF/MANIFEST.MF").exists(), is(false));
-    assertThat(new File(toDir, "org/sonar/plugins/checkstyle/CheckstyleVersion.class").exists(), is(false));
+    assertThat(new File(toDir, "sonar-checkstyle-plugin-2.8.jar")).exists();
+    assertThat(new File(toDir, "META-INF/MANIFEST.MF")).doesNotExist();
+    assertThat(new File(toDir, "org/sonar/plugins/checkstyle/CheckstyleVersion.class")).doesNotExist();
   }
 
   @Test
   public void shouldCopyRuleExtensionsOnServerSide() throws IOException {
-    File toDir = new File("target/test-tmp/PluginInstallerTest/shouldCopyRuleExtensionsOnServerSide");
-    FileUtils.forceMkdir(toDir);
-    FileUtils.cleanDirectory(toDir);
+    File toDir = temporaryFolder.newFolder();
 
     DefaultPluginMetadata metadata = DefaultPluginMetadata.create(getFile("sonar-checkstyle-plugin-2.8.jar"))
         .setKey("checkstyle")
-        .addDeprecatedExtension(getFile("PluginInstallerTest/shouldCopyRuleExtensionsOnServerSide/checkstyle-extension.xml"));
+        .addDeprecatedExtension(getFile("checkstyle-extension.xml"));
     extractor.install(metadata, toDir);
 
-    assertThat(new File(toDir, "sonar-checkstyle-plugin-2.8.jar").exists(), is(true));
-    assertThat(new File(toDir, "checkstyle-extension.xml").exists(), is(true));
+    assertThat(new File(toDir, "sonar-checkstyle-plugin-2.8.jar")).exists();
+    assertThat(new File(toDir, "checkstyle-extension.xml")).exists();
   }
 
-  private File getFile(String filename) {
-    return FileUtils.toFile(getClass().getResource("/org/sonar/core/plugins/" + filename));
+  static File getFile(String filename) {
+    return FileUtils.toFile(PluginInstallerTest.class.getResource("/org/sonar/core/plugins/" + filename));
   }
 }
diff --git a/sonar-core/src/test/resources/org/sonar/core/plugins/PluginInstallerTest/shouldCopyRuleExtensionsOnServerSide/checkstyle-extension.xml b/sonar-core/src/test/resources/org/sonar/core/plugins/PluginInstallerTest/shouldCopyRuleExtensionsOnServerSide/checkstyle-extension.xml
deleted file mode 100644 (file)
index 75a263d..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<fake/>
\ No newline at end of file
diff --git a/sonar-core/src/test/resources/org/sonar/core/plugins/checkstyle-extension.xml b/sonar-core/src/test/resources/org/sonar/core/plugins/checkstyle-extension.xml
new file mode 100644 (file)
index 0000000..75a263d
--- /dev/null
@@ -0,0 +1 @@
+<fake/>
\ No newline at end of file
diff --git a/sonar-core/src/test/resources/org/sonar/core/plugins/sonar-switch-off-violations-plugin-1.1.jar b/sonar-core/src/test/resources/org/sonar/core/plugins/sonar-switch-off-violations-plugin-1.1.jar
new file mode 100644 (file)
index 0000000..8044dff
Binary files /dev/null and b/sonar-core/src/test/resources/org/sonar/core/plugins/sonar-switch-off-violations-plugin-1.1.jar differ
index 79618d14160471aa13eb2f2234ff87e0e7e62245..775408ca64c2bcd202bf5b221fcda94b5afc0398 100644 (file)
@@ -19,6 +19,7 @@
  */
 package org.sonar.server.plugins;
 
+import com.google.common.base.Preconditions;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import org.apache.commons.io.FileUtils;
@@ -27,7 +28,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.sonar.api.ServerComponent;
 import org.sonar.api.platform.PluginMetadata;
-import org.sonar.api.utils.Logs;
+import org.sonar.api.platform.Server;
 import org.sonar.api.utils.SonarException;
 import org.sonar.api.utils.TimeProfiler;
 import org.sonar.core.plugins.DefaultPluginMetadata;
@@ -45,15 +46,17 @@ public class PluginDeployer implements ServerComponent {
 
   private static final Logger LOG = LoggerFactory.getLogger(PluginDeployer.class);
 
+  private final Server server;
   private final DefaultServerFileSystem fileSystem;
-  private final Map<String, PluginMetadata> pluginByKeys = Maps.newHashMap();
   private final PluginInstaller installer;
+  private final Map<String, PluginMetadata> pluginByKeys = Maps.newHashMap();
 
-  public PluginDeployer(DefaultServerFileSystem fileSystem) {
-    this(fileSystem, new PluginInstaller());
+  public PluginDeployer(Server server, DefaultServerFileSystem fileSystem) {
+    this(server, fileSystem, new PluginInstaller());
   }
 
-  PluginDeployer(DefaultServerFileSystem fileSystem, PluginInstaller installer) {
+  PluginDeployer(Server server, DefaultServerFileSystem fileSystem, PluginInstaller installer) {
+    this.server = server;
     this.fileSystem = fileSystem;
     this.installer = installer;
   }
@@ -91,19 +94,20 @@ public class PluginDeployer implements ServerComponent {
 
   private void registerPlugin(File file, boolean isCore, boolean canDelete) {
     DefaultPluginMetadata metadata = installer.extractMetadata(file, isCore);
-    if (StringUtils.isNotBlank(metadata.getKey())) {
-      PluginMetadata existing = pluginByKeys.get(metadata.getKey());
-      if (existing != null) {
-        if (canDelete) {
-          FileUtils.deleteQuietly(existing.getFile());
-          Logs.INFO.info("Plugin " + metadata.getKey() + " replaced by new version");
-
-        } else {
-          throw new ServerStartException("Found two plugins with the same key '" + metadata.getKey() + "': " + metadata.getFile().getName() + " and "
-            + existing.getFile().getName());
-        }
-      }
-      pluginByKeys.put(metadata.getKey(), metadata);
+    if (StringUtils.isBlank(metadata.getKey())) {
+      return;
+    }
+
+    PluginMetadata existing = pluginByKeys.put(metadata.getKey(), metadata);
+
+    if ((existing != null) && !canDelete) {
+      throw new ServerStartException("Found two plugins with the same key '" + metadata.getKey() + "': " + metadata.getFile().getName() + " and "
+        + existing.getFile().getName());
+    }
+
+    if (existing != null) {
+      FileUtils.deleteQuietly(existing.getFile());
+      LOG.info("Plugin " + metadata.getKey() + " replaced by new version");
     }
   }
 
@@ -186,9 +190,13 @@ public class PluginDeployer implements ServerComponent {
   }
 
   private void deploy(DefaultPluginMetadata plugin) {
-    try {
-      LOG.debug("Deploy plugin " + plugin);
+    LOG.debug("Deploy plugin " + plugin);
 
+    Preconditions.checkState(plugin.isCompatibleWith(server.getVersion()),
+        "Plugin %s needs a more recent version of Sonar than %s. At least %s is expected",
+        plugin.getKey(), server.getVersion(), plugin.getSonarVersion());
+
+    try {
       File pluginDeployDir = new File(fileSystem.getDeployedPluginsDir(), plugin.getKey());
       FileUtils.forceMkdir(pluginDeployDir);
       FileUtils.cleanDirectory(pluginDeployDir);
@@ -199,7 +207,6 @@ public class PluginDeployer implements ServerComponent {
       }
 
       installer.install(plugin, pluginDeployDir);
-
     } catch (IOException e) {
       throw new RuntimeException("Fail to deploy the plugin " + plugin, e);
     }
index 6adefb336f97b814d67dd9991522dee8e6efc05c..d134a23ce07741e488c609ba69557340409164ba 100644 (file)
  */
 package org.sonar.server.plugins;
 
-import org.hamcrest.core.Is;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.ExpectedException;
 import org.junit.rules.TestName;
 import org.sonar.api.platform.PluginMetadata;
+import org.sonar.api.platform.Server;
 import org.sonar.core.plugins.PluginInstaller;
 import org.sonar.server.platform.DefaultServerFileSystem;
 import org.sonar.server.platform.ServerStartException;
@@ -32,8 +33,9 @@ import org.sonar.test.TestUtils;
 
 import java.io.File;
 
-import static org.hamcrest.core.Is.is;
-import static org.junit.Assert.assertThat;
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 public class PluginDeployerTest {
 
@@ -42,17 +44,22 @@ public class PluginDeployerTest {
   private File homeDir;
   private File deployDir;
   private PluginDeployer deployer;
+  private Server server = mock(Server.class);
 
   @Rule
   public TestName name = new TestName();
 
+  @Rule
+  public ExpectedException exception = ExpectedException.none();
+
   @Before
   public void start() {
+    when(server.getVersion()).thenReturn("3.1");
     homeDir = TestUtils.getResource(PluginDeployerTest.class, name.getMethodName());
     deployDir = TestUtils.getTestTempDir(PluginDeployerTest.class, name.getMethodName() + "/deploy");
     fileSystem = new DefaultServerFileSystem(null, homeDir, deployDir);
     extractor = new PluginInstaller();
-    deployer = new PluginDeployer(fileSystem, extractor);
+    deployer = new PluginDeployer(server, fileSystem, extractor);
   }
 
   @Test
@@ -60,18 +67,18 @@ public class PluginDeployerTest {
     deployer.start();
 
     // check that the plugin is registered
-    assertThat(deployer.getMetadata().size(), Is.is(1)); // no more checkstyle
+    assertThat(deployer.getMetadata()).hasSize(1); // no more checkstyle
 
     PluginMetadata plugin = deployer.getMetadata("foo");
-    assertThat(plugin.getName(), is("Foo"));
-    assertThat(plugin.getDeployedFiles().size(), is(1));
-    assertThat(plugin.isCore(), is(false));
-    assertThat(plugin.isUseChildFirstClassLoader(), is(false));
+    assertThat(plugin.getName()).isEqualTo("Foo");
+    assertThat(plugin.getDeployedFiles()).hasSize(1);
+    assertThat(plugin.isCore()).isFalse();
+    assertThat(plugin.isUseChildFirstClassLoader()).isFalse();
 
     // check that the file is deployed
     File deployedJar = new File(deployDir, "plugins/foo/foo-plugin.jar");
-    assertThat(deployedJar.exists(), is(true));
-    assertThat(deployedJar.isFile(), is(true));
+    assertThat(deployedJar.exists()).isTrue();
+    assertThat(deployedJar.isFile()).isTrue();
   }
 
   @Test
@@ -79,16 +86,16 @@ public class PluginDeployerTest {
     deployer.start();
 
     // check that the plugin is registered
-    assertThat(deployer.getMetadata().size(), Is.is(1)); // no more checkstyle
+    assertThat(deployer.getMetadata()).hasSize(1); // no more checkstyle
 
     PluginMetadata plugin = deployer.getMetadata("buildbreaker");
-    assertThat(plugin.isCore(), is(false));
-    assertThat(plugin.isUseChildFirstClassLoader(), is(false));
+    assertThat(plugin.isCore()).isFalse();
+    assertThat(plugin.isUseChildFirstClassLoader()).isFalse();
 
     // check that the file is deployed
     File deployedJar = new File(deployDir, "plugins/buildbreaker/sonar-build-breaker-plugin-0.1.jar");
-    assertThat(deployedJar.exists(), is(true));
-    assertThat(deployedJar.isFile(), is(true));
+    assertThat(deployedJar.exists()).isTrue();
+    assertThat(deployedJar.isFile()).isTrue();
   }
 
   @Test
@@ -96,24 +103,34 @@ public class PluginDeployerTest {
     deployer.start();
 
     // check that the plugin is registered
-    assertThat(deployer.getMetadata().size(), Is.is(1)); // no more checkstyle
+    assertThat(deployer.getMetadata()).hasSize(1); // no more checkstyle
 
     PluginMetadata plugin = deployer.getMetadata("foo");
-    assertThat(plugin.getDeployedFiles().size(), is(2));
+    assertThat(plugin.getDeployedFiles()).hasSize(2);
     File extFile = plugin.getDeployedFiles().get(1);
-    assertThat(extFile.getName(), is("foo-extension.txt"));
+    assertThat(extFile.getName()).isEqualTo("foo-extension.txt");
 
     // check that the extension file is deployed
     File deployedJar = new File(deployDir, "plugins/foo/foo-extension.txt");
-    assertThat(deployedJar.exists(), is(true));
-    assertThat(deployedJar.isFile(), is(true));
+    assertThat(deployedJar.exists()).isTrue();
+    assertThat(deployedJar.isFile()).isTrue();
   }
 
   @Test
   public void ignoreJarsWhichAreNotPlugins() {
     deployer.start();
 
-    assertThat(deployer.getMetadata().size(), Is.is(0));
+    assertThat(deployer.getMetadata()).isEmpty();
+  }
+
+  @Test
+  public void should_fail_on_plugin_depending_on_more_recent_sonar() {
+    when(server.getVersion()).thenReturn("2.0");
+
+    exception.expect(IllegalStateException.class);
+    exception.expectMessage("Plugin switchoffviolations needs a more recent version of Sonar than 2.0. At least 2.5 is expected");
+
+    deployer.start();
   }
 
   @Test(expected = ServerStartException.class)
@@ -125,5 +142,4 @@ public class PluginDeployerTest {
   public void failIfTwoDeprecatedPluginsWithSameKey() {
     deployer.start();
   }
-
 }
diff --git a/sonar-server/src/test/resources/org/sonar/server/plugins/PluginDeployerTest/should_fail_on_plugin_depending_on_more_recent_sonar/extensions/plugins/sonar-switch-off-violations-plugin-1.1.jar b/sonar-server/src/test/resources/org/sonar/server/plugins/PluginDeployerTest/should_fail_on_plugin_depending_on_more_recent_sonar/extensions/plugins/sonar-switch-off-violations-plugin-1.1.jar
new file mode 100644 (file)
index 0000000..8044dff
Binary files /dev/null and b/sonar-server/src/test/resources/org/sonar/server/plugins/PluginDeployerTest/should_fail_on_plugin_depending_on_more_recent_sonar/extensions/plugins/sonar-switch-off-violations-plugin-1.1.jar differ