From: Sébastien Lesaint Date: Mon, 16 Oct 2017 08:15:41 +0000 (+0200) Subject: SONAR-9976 add editionBundled flag to response of api/plugins/installed X-Git-Tag: 6.7-RC1~108 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=2dd24c26aec365b6a2afcb3c27f3b46798e9900d;p=sonarqube.git SONAR-9976 add editionBundled flag to response of api/plugins/installed --- diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/edition/EditionBundledPlugins.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/edition/EditionBundledPlugins.java index 362f027005b..058958958be 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/plugins/edition/EditionBundledPlugins.java +++ b/server/sonar-server/src/main/java/org/sonar/server/plugins/edition/EditionBundledPlugins.java @@ -20,6 +20,7 @@ package org.sonar.server.plugins.edition; import java.util.Arrays; +import org.sonar.core.platform.PluginInfo; import org.sonar.updatecenter.common.Plugin; public final class EditionBundledPlugins { @@ -35,4 +36,9 @@ public final class EditionBundledPlugins { return SONARSOURCE_ORGANIZATION.equalsIgnoreCase(plugin.getOrganization()) && Arrays.stream(SONARSOURCE_COMMERCIAL_LICENSES).anyMatch(s -> s.equalsIgnoreCase(plugin.getLicense())); } + + public static boolean isEditionBundled(PluginInfo pluginInfo) { + return SONARSOURCE_ORGANIZATION.equalsIgnoreCase(pluginInfo.getOrganizationName()) + && Arrays.stream(SONARSOURCE_COMMERCIAL_LICENSES).anyMatch(s -> s.equalsIgnoreCase(pluginInfo.getLicense())); + } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/PluginWSCommons.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/PluginWSCommons.java index 82ee4b1a472..759d7a6f659 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/PluginWSCommons.java +++ b/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/PluginWSCommons.java @@ -37,6 +37,7 @@ import org.sonar.api.utils.text.JsonWriter; import org.sonar.core.platform.PluginInfo; import org.sonar.db.plugin.PluginDto; import org.sonar.server.plugins.UpdateCenterMatrixFactory; +import org.sonar.server.plugins.edition.EditionBundledPlugins; import org.sonar.updatecenter.common.Artifact; import org.sonar.updatecenter.common.Plugin; import org.sonar.updatecenter.common.PluginUpdate; @@ -110,6 +111,7 @@ public class PluginWSCommons { json.prop(PROPERTY_LICENSE, pluginInfo.getLicense()); json.prop(PROPERTY_ORGANIZATION_NAME, pluginInfo.getOrganizationName()); json.prop(PROPERTY_ORGANIZATION_URL, pluginInfo.getOrganizationUrl()); + json.prop(PROPERTY_EDITION_BUNDLED, EditionBundledPlugins.isEditionBundled(pluginInfo)); json.prop(PROPERTY_HOMEPAGE_URL, pluginInfo.getHomepageUrl()); json.prop(PROPERTY_ISSUE_TRACKER_URL, pluginInfo.getIssueTrackerUrl()); json.prop(PROPERTY_IMPLEMENTATION_BUILD, pluginInfo.getImplementationBuild()); diff --git a/server/sonar-server/src/main/resources/org/sonar/server/plugins/ws/example-installed_plugins.json b/server/sonar-server/src/main/resources/org/sonar/server/plugins/ws/example-installed_plugins.json index d88f50b376a..e961781b3ab 100644 --- a/server/sonar-server/src/main/resources/org/sonar/server/plugins/ws/example-installed_plugins.json +++ b/server/sonar-server/src/main/resources/org/sonar/server/plugins/ws/example-installed_plugins.json @@ -8,6 +8,7 @@ "license": "GNU LGPL 3", "organizationName": "SonarSource", "organizationUrl": "http://www.sonarsource.com", + "editionBundled": false, "homepageUrl": "https://redirect.sonarsource.com/plugins/scmgit.html", "issueTrackerUrl": "http://jira.sonarsource.com/browse/SONARSCGIT", "implementationBuild": "9ce9d330c313c296fab051317cc5ad4b26319e07", @@ -24,6 +25,7 @@ "license": "GNU LGPL 3", "organizationName": "SonarSource", "organizationUrl": "http://www.sonarsource.com", + "editionBundled": false, "homepageUrl": "https://redirect.sonarsource.com/plugins/java.html", "issueTrackerUrl": "http://jira.sonarsource.com/browse/SONARJAVA", "implementationBuild": "65396a609ddface8b311a6a665aca92a7da694f1", @@ -40,6 +42,7 @@ "license": "GNU LGPL 3", "organizationName": "SonarSource", "organizationUrl": "http://www.sonarsource.com", + "editionBundled": false, "homepageUrl": "https://redirect.sonarsource.com/plugins/scmsvn.html", "issueTrackerUrl": "http://jira.sonarsource.com/browse/SONARSCSVN", "implementationBuild": "213fc8a8b582ff530b12dd4a59a6512be1071234", diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/edition/EditionBundledPluginsTest.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/edition/EditionBundledPluginsTest.java new file mode 100644 index 00000000000..2687d8fa855 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/plugins/edition/EditionBundledPluginsTest.java @@ -0,0 +1,178 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.plugins.edition; + +import java.util.Random; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.core.platform.PluginInfo; +import org.sonar.updatecenter.common.Plugin; + +import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; +import static org.assertj.core.api.Assertions.assertThat; + +public class EditionBundledPluginsTest { + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + private final Random random = new Random(); + + @Test + public void isEditionBundled_on_Plugin_fails_with_NPE_if_arg_is_null() { + expectedException.expect(NullPointerException.class); + + EditionBundledPlugins.isEditionBundled((Plugin) null); + } + + @Test + public void isEditionBundled_on_Plugin_returns_false_for_SonarSource_and_non_commercial_license() { + Plugin plugin = newPlugin(randomizeCase("SonarSource"), randomAlphanumeric(3)); + + assertThat(EditionBundledPlugins.isEditionBundled(plugin)).isFalse(); + } + + @Test + public void isEditionBundled_on_Plugin_returns_false_for_license_SonarSource_and_non_SonarSource_organization() { + Plugin plugin = newPlugin(randomAlphanumeric(3), randomizeCase("SonarSource")); + + assertThat(EditionBundledPlugins.isEditionBundled(plugin)).isFalse(); + } + + @Test + public void isEditionBundled_on_Plugin_returns_false_for_license_Commercial_and_non_SonarSource_organization() { + Plugin plugin = newPlugin(randomAlphanumeric(3), randomizeCase("Commercial")); + + assertThat(EditionBundledPlugins.isEditionBundled(plugin)).isFalse(); + } + + @Test + public void isEditionBundled_on_Plugin_returns_true_for_organization_SonarSource_and_license_SonarSource_case_insensitive() { + Plugin plugin = newPlugin(randomizeCase("SonarSource"), randomizeCase("SonarSource")); + + assertThat(EditionBundledPlugins.isEditionBundled(plugin)).isTrue(); + } + + @Test + public void isEditionBundled_on_Plugin_returns_true_for_organization_SonarSource_and_license_Commercial_case_insensitive() { + Plugin plugin = newPlugin(randomizeCase("SonarSource"), randomizeCase("Commercial")); + + assertThat(EditionBundledPlugins.isEditionBundled(plugin)).isTrue(); + } + + @Test + public void isEditionBundled_on_PluginInfo_fails_with_NPE_if_arg_is_null() { + expectedException.expect(NullPointerException.class); + + EditionBundledPlugins.isEditionBundled((PluginInfo) null); + } + + @Test + public void isEditionBundled_on_PluginInfo_returns_false_for_SonarSource_and_non_commercial_license() { + PluginInfo pluginInfo = newPluginInfo(randomizeCase("SonarSource"), randomAlphanumeric(3)); + + assertThat(EditionBundledPlugins.isEditionBundled(pluginInfo)).isFalse(); + } + + @Test + public void isEditionBundled_on_PluginInfo_returns_false_for_license_SonarSource_and_non_SonarSource_organization() { + PluginInfo pluginInfo = newPluginInfo(randomAlphanumeric(3), randomizeCase("SonarSource")); + + assertThat(EditionBundledPlugins.isEditionBundled(pluginInfo)).isFalse(); + } + + @Test + public void isEditionBundled_on_PluginInfo_returns_false_for_license_Commercial_and_non_SonarSource_organization() { + PluginInfo pluginInfo = newPluginInfo(randomAlphanumeric(3), randomizeCase("Commercial")); + + assertThat(EditionBundledPlugins.isEditionBundled(pluginInfo)).isFalse(); + } + + @Test + public void isEditionBundled_on_PluginInfo_returns_true_for_organization_SonarSource_and_license_SonarSource_case_insensitive() { + PluginInfo pluginInfo = newPluginInfo(randomizeCase("SonarSource"), randomizeCase("SonarSource")); + + assertThat(EditionBundledPlugins.isEditionBundled(pluginInfo)).isTrue(); + } + + @Test + public void isEditionBundled_on_PluginINfo_returns_true_for_organization_SonarSource_and_license_Commercial_case_insensitive() { + PluginInfo pluginInfo = newPluginInfo(randomizeCase("SonarSource"), randomizeCase("Commercial")); + + assertThat(EditionBundledPlugins.isEditionBundled(pluginInfo)).isTrue(); + } + + private String randomizeCase(String s) { + return s.chars() + .map(c -> random.nextBoolean() ? Character.toUpperCase(c) : Character.toLowerCase(c)) + .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append) + .toString(); + } + + private PluginInfo newPluginInfo(String organization, String license) { + PluginInfo pluginInfo = new PluginInfo(randomAlphanumeric(2)); + if (random.nextBoolean()) { + pluginInfo.setName(randomAlphanumeric(3)); + } + if (random.nextBoolean()) { + pluginInfo.setOrganizationUrl(randomAlphanumeric(4)); + } + if (random.nextBoolean()) { + pluginInfo.setIssueTrackerUrl(randomAlphanumeric(5)); + } + if (random.nextBoolean()) { + pluginInfo.setIssueTrackerUrl(randomAlphanumeric(6)); + } + if (random.nextBoolean()) { + pluginInfo.setBasePlugin(randomAlphanumeric(7)); + } + if (random.nextBoolean()) { + pluginInfo.setHomepageUrl(randomAlphanumeric(8)); + } + return pluginInfo + .setOrganizationName(organization) + .setLicense(license); + } + + private Plugin newPlugin(String organization, String license) { + Plugin plugin = Plugin.factory(randomAlphanumeric(2)); + if (random.nextBoolean()) { + plugin.setName(randomAlphanumeric(3)); + } + if (random.nextBoolean()) { + plugin.setOrganizationUrl(randomAlphanumeric(4)); + } + if (random.nextBoolean()) { + plugin.setTermsConditionsUrl(randomAlphanumeric(5)); + } + if (random.nextBoolean()) { + plugin.setIssueTrackerUrl(randomAlphanumeric(6)); + } + if (random.nextBoolean()) { + plugin.setCategory(randomAlphanumeric(7)); + } + if (random.nextBoolean()) { + plugin.setHomepageUrl(randomAlphanumeric(8)); + } + return plugin + .setLicense(license) + .setOrganization(organization); + } +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/InstalledActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/InstalledActionTest.java index 9e113765a43..7da28d8a859 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/InstalledActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/InstalledActionTest.java @@ -20,11 +20,16 @@ package org.sonar.server.plugins.ws; import com.google.common.base.Optional; +import com.tngtech.java.junit.dataprovider.DataProvider; +import com.tngtech.java.junit.dataprovider.DataProviderRunner; +import com.tngtech.java.junit.dataprovider.UseDataProvider; import java.io.File; import java.util.Arrays; +import java.util.Random; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.WebService; import org.sonar.api.server.ws.WebService.Param; @@ -47,6 +52,7 @@ import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; import static org.sonar.test.JsonAssert.assertJson; +@RunWith(DataProviderRunner.class) public class InstalledActionTest { private static final String DUMMY_CONTROLLER_KEY = "dummy"; private static final String JSON_EMPTY_PLUGIN_LIST = "{" + @@ -147,7 +153,8 @@ public class InstalledActionTest { " \"version\": \"1.0\"," + " \"license\": \"license_hey\"," + " \"organizationName\": \"org_name\"," + - " \"organizationUrl\": \"org_url\"," + + " \"organizationUrl\": \"org_url\",\n" + + " \"editionBundled\": false," + " \"homepageUrl\": \"homepage_url\"," + " \"issueTrackerUrl\": \"issueTracker_url\"," + " \"implementationBuild\": \"sou_rev_sha1\"," + @@ -203,7 +210,8 @@ public class InstalledActionTest { " \"category\":\"cat_1\"," + " \"license\": \"license_hey\"," + " \"organizationName\": \"org_name\"," + - " \"organizationUrl\": \"org_url\"," + + " \"organizationUrl\": \"org_url\",\n" + + " \"editionBundled\": false," + " \"homepageUrl\": \"homepage_url\"," + " \"issueTrackerUrl\": \"issueTracker_url\"," + " \"implementationBuild\": \"sou_rev_sha1\"" + @@ -252,6 +260,68 @@ public class InstalledActionTest { "}"); } + @Test + @UseDataProvider("editionBundledLicenseValues") + public void commercial_plugins_from_SonarSource_has_flag_editionBundled_true_based_on_jar_info(String license) throws Exception { + String jarFilename = getClass().getSimpleName() + "/" + "some.jar"; + Random random = new Random(); + String organization = random.nextBoolean() ? "SonarSource" : "SONARSOURCE"; + String pluginKey = "plugKey"; + when(pluginRepository.getPluginInfos()).thenReturn(of( + new PluginInfo(pluginKey) + .setName("plugName") + .setVersion(Version.create("1.0")) + .setLicense(license) + .setOrganizationName(organization) + .setImplementationBuild("sou_rev_sha1") + .setJarFile(new File(getClass().getResource(jarFilename).toURI())))); + db.pluginDbTester().insertPlugin( + p -> p.setKee(pluginKey), + p -> p.setFileHash("abcdplugKey"), + p -> p.setUpdatedAt(111111L)); + // ensure flag editionBundled is computed from jar info by enabling datacenter with other organization and license values + UpdateCenter updateCenter = mock(UpdateCenter.class); + when(updateCenterMatrixFactory.getUpdateCenter(false)).thenReturn(Optional.of(updateCenter)); + when(updateCenter.findAllCompatiblePlugins()).thenReturn( + singletonList( + Plugin.factory(pluginKey) + .setOrganization("foo") + .setLicense("bar") + .setCategory("cat_1"))); + + + underTest.handle(request, response); + + verifyZeroInteractions(updateCenterMatrixFactory); + assertJson(response.outputAsString()) + .isSimilarTo("{" + + " \"plugins\":" + + " [" + + " {" + + " \"key\": \"plugKey\"," + + " \"name\": \"plugName\"," + + " \"license\": \"" + license + "\"," + + " \"organizationName\": \"" + organization + "\"," + + " \"editionBundled\": true" + + " }" + + " ]" + + "}"); + } + + @DataProvider + public static Object[][] editionBundledLicenseValues() { + return new Object[][] { + {"sonarsource"}, + {"SonarSource"}, + {"SonaRSOUrce"}, + {"SONARSOURCE"}, + {"commercial"}, + {"Commercial"}, + {"COMMERCIAL"}, + {"COmmERCiaL"}, + }; + } + @Test public void only_one_plugin_can_have_a_specific_name_and_key() throws Exception { when(pluginRepository.getPluginInfos()).thenReturn(