You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

PluginInfoTest.java 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2023 SonarSource SA
  4. * mailto:info AT sonarsource DOT com
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program; if not, write to the Free Software Foundation,
  18. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. package org.sonar.core.platform;
  21. import com.tngtech.java.junit.dataprovider.DataProvider;
  22. import com.tngtech.java.junit.dataprovider.DataProviderRunner;
  23. import com.tngtech.java.junit.dataprovider.UseDataProvider;
  24. import java.io.File;
  25. import java.io.IOException;
  26. import java.nio.charset.StandardCharsets;
  27. import java.util.Arrays;
  28. import java.util.List;
  29. import javax.annotation.Nullable;
  30. import org.apache.commons.io.FileUtils;
  31. import org.assertj.core.api.Assertions;
  32. import org.junit.Rule;
  33. import org.junit.Test;
  34. import org.junit.rules.TemporaryFolder;
  35. import org.junit.runner.RunWith;
  36. import org.sonar.api.utils.MessageException;
  37. import org.sonar.api.utils.ZipUtils;
  38. import org.sonar.updatecenter.common.PluginManifest;
  39. import org.sonar.updatecenter.common.Version;
  40. import static com.google.common.collect.Ordering.natural;
  41. import static org.assertj.core.api.Assertions.assertThat;
  42. import static org.assertj.core.api.Assertions.assertThatThrownBy;
  43. import static org.junit.Assert.fail;
  44. @RunWith(DataProviderRunner.class)
  45. public class PluginInfoTest {
  46. @Rule
  47. public TemporaryFolder temp = new TemporaryFolder();
  48. @Test
  49. public void test_RequiredPlugin() {
  50. PluginInfo.RequiredPlugin plugin = PluginInfo.RequiredPlugin.parse("java:1.1");
  51. assertThat(plugin.getKey()).isEqualTo("java");
  52. assertThat(plugin.getMinimalVersion().getName()).isEqualTo("1.1");
  53. assertThat(plugin).hasToString("java:1.1")
  54. .isEqualTo(PluginInfo.RequiredPlugin.parse("java:1.2"))
  55. .isNotEqualTo(PluginInfo.RequiredPlugin.parse("php:1.2"));
  56. try {
  57. PluginInfo.RequiredPlugin.parse("java");
  58. fail();
  59. } catch (IllegalArgumentException expected) {
  60. // ok
  61. }
  62. }
  63. @Test
  64. public void test_comparison() {
  65. PluginInfo java1 = new PluginInfo("java").setVersion(Version.create("1.0"));
  66. PluginInfo java2 = new PluginInfo("java").setVersion(Version.create("2.0"));
  67. PluginInfo javaNoVersion = new PluginInfo("java");
  68. PluginInfo cobol = new PluginInfo("cobol").setVersion(Version.create("1.0"));
  69. PluginInfo noVersion = new PluginInfo("noVersion");
  70. List<PluginInfo> plugins = Arrays.asList(java1, cobol, javaNoVersion, noVersion, java2);
  71. List<PluginInfo> ordered = natural().sortedCopy(plugins);
  72. Assertions.assertThat(ordered.get(0)).isSameAs(cobol);
  73. Assertions.assertThat(ordered.get(1)).isSameAs(javaNoVersion);
  74. Assertions.assertThat(ordered.get(2)).isSameAs(java1);
  75. Assertions.assertThat(ordered.get(3)).isSameAs(java2);
  76. Assertions.assertThat(ordered.get(4)).isSameAs(noVersion);
  77. }
  78. @Test
  79. public void test_equals() {
  80. PluginInfo java1 = new PluginInfo("java").setVersion(Version.create("1.0"));
  81. PluginInfo java2 = new PluginInfo("java").setVersion(Version.create("2.0"));
  82. PluginInfo javaNoVersion = new PluginInfo("java");
  83. PluginInfo cobol = new PluginInfo("cobol").setVersion(Version.create("1.0"));
  84. assertThat(java1.equals(java1)).isTrue();
  85. assertThat(java1.equals(java2)).isFalse();
  86. assertThat(java1.equals(javaNoVersion)).isFalse();
  87. assertThat(java1.equals(cobol)).isFalse();
  88. assertThat(java1.equals("java:1.0")).isFalse();
  89. assertThat(java1.equals(null)).isFalse();
  90. assertThat(javaNoVersion.equals(javaNoVersion)).isTrue();
  91. assertThat(java1).hasSameHashCodeAs(java1);
  92. assertThat(javaNoVersion).hasSameHashCodeAs(javaNoVersion);
  93. }
  94. /**
  95. * SNAPSHOT versions of SonarQube are built on local developer machines only.
  96. * All other build environments have unique release versions (6.3.0.12345).
  97. */
  98. @Test
  99. public void test_compatibility_with_snapshot_version_of_sonarqube() {
  100. // plugins compatible with 5.6 LTS
  101. assertThat(withMinSqVersion("5.6").isCompatibleWith("6.3-SNAPSHOT")).isTrue();
  102. assertThat(withMinSqVersion("5.6.1").isCompatibleWith("6.3-SNAPSHOT")).isTrue();
  103. // plugin build with old release candidates of SonarQube (RC technical versions have been removed
  104. // in SonarQube 6.3)
  105. assertThat(withMinSqVersion("5.6-RC1").isCompatibleWith("6.3-SNAPSHOT")).isTrue();
  106. assertThat(withMinSqVersion("6.2-RC1").isCompatibleWith("6.3-SNAPSHOT")).isTrue();
  107. // plugin built with snapshot version of SonarQube
  108. assertThat(withMinSqVersion("5.6-SNAPSHOT").isCompatibleWith("6.3-SNAPSHOT")).isTrue();
  109. assertThat(withMinSqVersion("6.3-SNAPSHOT").isCompatibleWith("6.3-SNAPSHOT")).isTrue();
  110. assertThat(withMinSqVersion("6.4-SNAPSHOT").isCompatibleWith("6.3-SNAPSHOT")).isFalse();
  111. // plugin built with SonarQube releases
  112. assertThat(withMinSqVersion("6.3.0.5000").isCompatibleWith("6.3-SNAPSHOT")).isTrue();
  113. assertThat(withMinSqVersion("6.3.1.5000").isCompatibleWith("6.3-SNAPSHOT")).isTrue();
  114. assertThat(withMinSqVersion("6.3.1.5000").isCompatibleWith("6.4-SNAPSHOT")).isTrue();
  115. assertThat(withMinSqVersion("6.4.0.5000").isCompatibleWith("6.3-SNAPSHOT")).isFalse();
  116. // no constraint
  117. assertThat(withMinSqVersion(null).isCompatibleWith("6.3-SNAPSHOT")).isTrue();
  118. }
  119. /**
  120. * @see #test_compatibility_with_snapshot_version_of_sonarqube
  121. */
  122. @Test
  123. public void test_compatibility_with_release_version_of_sonarqube() {
  124. // plugins compatible with 5.6 LTS
  125. assertThat(withMinSqVersion("5.6").isCompatibleWith("6.3.0.5000")).isTrue();
  126. assertThat(withMinSqVersion("5.6.1").isCompatibleWith("6.3.0.5000")).isTrue();
  127. // plugin build with old release candidates of SonarQube (RC technical versions have been removed
  128. // in SonarQube 6.3)
  129. assertThat(withMinSqVersion("5.6-RC1").isCompatibleWith("6.3.0.5000")).isTrue();
  130. assertThat(withMinSqVersion("6.2-RC1").isCompatibleWith("6.3.0.5000")).isTrue();
  131. // plugin built with snapshot version of SonarQube
  132. assertThat(withMinSqVersion("5.6-SNAPSHOT").isCompatibleWith("6.3.0.5000")).isTrue();
  133. assertThat(withMinSqVersion("6.3-SNAPSHOT").isCompatibleWith("6.3.0.5000")).isTrue();
  134. assertThat(withMinSqVersion("6.3-SNAPSHOT").isCompatibleWith("6.3.1.6000")).isTrue();
  135. assertThat(withMinSqVersion("6.4-SNAPSHOT").isCompatibleWith("6.3.0.5000")).isFalse();
  136. // plugin built with SonarQube releases
  137. assertThat(withMinSqVersion("6.3.0.5000").isCompatibleWith("6.3.0.4000")).isFalse();
  138. assertThat(withMinSqVersion("6.3.0.5000").isCompatibleWith("6.3.0.5000")).isTrue();
  139. assertThat(withMinSqVersion("6.3.0.5000").isCompatibleWith("6.3.1.6000")).isTrue();
  140. assertThat(withMinSqVersion("6.4.0.7000").isCompatibleWith("6.3.0.5000")).isFalse();
  141. // no constraint
  142. assertThat(withMinSqVersion(null).isCompatibleWith("6.3.0.5000")).isTrue();
  143. }
  144. @Test
  145. public void create_from_minimal_manifest() throws Exception {
  146. PluginManifest manifest = new PluginManifest();
  147. manifest.setKey("java");
  148. manifest.setVersion("1.0");
  149. manifest.setName("Java");
  150. manifest.setMainClass("org.foo.FooPlugin");
  151. File jarFile = temp.newFile();
  152. PluginInfo pluginInfo = PluginInfo.create(jarFile, manifest);
  153. assertThat(pluginInfo.getKey()).isEqualTo("java");
  154. assertThat(pluginInfo.getName()).isEqualTo("Java");
  155. assertThat(pluginInfo.getVersion().getName()).isEqualTo("1.0");
  156. assertThat(pluginInfo.getJarFile()).isSameAs(jarFile);
  157. assertThat(pluginInfo.getMainClass()).isEqualTo("org.foo.FooPlugin");
  158. assertThat(pluginInfo.getBasePlugin()).isNull();
  159. assertThat(pluginInfo.getDescription()).isNull();
  160. assertThat(pluginInfo.getHomepageUrl()).isNull();
  161. assertThat(pluginInfo.getImplementationBuild()).isNull();
  162. assertThat(pluginInfo.getIssueTrackerUrl()).isNull();
  163. assertThat(pluginInfo.getLicense()).isNull();
  164. assertThat(pluginInfo.getOrganizationName()).isNull();
  165. assertThat(pluginInfo.getOrganizationUrl()).isNull();
  166. assertThat(pluginInfo.getMinimalSonarPluginApiVersion()).isNull();
  167. assertThat(pluginInfo.getRequiredPlugins()).isEmpty();
  168. assertThat(pluginInfo.isSonarLintSupported()).isFalse();
  169. assertThat(pluginInfo.getRequiredForLanguages()).isEmpty();
  170. }
  171. @Test
  172. public void create_from_complete_manifest() throws Exception {
  173. PluginManifest manifest = new PluginManifest();
  174. manifest.setKey("fbcontrib");
  175. manifest.setVersion("2.0");
  176. manifest.setName("Java");
  177. manifest.setMainClass("org.fb.FindbugsPlugin");
  178. manifest.setBasePlugin("findbugs");
  179. manifest.setSonarVersion("4.5.1");
  180. manifest.setDescription("the desc");
  181. manifest.setHomepage("http://fbcontrib.org");
  182. manifest.setImplementationBuild("SHA1");
  183. manifest.setLicense("LGPL");
  184. manifest.setOrganization("SonarSource");
  185. manifest.setOrganizationUrl("http://sonarsource.com");
  186. manifest.setIssueTrackerUrl("http://jira.com");
  187. manifest.setRequirePlugins(new String[] {"java:2.0", "pmd:1.3"});
  188. manifest.setSonarLintSupported(true);
  189. manifest.setRequiredForLanguages(new String[]{"java", "xml"});
  190. File jarFile = temp.newFile();
  191. PluginInfo pluginInfo = PluginInfo.create(jarFile, manifest);
  192. assertThat(pluginInfo.getBasePlugin()).isEqualTo("findbugs");
  193. assertThat(pluginInfo.getDescription()).isEqualTo("the desc");
  194. assertThat(pluginInfo.getHomepageUrl()).isEqualTo("http://fbcontrib.org");
  195. assertThat(pluginInfo.getImplementationBuild()).isEqualTo("SHA1");
  196. assertThat(pluginInfo.getIssueTrackerUrl()).isEqualTo("http://jira.com");
  197. assertThat(pluginInfo.getLicense()).isEqualTo("LGPL");
  198. assertThat(pluginInfo.getOrganizationName()).isEqualTo("SonarSource");
  199. assertThat(pluginInfo.getOrganizationUrl()).isEqualTo("http://sonarsource.com");
  200. assertThat(pluginInfo.getMinimalSonarPluginApiVersion().getName()).isEqualTo("4.5.1");
  201. assertThat(pluginInfo.getRequiredPlugins()).extracting("key").containsOnly("java", "pmd");
  202. assertThat(pluginInfo.isSonarLintSupported()).isTrue();
  203. assertThat(pluginInfo.getRequiredForLanguages()).containsOnly("java", "xml");
  204. }
  205. @Test
  206. @UseDataProvider("licenseVersions")
  207. public void requiredPlugin_license_is_ignored_when_reading_manifest(String version) throws IOException {
  208. PluginManifest manifest = new PluginManifest();
  209. manifest.setKey("java");
  210. manifest.setVersion("1.0");
  211. manifest.setName("Java");
  212. manifest.setMainClass("org.foo.FooPlugin");
  213. manifest.setRequirePlugins(new String[] {"license:" + version});
  214. File jarFile = temp.newFile();
  215. PluginInfo pluginInfo = PluginInfo.create(jarFile, manifest);
  216. assertThat(pluginInfo.getRequiredPlugins()).isEmpty();
  217. }
  218. @Test
  219. @UseDataProvider("licenseVersions")
  220. public void requiredPlugin_license_among_others_is_ignored_when_reading_manifest(String version) throws IOException {
  221. PluginManifest manifest = new PluginManifest();
  222. manifest.setKey("java");
  223. manifest.setVersion("1.0");
  224. manifest.setName("Java");
  225. manifest.setMainClass("org.foo.FooPlugin");
  226. manifest.setRequirePlugins(new String[] {"java:2.0", "license:" + version, "pmd:1.3"});
  227. File jarFile = temp.newFile();
  228. PluginInfo pluginInfo = PluginInfo.create(jarFile, manifest);
  229. assertThat(pluginInfo.getRequiredPlugins()).extracting("key").containsOnly("java", "pmd");
  230. }
  231. @DataProvider
  232. public static Object[][] licenseVersions() {
  233. return new Object[][] {
  234. {"0.3"},
  235. {"7.2.0.1253"}
  236. };
  237. }
  238. @Test
  239. public void create_from_file() {
  240. File checkstyleJar = FileUtils.toFile(getClass().getResource("/org/sonar/core/platform/sonar-checkstyle-plugin-2.8.jar"));
  241. PluginInfo checkstyleInfo = PluginInfo.create(checkstyleJar);
  242. assertThat(checkstyleInfo.getName()).isEqualTo("Checkstyle");
  243. assertThat(checkstyleInfo.getDocumentationPath()).isNull();
  244. assertThat(checkstyleInfo.getMinimalSonarPluginApiVersion()).isEqualTo(Version.create("2.8"));
  245. }
  246. @Test
  247. public void create_from_file_with_documentation() {
  248. File jarWithDocs = FileUtils.toFile(getClass().getResource("/org/sonar/core/platform/jar_with_documentation.jar"));
  249. PluginInfo checkstyleInfo = PluginInfo.create(jarWithDocs);
  250. assertThat(checkstyleInfo.getDocumentationPath()).isNotBlank();
  251. assertThat(checkstyleInfo.getDocumentationPath()).isEqualTo("static/documentation.md");
  252. }
  253. @Test
  254. public void test_toString() {
  255. PluginInfo pluginInfo = new PluginInfo("java").setVersion(Version.create("1.1"));
  256. assertThat(pluginInfo).hasToString("[java / 1.1]");
  257. pluginInfo.setImplementationBuild("SHA1");
  258. assertThat(pluginInfo).hasToString("[java / 1.1 / SHA1]");
  259. }
  260. /**
  261. * The English bundle plugin was removed in 5.2. L10n plugins do not need to declare
  262. * it as base plugin anymore
  263. */
  264. @Test
  265. public void l10n_plugins_should_not_extend_english_plugin() {
  266. PluginInfo pluginInfo = new PluginInfo("l10nfr").setBasePlugin("l10nen");
  267. assertThat(pluginInfo.getBasePlugin()).isNull();
  268. }
  269. @Test
  270. public void fail_when_jar_is_not_a_plugin() throws IOException {
  271. // this JAR has a manifest but is not a plugin
  272. File jarRootDir = temp.newFolder();
  273. FileUtils.write(new File(jarRootDir, "META-INF/MANIFEST.MF"), "Build-Jdk: 1.6.0_15", StandardCharsets.UTF_8);
  274. File jar = temp.newFile();
  275. ZipUtils.zipDir(jarRootDir, jar);
  276. assertThatThrownBy(() -> PluginInfo.create(jar))
  277. .isInstanceOf(MessageException.class)
  278. .hasMessage("File is not a plugin. Please delete it and restart: " + jar.getAbsolutePath());
  279. }
  280. PluginInfo withMinSqVersion(@Nullable String version) {
  281. PluginInfo pluginInfo = new PluginInfo("foo");
  282. if (version != null) {
  283. pluginInfo.setMinimalSonarPluginApiVersion(Version.create(version));
  284. }
  285. return pluginInfo;
  286. }
  287. }