From 24d686a58de32655ab4a324b26075f6d226767a3 Mon Sep 17 00:00:00 2001 From: Teryk Bellahsene Date: Fri, 17 Jul 2015 14:29:22 +0200 Subject: [PATCH] SONAR-6376 ws plugins/installed and plugins/pending add category field - use Optional when retrieving an UpdateCenter --- .../server/platform/ws/UpgradesAction.java | 21 +-- .../server/plugins/PluginDownloader.java | 37 ++--- .../server/plugins/UpdateCenterClient.java | 24 ++-- .../plugins/UpdateCenterMatrixFactory.java | 16 +-- .../server/plugins/ws/AvailableAction.java | 12 +- .../server/plugins/ws/InstallAction.java | 18 ++- .../server/plugins/ws/InstalledAction.java | 24 ++-- .../server/plugins/ws/PendingAction.java | 44 +++--- .../server/plugins/ws/PluginWSCommons.java | 133 ++++++++++-------- .../sonar/server/plugins/ws/UpdateAction.java | 16 ++- .../server/plugins/ws/UpdatesAction.java | 24 ++-- .../java/org/sonar/server/ui/JRubyFacade.java | 2 +- .../platform/ws/UpgradesActionTest.java | 14 +- .../server/plugins/PluginDownloaderTest.java | 20 ++- .../plugins/UpdateCenterClientTest.java | 45 +++--- ...tUpdateCenterBasedPluginsWsActionTest.java | 3 +- .../plugins/ws/AvailableActionTest.java | 20 ++- .../server/plugins/ws/InstallActionTest.java | 15 +- .../plugins/ws/InstalledActionTest.java | 34 ++++- .../server/plugins/ws/PendingActionTest.java | 32 ++++- .../plugins/ws/PluginWSCommonsTest.java | 9 +- .../server/plugins/ws/UpdateActionTest.java | 15 +- .../core/platform/PluginInfoFunctions.java | 57 ++++++++ 23 files changed, 426 insertions(+), 209 deletions(-) create mode 100644 sonar-core/src/main/java/org/sonar/core/platform/PluginInfoFunctions.java diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/ws/UpgradesAction.java b/server/sonar-server/src/main/java/org/sonar/server/platform/ws/UpgradesAction.java index 8e2edabaa89..4a77e6a6d26 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/ws/UpgradesAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/ws/UpgradesAction.java @@ -19,6 +19,7 @@ */ package org.sonar.server.platform.ws; +import com.google.common.base.Optional; import com.google.common.io.Resources; import java.util.List; import org.sonar.api.server.ws.Request; @@ -82,18 +83,22 @@ public class UpgradesAction implements SystemWsAction { private void writeResponse(JsonWriter jsonWriter) { jsonWriter.beginObject(); - UpdateCenter updateCenter = updateCenterFactory.getUpdateCenter(DO_NOT_FORCE_REFRESH); + Optional updateCenter = updateCenterFactory.getUpdateCenter(DO_NOT_FORCE_REFRESH); writeUpgrades(jsonWriter, updateCenter); - jsonWriter.propDateTime(PROPERTY_UPDATE_CENTER_REFRESH, updateCenter.getDate()); + if (updateCenter.isPresent()) { + jsonWriter.propDateTime(PROPERTY_UPDATE_CENTER_REFRESH, updateCenter.get().getDate()); + } jsonWriter.endObject(); } - private void writeUpgrades(JsonWriter jsonWriter, UpdateCenter updateCenter) { + private void writeUpgrades(JsonWriter jsonWriter, Optional updateCenter) { jsonWriter.name(ARRAY_UPGRADES).beginArray(); - for (SonarUpdate sonarUpdate : updateCenter.findSonarUpdates()) { - writeUpgrade(jsonWriter, sonarUpdate); + if (updateCenter.isPresent()) { + for (SonarUpdate sonarUpdate : updateCenter.get().findSonarUpdates()) { + writeUpgrade(jsonWriter, sonarUpdate); + } } jsonWriter.endArray(); @@ -132,7 +137,7 @@ public class UpgradesAction implements SystemWsAction { for (Release release : pluginsToUpgrade) { jsonWriter.beginObject(); - pluginWSCommons.writeMetadata(jsonWriter, (Plugin) release.getArtifact()); + pluginWSCommons.writePlugin(jsonWriter, (Plugin) release.getArtifact()); jsonWriter.prop(PROPERTY_VERSION, release.getVersion().toString()); jsonWriter.endObject(); @@ -146,9 +151,7 @@ public class UpgradesAction implements SystemWsAction { for (Plugin incompatiblePlugin : incompatiblePlugins) { jsonWriter.beginObject(); - - pluginWSCommons.writeMetadata(jsonWriter, incompatiblePlugin); - + pluginWSCommons.writePlugin(jsonWriter, incompatiblePlugin); jsonWriter.endObject(); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/PluginDownloader.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/PluginDownloader.java index 96fec742509..a164ad7bc18 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/plugins/PluginDownloader.java +++ b/server/sonar-server/src/main/java/org/sonar/server/plugins/PluginDownloader.java @@ -19,6 +19,14 @@ */ package org.sonar.server.plugins; +import com.google.common.base.Optional; +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; import org.apache.commons.io.FileUtils; import org.picocontainer.Startable; import org.sonar.api.utils.HttpDownloader; @@ -28,16 +36,9 @@ import org.sonar.api.utils.log.Loggers; import org.sonar.core.platform.PluginInfo; import org.sonar.server.platform.DefaultServerFileSystem; import org.sonar.updatecenter.common.Release; +import org.sonar.updatecenter.common.UpdateCenter; import org.sonar.updatecenter.common.Version; -import java.io.File; -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - import static com.google.common.collect.Iterables.transform; import static com.google.common.collect.Lists.newArrayList; import static org.apache.commons.io.FileUtils.cleanDirectory; @@ -120,15 +121,17 @@ public class PluginDownloader implements Startable { } public void download(String pluginKey, Version version) { - for (Release release : updateCenterMatrixFactory.getUpdateCenter(true).findInstallablePlugins(pluginKey, version)) { - try { - downloadRelease(release); - - } catch (Exception e) { - String message = String.format("Fail to download the plugin (%s, version %s) from %s (error is : %s)", - release.getArtifact().getKey(), release.getVersion().getName(), release.getDownloadUrl(), e.getMessage()); - LOG.debug(message, e); - throw new SonarException(message, e); + Optional updateCenter = updateCenterMatrixFactory.getUpdateCenter(true); + if (updateCenter.isPresent()) { + for (Release release : updateCenter.get().findInstallablePlugins(pluginKey, version)) { + try { + downloadRelease(release); + } catch (Exception e) { + String message = String.format("Fail to download the plugin (%s, version %s) from %s (error is : %s)", + release.getArtifact().getKey(), release.getVersion().getName(), release.getDownloadUrl(), e.getMessage()); + LOG.debug(message, e); + throw new SonarException(message, e); + } } } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/UpdateCenterClient.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/UpdateCenterClient.java index d4b3d164890..6d94cdeaa26 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/plugins/UpdateCenterClient.java +++ b/server/sonar-server/src/main/java/org/sonar/server/plugins/UpdateCenterClient.java @@ -19,6 +19,12 @@ */ package org.sonar.server.plugins; +import com.google.common.base.Optional; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.charset.StandardCharsets; +import java.util.Date; import org.apache.commons.io.IOUtils; import org.sonar.api.Properties; import org.sonar.api.Property; @@ -30,12 +36,6 @@ import org.sonar.updatecenter.common.UpdateCenter; import org.sonar.updatecenter.common.UpdateCenterDeserializer; import org.sonar.updatecenter.common.UpdateCenterDeserializer.Mode; -import java.io.InputStream; -import java.net.URI; -import java.net.URISyntaxException; -import java.nio.charset.StandardCharsets; -import java.util.Date; - /** * HTTP client to load data from the remote update center hosted at http://update.sonarsource.org. * @@ -68,25 +68,31 @@ public class UpdateCenterClient { private final URI uri; private final UriReader uriReader; + private final boolean isActivated; private UpdateCenter pluginCenter = null; private long lastRefreshDate = 0; public UpdateCenterClient(UriReader uriReader, Settings settings) throws URISyntaxException { this.uriReader = uriReader; this.uri = new URI(settings.getString(URL_PROPERTY)); + this.isActivated = settings.getBoolean(ACTIVATION_PROPERTY); Loggers.get(getClass()).info("Update center: " + uriReader.description(uri)); } - public UpdateCenter getUpdateCenter() { + public Optional getUpdateCenter() { return getUpdateCenter(false); } - public UpdateCenter getUpdateCenter(boolean forceRefresh) { + public Optional getUpdateCenter(boolean forceRefresh) { + if (!isActivated) { + return Optional.absent(); + } + if (pluginCenter == null || forceRefresh || needsRefresh()) { pluginCenter = init(); lastRefreshDate = System.currentTimeMillis(); } - return pluginCenter; + return Optional.fromNullable(pluginCenter); } public Date getLastRefreshDate() { diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/UpdateCenterMatrixFactory.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/UpdateCenterMatrixFactory.java index b793b88cf77..6ef445f1287 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/plugins/UpdateCenterMatrixFactory.java +++ b/server/sonar-server/src/main/java/org/sonar/server/plugins/UpdateCenterMatrixFactory.java @@ -19,6 +19,7 @@ */ package org.sonar.server.plugins; +import com.google.common.base.Optional; import org.sonar.api.platform.Server; import org.sonar.updatecenter.common.UpdateCenter; import org.sonar.updatecenter.common.Version; @@ -33,20 +34,19 @@ public class UpdateCenterMatrixFactory { private final InstalledPluginReferentialFactory installedPluginReferentialFactory; public UpdateCenterMatrixFactory(UpdateCenterClient centerClient, Server server, - InstalledPluginReferentialFactory installedPluginReferentialFactory) { + InstalledPluginReferentialFactory installedPluginReferentialFactory) { this.centerClient = centerClient; this.installedPluginReferentialFactory = installedPluginReferentialFactory; this.sonarVersion = Version.create(server.getVersion()); } - public UpdateCenter getUpdateCenter(boolean refreshUpdateCenter) { - UpdateCenter updatePluginCenter = centerClient.getUpdateCenter(refreshUpdateCenter); - if (updatePluginCenter != null) { - return updatePluginCenter.setInstalledSonarVersion(sonarVersion).registerInstalledPlugins( + public Optional getUpdateCenter(boolean refreshUpdateCenter) { + Optional updatePluginCenter = centerClient.getUpdateCenter(refreshUpdateCenter); + if (updatePluginCenter.isPresent()) { + return Optional.of(updatePluginCenter.get().setInstalledSonarVersion(sonarVersion).registerInstalledPlugins( installedPluginReferentialFactory.getInstalledPluginReferential()) - .setDate(centerClient.getLastRefreshDate()); + .setDate(centerClient.getLastRefreshDate())); } - return null; + return Optional.absent(); } } - diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/AvailableAction.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/AvailableAction.java index 1b4df7beccd..3ae4784eb91 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/AvailableAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/AvailableAction.java @@ -19,6 +19,7 @@ */ package org.sonar.server.plugins.ws; +import com.google.common.base.Optional; import com.google.common.collect.ImmutableSortedSet; import com.google.common.io.Resources; import java.util.Collection; @@ -69,20 +70,21 @@ public class AvailableAction implements PluginsWsAction { JsonWriter jsonWriter = response.newJsonWriter(); jsonWriter.beginObject(); - UpdateCenter updateCenter = updateCenterFactory.getUpdateCenter(DO_NOT_FORCE_REFRESH); + Optional updateCenter = updateCenterFactory.getUpdateCenter(DO_NOT_FORCE_REFRESH); writePlugins(jsonWriter, updateCenter); - pluginWSCommons.writeUpdateCenterProperties(jsonWriter, updateCenter); jsonWriter.endObject(); jsonWriter.close(); } - private void writePlugins(JsonWriter jsonWriter, UpdateCenter updateCenter) { + private void writePlugins(JsonWriter jsonWriter, Optional updateCenter) { jsonWriter.name(ARRAY_PLUGINS).beginArray(); - for (PluginUpdate pluginUpdate : retrieveAvailablePlugins(updateCenter)) { - pluginWSCommons.writePluginUpdate(jsonWriter, pluginUpdate); + if (updateCenter.isPresent()) { + for (PluginUpdate pluginUpdate : retrieveAvailablePlugins(updateCenter.get())) { + pluginWSCommons.writePluginUpdate(jsonWriter, pluginUpdate); + } } jsonWriter.endArray(); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/InstallAction.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/InstallAction.java index e629620df2e..32aab6c6279 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/InstallAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/InstallAction.java @@ -19,6 +19,7 @@ */ package org.sonar.server.plugins.ws; +import com.google.common.base.Optional; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; import javax.annotation.Nullable; @@ -30,6 +31,7 @@ import org.sonar.server.plugins.PluginDownloader; import org.sonar.server.plugins.UpdateCenterMatrixFactory; import org.sonar.server.user.UserSession; import org.sonar.updatecenter.common.PluginUpdate; +import org.sonar.updatecenter.common.UpdateCenter; import static java.lang.String.format; @@ -77,15 +79,21 @@ public class InstallAction implements PluginsWsAction { } private PluginUpdate findAvailablePluginByKey(String key) { - PluginUpdate pluginUpdate = Iterables.find( - updateCenterFactory.getUpdateCenter(false).findAvailablePlugins(), - hasKey(key), - MISSING_PLUGIN - ); + PluginUpdate pluginUpdate = MISSING_PLUGIN; + + Optional updateCenter = updateCenterFactory.getUpdateCenter(false); + if (updateCenter.isPresent()) { + pluginUpdate= Iterables.find( + updateCenter.get().findAvailablePlugins(), + hasKey(key), + MISSING_PLUGIN); + } + if (pluginUpdate == MISSING_PLUGIN) { throw new IllegalArgumentException( format("No plugin with key '%s' or plugin '%s' is already installed in latest version", key, key)); } + return pluginUpdate; } diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/InstalledAction.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/InstalledAction.java index 37cc7436ec4..cf7998c71c4 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/InstalledAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/InstalledAction.java @@ -19,6 +19,7 @@ */ package org.sonar.server.plugins.ws; +import com.google.common.collect.ImmutableMap; import com.google.common.io.Resources; import java.util.Collection; import java.util.SortedSet; @@ -28,9 +29,12 @@ import org.sonar.api.server.ws.WebService; import org.sonar.api.utils.text.JsonWriter; import org.sonar.core.platform.PluginInfo; import org.sonar.server.plugins.ServerPluginRepository; +import org.sonar.server.plugins.UpdateCenterMatrixFactory; +import org.sonar.updatecenter.common.Plugin; import static com.google.common.collect.ImmutableSortedSet.copyOf; import static org.sonar.server.plugins.ws.PluginWSCommons.NAME_KEY_PLUGIN_METADATA_COMPARATOR; +import static org.sonar.server.plugins.ws.PluginWSCommons.compatiblePluginsByKey; /** * Implementation of the {@code installed} action for the Plugins WebService. @@ -40,10 +44,12 @@ public class InstalledAction implements PluginsWsAction { private final ServerPluginRepository pluginRepository; private final PluginWSCommons pluginWSCommons; + private final UpdateCenterMatrixFactory updateCenterMatrixFactory; - public InstalledAction(ServerPluginRepository pluginRepository, PluginWSCommons pluginWSCommons) { + public InstalledAction(ServerPluginRepository pluginRepository, PluginWSCommons pluginWSCommons, UpdateCenterMatrixFactory updateCenterMatrixFactory) { this.pluginRepository = pluginRepository; this.pluginWSCommons = pluginWSCommons; + this.updateCenterMatrixFactory = updateCenterMatrixFactory; } @Override @@ -57,28 +63,24 @@ public class InstalledAction implements PluginsWsAction { @Override public void handle(Request request, Response response) throws Exception { - Collection infos = retrieveAndSortPluginMetadata(); + Collection pluginInfoList = searchPluginInfoList(); JsonWriter jsonWriter = response.newJsonWriter(); jsonWriter.setSerializeEmptys(false); jsonWriter.beginObject(); - writeMetadataList(jsonWriter, infos); + writePluginInfoList(jsonWriter, pluginInfoList); jsonWriter.endObject(); jsonWriter.close(); } - private SortedSet retrieveAndSortPluginMetadata() { + private SortedSet searchPluginInfoList() { return copyOf(NAME_KEY_PLUGIN_METADATA_COMPARATOR, pluginRepository.getPluginInfos()); } - private void writeMetadataList(JsonWriter jsonWriter, Collection pluginMetadatas) { - jsonWriter.name(ARRAY_PLUGINS); - jsonWriter.beginArray(); - for (PluginInfo pluginMetadata : pluginMetadatas) { - pluginWSCommons.writePluginMetadata(jsonWriter, pluginMetadata); - } - jsonWriter.endArray(); + private void writePluginInfoList(JsonWriter jsonWriter, Collection pluginInfoList) { + ImmutableMap compatiblesPluginsByKeys = compatiblePluginsByKey(updateCenterMatrixFactory); + pluginWSCommons.writePluginInfoList(jsonWriter, pluginInfoList, compatiblesPluginsByKeys, ARRAY_PLUGINS); } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/PendingAction.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/PendingAction.java index 86293e731d5..c7ea6d33a29 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/PendingAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/PendingAction.java @@ -19,6 +19,9 @@ */ package org.sonar.server.plugins.ws; +import com.google.common.collect.ImmutableMap; +import java.util.Collection; +import java.util.Map; import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; @@ -26,12 +29,11 @@ import org.sonar.api.utils.text.JsonWriter; import org.sonar.core.platform.PluginInfo; import org.sonar.server.plugins.PluginDownloader; import org.sonar.server.plugins.ServerPluginRepository; +import org.sonar.server.plugins.UpdateCenterMatrixFactory; +import org.sonar.updatecenter.common.Plugin; -import java.util.Collection; - -import static com.google.common.collect.ImmutableSortedSet.copyOf; import static com.google.common.io.Resources.getResource; -import static org.sonar.server.plugins.ws.PluginWSCommons.NAME_KEY_PLUGIN_METADATA_COMPARATOR; +import static org.sonar.server.plugins.ws.PluginWSCommons.compatiblePluginsByKey; /** * Implementation of the {@code pending} action for the Plugins WebService. @@ -44,13 +46,15 @@ public class PendingAction implements PluginsWsAction { private final PluginDownloader pluginDownloader; private final ServerPluginRepository installer; private final PluginWSCommons pluginWSCommons; + private final UpdateCenterMatrixFactory updateCenterMatrixFactory; public PendingAction(PluginDownloader pluginDownloader, - ServerPluginRepository installer, - PluginWSCommons pluginWSCommons) { + ServerPluginRepository installer, + PluginWSCommons pluginWSCommons, UpdateCenterMatrixFactory updateCenterMatrixFactory) { this.pluginDownloader = pluginDownloader; this.installer = installer; this.pluginWSCommons = pluginWSCommons; + this.updateCenterMatrixFactory = updateCenterMatrixFactory; } @Override @@ -64,36 +68,24 @@ public class PendingAction implements PluginsWsAction { @Override public void handle(Request request, Response response) throws Exception { + ImmutableMap compatiblePluginsByKey = compatiblePluginsByKey(updateCenterMatrixFactory); + JsonWriter jsonWriter = response.newJsonWriter(); jsonWriter.beginObject(); - - writeInstalling(jsonWriter); - - writeRemoving(jsonWriter); - + writeInstalling(jsonWriter, compatiblePluginsByKey); + writeRemoving(jsonWriter, compatiblePluginsByKey); jsonWriter.endObject(); jsonWriter.close(); } - private void writeInstalling(JsonWriter jsonWriter) { - jsonWriter.name(ARRAY_INSTALLING); - jsonWriter.beginArray(); + private void writeInstalling(JsonWriter json, Map compatiblePluginsByKey) { Collection plugins = pluginDownloader.getDownloadedPlugins(); - for (PluginInfo pluginMetadata : copyOf(NAME_KEY_PLUGIN_METADATA_COMPARATOR, plugins)) { - pluginWSCommons.writePluginMetadata(jsonWriter, pluginMetadata); - } - jsonWriter.endArray(); + pluginWSCommons.writePluginInfoList(json, plugins, compatiblePluginsByKey, ARRAY_INSTALLING); } - private void writeRemoving(JsonWriter jsonWriter) { - jsonWriter.name(ARRAY_REMOVING); - jsonWriter.beginArray(); + private void writeRemoving(JsonWriter json, Map compatiblePluginsByKey) { Collection plugins = installer.getUninstalledPlugins(); - for (PluginInfo pluginMetadata : copyOf(NAME_KEY_PLUGIN_METADATA_COMPARATOR, plugins)) { - pluginWSCommons.writePluginMetadata(jsonWriter, pluginMetadata); - } - jsonWriter.endArray(); + pluginWSCommons.writePluginInfoList(json, plugins, compatiblePluginsByKey, ARRAY_REMOVING); } - } 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 6c764861e38..209df136186 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 @@ -21,11 +21,19 @@ package org.sonar.server.plugins.ws; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Function; +import com.google.common.base.Optional; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; import com.google.common.collect.Ordering; +import java.util.Collections; import java.util.Comparator; +import java.util.List; +import java.util.Map; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import org.sonar.api.utils.text.JsonWriter; import org.sonar.core.platform.PluginInfo; +import org.sonar.server.plugins.UpdateCenterMatrixFactory; import org.sonar.updatecenter.common.Artifact; import org.sonar.updatecenter.common.Plugin; import org.sonar.updatecenter.common.PluginUpdate; @@ -33,9 +41,12 @@ import org.sonar.updatecenter.common.Release; import org.sonar.updatecenter.common.UpdateCenter; import org.sonar.updatecenter.common.Version; +import static com.google.common.collect.ImmutableSortedSet.copyOf; import static com.google.common.collect.Iterables.filter; import static com.google.common.collect.Iterables.transform; import static java.lang.String.CASE_INSENSITIVE_ORDER; +import static org.sonar.core.platform.PluginInfoFunctions.toKey; +import static org.sonar.core.platform.PluginInfoFunctions.toName; public class PluginWSCommons { static final String PROPERTY_KEY = "key"; @@ -61,54 +72,48 @@ public class PluginWSCommons { static final String PROPERTY_CHANGE_LOG_URL = "changeLogUrl"; public static final Ordering NAME_KEY_PLUGIN_METADATA_COMPARATOR = Ordering.natural() - .onResultOf(PluginMetadataToName.INSTANCE) - .compound(Ordering.natural().onResultOf(PluginMetadataToKey.INSTANCE)); + .onResultOf(toName()) + .compound(Ordering.natural().onResultOf(toKey())); public static final Comparator NAME_KEY_PLUGIN_ORDERING = Ordering.from(CASE_INSENSITIVE_ORDER) .onResultOf(PluginToName.INSTANCE) .compound( - Ordering.from(CASE_INSENSITIVE_ORDER).onResultOf(PluginToKey.INSTANCE) + Ordering.from(CASE_INSENSITIVE_ORDER).onResultOf(PluginToKeyFunction.INSTANCE) ); public static final Comparator NAME_KEY_PLUGIN_UPDATE_ORDERING = Ordering.from(NAME_KEY_PLUGIN_ORDERING) .onResultOf(PluginUpdateToPlugin.INSTANCE); - public void writePluginMetadata(JsonWriter jsonWriter, PluginInfo info) { - jsonWriter.beginObject(); + void writePluginInfo(JsonWriter json, PluginInfo pluginInfo, @Nullable String category) { + json.beginObject(); - writeMetadata(jsonWriter, info); - - jsonWriter.endObject(); - } - - public void writeMetadata(JsonWriter jsonWriter, PluginInfo pluginMetadata) { - jsonWriter.prop(PROPERTY_KEY, pluginMetadata.getKey()); - jsonWriter.prop(PROPERTY_NAME, pluginMetadata.getName()); - jsonWriter.prop(PROPERTY_DESCRIPTION, pluginMetadata.getDescription()); - Version version = pluginMetadata.getVersion(); + json.prop(PROPERTY_KEY, pluginInfo.getKey()); + json.prop(PROPERTY_NAME, pluginInfo.getName()); + json.prop(PROPERTY_DESCRIPTION, pluginInfo.getDescription()); + Version version = pluginInfo.getVersion(); if (version != null) { - jsonWriter.prop(PROPERTY_VERSION, version.getName()); + json.prop(PROPERTY_VERSION, version.getName()); } - jsonWriter.prop(PROPERTY_LICENSE, pluginMetadata.getLicense()); - jsonWriter.prop(PROPERTY_ORGANIZATION_NAME, pluginMetadata.getOrganizationName()); - jsonWriter.prop(PROPERTY_ORGANIZATION_URL, pluginMetadata.getOrganizationUrl()); - jsonWriter.prop(PROPERTY_HOMEPAGE_URL, pluginMetadata.getHomepageUrl()); - jsonWriter.prop(PROPERTY_ISSUE_TRACKER_URL, pluginMetadata.getIssueTrackerUrl()); - jsonWriter.prop(PROPERTY_IMPLEMENTATION_BUILD, pluginMetadata.getImplementationBuild()); + json.prop(PROPERTY_CATEGORY, category); + json.prop(PROPERTY_LICENSE, pluginInfo.getLicense()); + json.prop(PROPERTY_ORGANIZATION_NAME, pluginInfo.getOrganizationName()); + json.prop(PROPERTY_ORGANIZATION_URL, pluginInfo.getOrganizationUrl()); + json.prop(PROPERTY_HOMEPAGE_URL, pluginInfo.getHomepageUrl()); + json.prop(PROPERTY_ISSUE_TRACKER_URL, pluginInfo.getIssueTrackerUrl()); + json.prop(PROPERTY_IMPLEMENTATION_BUILD, pluginInfo.getImplementationBuild()); + + json.endObject(); } - public void writePluginUpdate(JsonWriter jsonWriter, PluginUpdate pluginUpdate) { - jsonWriter.beginObject(); - Plugin plugin = pluginUpdate.getPlugin(); - - writeMetadata(jsonWriter, plugin); - - writeRelease(jsonWriter, pluginUpdate.getRelease()); - - writeUpdate(jsonWriter, pluginUpdate); - - jsonWriter.endObject(); + public void writePluginInfoList(JsonWriter json, Iterable plugins, Map compatiblePluginsByKey, String propertyName) { + json.name(propertyName); + json.beginArray(); + for (PluginInfo pluginInfo : copyOf(NAME_KEY_PLUGIN_METADATA_COMPARATOR, plugins)) { + Plugin plugin = compatiblePluginsByKey.get(pluginInfo.getKey()); + writePluginInfo(json, pluginInfo, categoryOrNull(plugin)); + } + json.endArray(); } - public void writeMetadata(JsonWriter jsonWriter, Plugin plugin) { + public void writePlugin(JsonWriter jsonWriter, Plugin plugin) { jsonWriter.prop(PROPERTY_KEY, plugin.getKey()); jsonWriter.prop(PROPERTY_NAME, plugin.getName()); jsonWriter.prop(PROPERTY_CATEGORY, plugin.getCategory()); @@ -121,6 +126,16 @@ public class PluginWSCommons { jsonWriter.prop(PROPERTY_ISSUE_TRACKER_URL, plugin.getIssueTrackerUrl()); } + public void writePluginUpdate(JsonWriter json, PluginUpdate pluginUpdate) { + Plugin plugin = pluginUpdate.getPlugin(); + + json.beginObject(); + writePlugin(json, plugin); + writeRelease(json, pluginUpdate.getRelease()); + writeUpdate(json, pluginUpdate); + json.endObject(); + } + public void writeRelease(JsonWriter jsonWriter, Release release) { jsonWriter.name(OBJECT_RELEASE).beginObject(); @@ -214,61 +229,57 @@ public class PluginWSCommons { * "updateCenterRefresh": "2015-04-24T16:08:36+0200" * */ - public void writeUpdateCenterProperties(JsonWriter jsonWriter, UpdateCenter updateCenter) { - jsonWriter.propDateTime(PROPERTY_UPDATE_CENTER_REFRESH, updateCenter.getDate()); - } - - private enum ReleaseToArtifact implements Function { - INSTANCE; - - @Override - public Artifact apply(@Nonnull Release input) { - return input.getArtifact(); + public void writeUpdateCenterProperties(JsonWriter json, Optional updateCenter) { + if (updateCenter.isPresent()) { + json.propDateTime(PROPERTY_UPDATE_CENTER_REFRESH, updateCenter.get().getDate()); } } - private enum PluginMetadataToName implements Function { + enum PluginToKeyFunction implements Function { INSTANCE; @Override - public String apply(@Nonnull PluginInfo input) { - return input.getName(); + public String apply(@Nonnull Plugin input) { + return input.getKey(); } } - private enum PluginMetadataToKey implements Function { + private enum ReleaseToArtifact implements Function { INSTANCE; - @Override - public String apply(@Nonnull PluginInfo input) { - return input.getKey(); + public Artifact apply(@Nonnull Release input) { + return input.getArtifact(); } + } private enum PluginUpdateToPlugin implements Function { INSTANCE; - @Override public Plugin apply(@Nonnull PluginUpdate input) { return input.getPlugin(); } } - private enum PluginToKey implements Function { + private enum PluginToName implements Function { INSTANCE; - @Override public String apply(@Nonnull Plugin input) { - return input.getKey(); + return input.getName(); } } - private enum PluginToName implements Function { - INSTANCE; + static String categoryOrNull(Plugin plugin) { + return plugin != null ? plugin.getCategory() : null; + } - @Override - public String apply(@Nonnull Plugin input) { - return input.getName(); - } + private static List compatiblePlugins(UpdateCenterMatrixFactory updateCenterMatrixFactory) { + Optional updateCenter = updateCenterMatrixFactory.getUpdateCenter(false); + return updateCenter.isPresent() ? updateCenter.get().findAllCompatiblePlugins() : Collections.emptyList(); + } + + static ImmutableMap compatiblePluginsByKey(UpdateCenterMatrixFactory updateCenterMatrixFactory) { + List compatiblePlugins = compatiblePlugins(updateCenterMatrixFactory); + return Maps.uniqueIndex(compatiblePlugins, PluginToKeyFunction.INSTANCE); } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/UpdateAction.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/UpdateAction.java index 1a8a3bc78e5..24473e9ed95 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/UpdateAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/UpdateAction.java @@ -19,6 +19,7 @@ */ package org.sonar.server.plugins.ws; +import com.google.common.base.Optional; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; import org.sonar.api.server.ws.Request; @@ -32,6 +33,7 @@ import org.sonar.updatecenter.common.PluginUpdate; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import org.sonar.updatecenter.common.UpdateCenter; import static java.lang.String.format; @@ -80,11 +82,17 @@ public class UpdateAction implements PluginsWsAction { @Nonnull private PluginUpdate findPluginUpdateByKey(String key) { - PluginUpdate pluginUpdate = Iterables.find( - updateCenterFactory.getUpdateCenter(false).findPluginUpdates(), - new PluginKeyPredicate(key), - MISSING_PLUGIN + Optional updateCenter = updateCenterFactory.getUpdateCenter(false); + PluginUpdate pluginUpdate = MISSING_PLUGIN; + + if (updateCenter.isPresent()) { + pluginUpdate = Iterables.find( + updateCenter.get().findPluginUpdates(), + new PluginKeyPredicate(key), + MISSING_PLUGIN ); + } + if (pluginUpdate == MISSING_PLUGIN) { throw new IllegalArgumentException( format("No plugin with key '%s' or plugin '%s' is already in latest compatible version", key, key)); diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/UpdatesAction.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/UpdatesAction.java index 1e6014366bd..430d60cdfd9 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/UpdatesAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/UpdatesAction.java @@ -20,9 +20,13 @@ package org.sonar.server.plugins.ws; import com.google.common.base.Function; +import com.google.common.base.Optional; import com.google.common.collect.ImmutableSortedSet; import com.google.common.collect.Ordering; import com.google.common.io.Resources; +import java.util.Collection; +import java.util.List; +import javax.annotation.Nonnull; import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; @@ -33,10 +37,6 @@ import org.sonar.updatecenter.common.Plugin; import org.sonar.updatecenter.common.PluginUpdate; import org.sonar.updatecenter.common.UpdateCenter; -import javax.annotation.Nonnull; -import java.util.Collection; -import java.util.List; - /** * Implementation of the {@code updates} action for the Plugins WebService. */ @@ -60,8 +60,8 @@ public class UpdatesAction implements PluginsWsAction { private final PluginUpdateAggregator aggregator; public UpdatesAction(UpdateCenterMatrixFactory updateCenterMatrixFactory, - PluginWSCommons pluginWSCommons, - PluginUpdateAggregator aggregator) { + PluginWSCommons pluginWSCommons, + PluginUpdateAggregator aggregator) { this.updateCenterMatrixFactory = updateCenterMatrixFactory; this.pluginWSCommons = pluginWSCommons; this.aggregator = aggregator; @@ -87,7 +87,7 @@ public class UpdatesAction implements PluginsWsAction { JsonWriter jsonWriter = response.newJsonWriter(); jsonWriter.beginObject(); - UpdateCenter updateCenter = updateCenterMatrixFactory.getUpdateCenter(DO_NOT_FORCE_REFRESH); + Optional updateCenter = updateCenterMatrixFactory.getUpdateCenter(DO_NOT_FORCE_REFRESH); writePlugins(jsonWriter, updateCenter); @@ -97,11 +97,13 @@ public class UpdatesAction implements PluginsWsAction { jsonWriter.close(); } - private void writePlugins(JsonWriter jsonWriter, UpdateCenter updateCenter) { + private void writePlugins(JsonWriter jsonWriter, Optional updateCenter) { jsonWriter.name(ARRAY_PLUGINS); jsonWriter.beginArray(); - for (PluginUpdateAggregate aggregate : retrieveUpdatablePlugins(updateCenter)) { - writePluginUpdateAggregate(jsonWriter, aggregate); + if (updateCenter.isPresent()) { + for (PluginUpdateAggregate aggregate : retrieveUpdatablePlugins(updateCenter.get())) { + writePluginUpdateAggregate(jsonWriter, aggregate); + } } jsonWriter.endArray(); } @@ -110,7 +112,7 @@ public class UpdatesAction implements PluginsWsAction { jsonWriter.beginObject(); Plugin plugin = aggregate.getPlugin(); - pluginWSCommons.writeMetadata(jsonWriter, plugin); + pluginWSCommons.writePlugin(jsonWriter, plugin); writeUpdates(jsonWriter, aggregate.getUpdates()); diff --git a/server/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java b/server/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java index 404a93a8c16..cbc4aeee1a3 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java +++ b/server/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java @@ -162,7 +162,7 @@ public final class JRubyFacade { } public UpdateCenter getUpdatePluginCenter(boolean forceReload) { - return get(UpdateCenterMatrixFactory.class).getUpdateCenter(forceReload); + return get(UpdateCenterMatrixFactory.class).getUpdateCenter(forceReload).orNull(); } public PluginReferential getInstalledPluginReferential() { diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/ws/UpgradesActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/ws/UpgradesActionTest.java index 305fdab3cdd..0f9f96525c9 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/ws/UpgradesActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/platform/ws/UpgradesActionTest.java @@ -19,6 +19,7 @@ */ package org.sonar.server.platform.ws; +import com.google.common.base.Optional; import org.junit.Before; import org.junit.Test; import org.sonar.api.server.ws.Request; @@ -57,7 +58,7 @@ public class UpgradesActionTest { @Before public void wireMocks() { - when(updateCenterFactory.getUpdateCenter(anyBoolean())).thenReturn(updateCenter); + when(updateCenterFactory.getUpdateCenter(anyBoolean())).thenReturn(Optional.of(updateCenter)); when(updateCenter.getDate()).thenReturn(DateUtils.parseDateTime("2015-04-24T16:08:36+0200")); } @@ -87,6 +88,15 @@ public class UpgradesActionTest { assertJson(response.outputAsString()).setStrictArrayOrder(true).isSimilarTo(JSON_EMPTY_UPGRADE_LIST); } + @Test + public void empty_array_is_returned_when_update_center_is_unavailable() throws Exception { + when(updateCenterFactory.getUpdateCenter(anyBoolean())).thenReturn(Optional.absent()); + + underTest.handle(request, response); + + assertJson(response.outputAsString()).setStrictArrayOrder(true).isSimilarTo(JSON_EMPTY_UPGRADE_LIST); + } + @Test public void verify_JSON_response_against_example() throws Exception { SonarUpdate sonarUpdate = createSonar_51_update(); @@ -126,7 +136,7 @@ public class UpgradesActionTest { .setDescription("New overall layout, merge Issues Drilldown [...]") .setDownloadUrl("http://dist.sonar.codehaus.org/sonarqube-5.1.zip") .setChangelogUrl("http://jira.sonarsource.com/secure/ReleaseNote.jspa?projectId=11694&version=20666") - ); + ); sonarUpdate.addIncompatiblePlugin(brandingPlugin); sonarUpdate.addPluginToUpgrade(new Release(viewsPlugin, Version.create("2.8"))); diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/PluginDownloaderTest.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/PluginDownloaderTest.java index 802e6f011b1..7f78fc6c538 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/plugins/PluginDownloaderTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/plugins/PluginDownloaderTest.java @@ -19,6 +19,9 @@ */ package org.sonar.server.plugins; +import com.google.common.base.Optional; +import java.io.File; +import java.net.URI; import org.junit.After; import org.junit.Before; import org.junit.Rule; @@ -36,9 +39,6 @@ import org.sonar.updatecenter.common.Release; import org.sonar.updatecenter.common.UpdateCenter; import org.sonar.updatecenter.common.Version; -import java.io.File; -import java.net.URI; - import static com.google.common.collect.Lists.newArrayList; import static org.apache.commons.io.FileUtils.copyFileToDirectory; import static org.apache.commons.io.FileUtils.touch; @@ -70,7 +70,7 @@ public class PluginDownloaderTest { public void before() throws Exception { updateCenterMatrixFactory = mock(UpdateCenterMatrixFactory.class); updateCenter = mock(UpdateCenter.class); - when(updateCenterMatrixFactory.getUpdateCenter(anyBoolean())).thenReturn(updateCenter); + when(updateCenterMatrixFactory.getUpdateCenter(anyBoolean())).thenReturn(Optional.of(updateCenter)); httpDownloader = mock(HttpDownloader.class); doAnswer(new Answer() { @@ -124,6 +124,18 @@ public class PluginDownloaderTest { assertThat(new File(downloadDir, "test-1.0.jar.tmp")).doesNotExist(); } + @Test + public void download_when_update_center_is_unavailable_with_no_exception_thrown() { + when(updateCenterMatrixFactory.getUpdateCenter(anyBoolean())).thenReturn(Optional.absent()); + + Plugin test = new Plugin("test"); + Release test10 = new Release(test, "1.0").setDownloadUrl("http://server/test-1.0.jar"); + test.addRelease(test10); + + pluginDownloader.start(); + pluginDownloader.download("foo", create("1.0")); + } + /** * SONAR-4685 */ diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/UpdateCenterClientTest.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/UpdateCenterClientTest.java index 9d6581bb583..b6d1e32e869 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/plugins/UpdateCenterClientTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/plugins/UpdateCenterClientTest.java @@ -19,6 +19,9 @@ */ package org.sonar.server.plugins; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.charset.StandardCharsets; import org.junit.Before; import org.junit.Test; import org.sonar.api.config.Settings; @@ -27,11 +30,8 @@ import org.sonar.api.utils.UriReader; import org.sonar.updatecenter.common.UpdateCenter; import org.sonar.updatecenter.common.Version; -import java.net.URI; -import java.net.URISyntaxException; -import java.nio.charset.StandardCharsets; - import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.guava.api.Assertions.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; @@ -41,43 +41,47 @@ import static org.mockito.Mockito.when; public class UpdateCenterClientTest { - private static final String BASE_URL = "http://update.sonarsource.org"; - private UpdateCenterClient client; - private UriReader reader; + static final String BASE_URL = "http://update.sonarsource.org"; + UriReader reader; + Settings settings; + + UpdateCenterClient underTest; @Before public void startServer() throws Exception { reader = mock(UriReader.class); - Settings settings = new Settings().setProperty(UpdateCenterClient.URL_PROPERTY, BASE_URL); - client = new UpdateCenterClient(reader, settings); + settings = new Settings() + .setProperty(UpdateCenterClient.URL_PROPERTY, BASE_URL) + .setProperty(UpdateCenterClient.ACTIVATION_PROPERTY, true); + underTest = new UpdateCenterClient(reader, settings); } @Test public void downloadUpdateCenter() throws URISyntaxException { when(reader.readString(new URI(BASE_URL), StandardCharsets.UTF_8)).thenReturn("publicVersions=2.2,2.3"); - UpdateCenter plugins = client.getUpdateCenter(); + UpdateCenter plugins = underTest.getUpdateCenter().get(); verify(reader, times(1)).readString(new URI(BASE_URL), StandardCharsets.UTF_8); assertThat(plugins.getSonar().getVersions()).containsOnly(Version.create("2.2"), Version.create("2.3")); - assertThat(client.getLastRefreshDate()).isNotNull(); + assertThat(underTest.getLastRefreshDate()).isNotNull(); } @Test public void not_available_before_initialization() { - assertThat(client.getLastRefreshDate()).isNull(); + assertThat(underTest.getLastRefreshDate()).isNull(); } @Test public void ignore_connection_errors() { when(reader.readString(any(URI.class), eq(StandardCharsets.UTF_8))).thenThrow(new SonarException()); - assertThat(client.getUpdateCenter()).isNull(); + assertThat(underTest.getUpdateCenter()).isAbsent(); } @Test public void cache_data() throws Exception { when(reader.readString(new URI(BASE_URL), StandardCharsets.UTF_8)).thenReturn("sonar.versions=2.2,2.3"); - client.getUpdateCenter(); - client.getUpdateCenter(); + underTest.getUpdateCenter(); + underTest.getUpdateCenter(); verify(reader, times(1)).readString(new URI(BASE_URL), StandardCharsets.UTF_8); } @@ -86,9 +90,16 @@ public class UpdateCenterClientTest { public void forceRefresh() throws Exception { when(reader.readString(new URI(BASE_URL), StandardCharsets.UTF_8)).thenReturn("sonar.versions=2.2,2.3"); - client.getUpdateCenter(); - client.getUpdateCenter(true); + underTest.getUpdateCenter(); + underTest.getUpdateCenter(true); verify(reader, times(2)).readString(new URI(BASE_URL), StandardCharsets.UTF_8); } + + @Test + public void update_center_is_null_when_property_is_false() { + settings.setProperty(UpdateCenterClient.ACTIVATION_PROPERTY, false); + + assertThat(underTest.getUpdateCenter()).isAbsent(); + } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/AbstractUpdateCenterBasedPluginsWsActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/AbstractUpdateCenterBasedPluginsWsActionTest.java index 8d28df8418a..6bb398cfadc 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/AbstractUpdateCenterBasedPluginsWsActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/AbstractUpdateCenterBasedPluginsWsActionTest.java @@ -19,6 +19,7 @@ */ package org.sonar.server.plugins.ws; +import com.google.common.base.Optional; import org.junit.Before; import org.sonar.api.server.ws.Request; import org.sonar.api.utils.DateUtils; @@ -74,7 +75,7 @@ public abstract class AbstractUpdateCenterBasedPluginsWsActionTest { @Before public void wireMocksTogether() { - when(updateCenterFactory.getUpdateCenter(anyBoolean())).thenReturn(updateCenter); + when(updateCenterFactory.getUpdateCenter(anyBoolean())).thenReturn(Optional.of(updateCenter)); when(updateCenter.getDate()).thenReturn(DateUtils.parseDateTime("2015-04-24T16:08:36+0200")); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/AvailableActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/AvailableActionTest.java index 205c657fa45..2524a4962ce 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/AvailableActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/AvailableActionTest.java @@ -19,6 +19,7 @@ */ package org.sonar.server.plugins.ws; +import com.google.common.base.Optional; import org.junit.Test; import org.sonar.api.server.ws.WebService; import org.sonar.api.utils.DateUtils; @@ -26,9 +27,11 @@ import org.sonar.server.ws.WsTester; import org.sonar.updatecenter.common.Plugin; import org.sonar.updatecenter.common.PluginUpdate; import org.sonar.updatecenter.common.Release; +import org.sonar.updatecenter.common.UpdateCenter; import static com.google.common.collect.ImmutableList.of; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Matchers.anyBoolean; import static org.mockito.Mockito.when; import static org.sonar.test.JsonAssert.assertJson; import static org.sonar.updatecenter.common.PluginUpdate.Status.COMPATIBLE; @@ -80,11 +83,20 @@ public class AvailableActionTest extends AbstractUpdateCenterBasedPluginsWsActio assertJson(response.outputAsString()).setStrictArrayOrder(true).isSimilarTo(JSON_EMPTY_PLUGIN_LIST); } + @Test + public void empty_array_is_returned_when_update_center_is_not_accessible() throws Exception { + when(updateCenterFactory.getUpdateCenter(anyBoolean())).thenReturn(Optional.absent()); + + underTest.handle(request, response); + + assertJson(response.outputAsString()).setStrictArrayOrder(true).isSimilarTo(JSON_EMPTY_PLUGIN_LIST); + } + @Test public void verify_properties_displayed_in_json_per_plugin() throws Exception { when(updateCenter.findAvailablePlugins()).thenReturn(of( pluginUpdate(FULL_PROPERTIES_PLUGIN_RELEASE, COMPATIBLE) - )); + )); underTest.handle(request, response); @@ -114,7 +126,7 @@ public class AvailableActionTest extends AbstractUpdateCenterBasedPluginsWsActio private void checkStatusDisplayedInJson(PluginUpdate.Status status, String expectedValue) throws Exception { when(updateCenter.findAvailablePlugins()).thenReturn(of( pluginUpdate(release(PLUGIN_1, "1.0.0"), status) - )); + )); underTest.handle(request, response); @@ -128,7 +140,7 @@ public class AvailableActionTest extends AbstractUpdateCenterBasedPluginsWsActio " }" + " ]" + "}" - ); + ); } @Test @@ -139,6 +151,6 @@ public class AvailableActionTest extends AbstractUpdateCenterBasedPluginsWsActio pluginUpdate("key2", "name2"), pluginUpdate("key0", "name0"), pluginUpdate("key1", "name1") - )); + )); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/InstallActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/InstallActionTest.java index 6cac3de746d..fd4d2cd478f 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/InstallActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/InstallActionTest.java @@ -19,6 +19,7 @@ */ package org.sonar.server.plugins.ws; +import com.google.common.base.Optional; import com.google.common.collect.ImmutableList; import org.junit.Before; import org.junit.Rule; @@ -49,7 +50,7 @@ public class InstallActionTest { private static final String ACTION_KEY = "install"; private static final String KEY_PARAM = "key"; private static final String PLUGIN_KEY = "pluginKey"; - + @Rule public UserSessionRule userSessionRule = UserSessionRule.standalone(); @@ -68,7 +69,7 @@ public class InstallActionTest { @Before public void wireMocks() { - when(updateCenterFactory.getUpdateCenter(anyBoolean())).thenReturn(updateCenter); + when(updateCenterFactory.getUpdateCenter(anyBoolean())).thenReturn(Optional.of(updateCenter)); userSessionRule.setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN); } @@ -123,6 +124,16 @@ public class InstallActionTest { validRequest.execute(); } + @Test + public void IAE_is_raised_when_update_center_is_unavailable() throws Exception { + when(updateCenterFactory.getUpdateCenter(anyBoolean())).thenReturn(Optional.absent()); + + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("No plugin with key 'pluginKey'"); + + validRequest.execute(); + } + @Test public void if_plugin_is_found_available_download_is_triggered_with_latest_version_from_updatecenter() throws Exception { Version version = Version.create("1.0"); 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 2087259a96e..6e0ba04f45c 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 @@ -19,7 +19,9 @@ */ package org.sonar.server.plugins.ws; +import com.google.common.base.Optional; import java.io.File; +import java.util.Arrays; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; @@ -27,11 +29,15 @@ import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.WebService; import org.sonar.core.platform.PluginInfo; import org.sonar.server.plugins.ServerPluginRepository; +import org.sonar.server.plugins.UpdateCenterMatrixFactory; import org.sonar.server.ws.WsTester; +import org.sonar.updatecenter.common.Plugin; +import org.sonar.updatecenter.common.UpdateCenter; import org.sonar.updatecenter.common.Version; import static com.google.common.collect.ImmutableList.of; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.RETURNS_DEEP_STUBS; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.sonar.test.JsonAssert.assertJson; @@ -46,11 +52,13 @@ public class InstalledActionTest { @Rule public TemporaryFolder temp = new TemporaryFolder(); - private ServerPluginRepository pluginRepository = mock(ServerPluginRepository.class); - private InstalledAction underTest = new InstalledAction(pluginRepository, new PluginWSCommons()); + ServerPluginRepository pluginRepository = mock(ServerPluginRepository.class); + UpdateCenterMatrixFactory updateCenterMatrixFactory = mock(UpdateCenterMatrixFactory.class, RETURNS_DEEP_STUBS); - private Request request = mock(Request.class); - private WsTester.TestResponse response = new WsTester.TestResponse(); + InstalledAction underTest = new InstalledAction(pluginRepository, new PluginWSCommons(), updateCenterMatrixFactory); + + Request request = mock(Request.class); + WsTester.TestResponse response = new WsTester.TestResponse(); @Test public void action_installed_is_defined() { @@ -76,6 +84,15 @@ public class InstalledActionTest { assertJson(response.outputAsString()).setStrictArrayOrder(true).isSimilarTo(JSON_EMPTY_PLUGIN_LIST); } + @Test + public void empty_array_when_update_center_is_unavailable() throws Exception { + when(updateCenterMatrixFactory.getUpdateCenter(false)).thenReturn(Optional.absent()); + + underTest.handle(request, response); + + assertJson(response.outputAsString()).setStrictArrayOrder(true).isSimilarTo(JSON_EMPTY_PLUGIN_LIST); + } + @Test public void empty_fields_are_not_serialized_to_json() throws Exception { when(pluginRepository.getPluginInfos()).thenReturn( @@ -106,6 +123,14 @@ public class InstalledActionTest { .setJarFile(new File(getClass().getResource(jarFilename).toURI())) ) ); + UpdateCenter updateCenter = mock(UpdateCenter.class); + when(updateCenterMatrixFactory.getUpdateCenter(false)).thenReturn(Optional.of(updateCenter)); + when(updateCenter.findAllCompatiblePlugins()).thenReturn( + Arrays.asList( + new Plugin("plugKey") + .setCategory("cat_1") + ) + ); underTest.handle(request, response); @@ -118,6 +143,7 @@ public class InstalledActionTest { " \"name\": \"plugName\"," + " \"description\": \"desc_it\"," + " \"version\": \"1.0\"," + + " \"category\":\"cat_1\"," + " \"license\": \"license_hey\"," + " \"organizationName\": \"org_name\"," + " \"organizationUrl\": \"org_url\"," + diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/PendingActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/PendingActionTest.java index 143747095e8..b35c4c31c1a 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/PendingActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/PendingActionTest.java @@ -19,17 +19,23 @@ */ package org.sonar.server.plugins.ws; +import com.google.common.base.Optional; +import java.util.Arrays; import org.junit.Test; import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.WebService; import org.sonar.core.platform.PluginInfo; import org.sonar.server.plugins.PluginDownloader; import org.sonar.server.plugins.ServerPluginRepository; +import org.sonar.server.plugins.UpdateCenterMatrixFactory; import org.sonar.server.ws.WsTester; +import org.sonar.updatecenter.common.Plugin; +import org.sonar.updatecenter.common.UpdateCenter; import org.sonar.updatecenter.common.Version; import static com.google.common.collect.ImmutableList.of; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.RETURNS_DEEP_STUBS; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.sonar.test.JsonAssert.assertJson; @@ -40,7 +46,8 @@ public class PendingActionTest { PluginDownloader pluginDownloader = mock(PluginDownloader.class); ServerPluginRepository serverPluginRepository = mock(ServerPluginRepository.class); - PendingAction underTest = new PendingAction(pluginDownloader, serverPluginRepository, new PluginWSCommons()); + UpdateCenterMatrixFactory updateCenterMatrixFactory = mock(UpdateCenterMatrixFactory.class, RETURNS_DEEP_STUBS); + PendingAction underTest = new PendingAction(pluginDownloader, serverPluginRepository, new PluginWSCommons(), updateCenterMatrixFactory); Request request = mock(Request.class); WsTester.TestResponse response = new WsTester.TestResponse(); @@ -73,9 +80,31 @@ public class PendingActionTest { ); } + @Test + public void empty_arrays_are_returned_when_update_center_is_unavailable() throws Exception { + when(updateCenterMatrixFactory.getUpdateCenter(false)).thenReturn(Optional.absent()); + + underTest.handle(request, response); + + assertJson(response.outputAsString()).setStrictArrayOrder(true).isSimilarTo( + "{" + + " \"installing\": []," + + " \"removing\": []" + + "}" + ); + } + @Test public void verify_properties_displayed_in_json_per_installing_plugin() throws Exception { when(pluginDownloader.getDownloadedPlugins()).thenReturn(of(gitPluginInfo())); + UpdateCenter updateCenter = mock(UpdateCenter.class); + when(updateCenterMatrixFactory.getUpdateCenter(false)).thenReturn(Optional.of(updateCenter)); + when(updateCenter.findAllCompatiblePlugins()).thenReturn( + Arrays.asList( + new Plugin("scmgit") + .setCategory("cat_1") + ) + ); underTest.handle(request, response); @@ -89,6 +118,7 @@ public class PendingActionTest { " \"description\": \"Git SCM Provider.\"," + " \"version\": \"1.0\"," + " \"license\": \"GNU LGPL 3\"," + + " \"category\":\"cat_1\"," + " \"organizationName\": \"SonarSource\"," + " \"organizationUrl\": \"http://www.sonarsource.com\"," + " \"homepageUrl\": \"http://redirect.sonarsource.com/plugins/scmgit.html\"," + diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/PluginWSCommonsTest.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/PluginWSCommonsTest.java index 11403c59936..146115b6a4b 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/PluginWSCommonsTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/PluginWSCommonsTest.java @@ -45,7 +45,7 @@ public class PluginWSCommonsTest { @Test public void verify_properties_written_by_writePluginMetadata() { - underTest.writePluginMetadata(jsonWriter, gitPluginInfo()); + underTest.writePluginInfo(jsonWriter, gitPluginInfo(), null); jsonWriter.close(); assertJson(response.outputAsString()).setStrictArrayOrder(true).isSimilarTo("{" + @@ -63,9 +63,7 @@ public class PluginWSCommonsTest { @Test public void verify_properties_written_by_writeMetadata() { - jsonWriter.beginObject(); - underTest.writeMetadata(jsonWriter, gitPluginInfo()); - jsonWriter.endObject(); + underTest.writePluginInfo(jsonWriter, gitPluginInfo(), "cat_1"); jsonWriter.close(); assertJson(response.outputAsString()).setStrictArrayOrder(true).isSimilarTo("{" + @@ -74,6 +72,7 @@ public class PluginWSCommonsTest { " \"description\": \"Git SCM Provider.\"," + " \"version\": \"1.0\"," + " \"license\": \"GNU LGPL 3\"," + + " \"category\":\"cat_1\"" + " \"organizationName\": \"SonarSource\"," + " \"organizationUrl\": \"http://www.sonarsource.com\"," + " \"homepageUrl\": \"http://redirect.sonarsource.com/plugins/scmgit.html\"," + @@ -105,7 +104,7 @@ public class PluginWSCommonsTest { @Test public void verify_properties_written_by_writeMetadata_from_plugin() { jsonWriter.beginObject(); - underTest.writeMetadata(jsonWriter, newPlugin()); + underTest.writePlugin(jsonWriter, newPlugin()); jsonWriter.endObject(); jsonWriter.close(); diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/UpdateActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/UpdateActionTest.java index 22c8ac0fc05..4f840c72b49 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/UpdateActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/UpdateActionTest.java @@ -19,6 +19,7 @@ */ package org.sonar.server.plugins.ws; +import com.google.common.base.Optional; import com.google.common.collect.ImmutableList; import org.junit.Before; import org.junit.Rule; @@ -70,7 +71,7 @@ public class UpdateActionTest { @Before public void setUp() { - when(updateCenterFactory.getUpdateCenter(anyBoolean())).thenReturn(updateCenter); + when(updateCenterFactory.getUpdateCenter(anyBoolean())).thenReturn(Optional.of(updateCenter)); userSessionRule.setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN); } @@ -125,12 +126,22 @@ public class UpdateActionTest { underTest.handle(validRequest, response); } + @Test + public void IAE_is_raised_when_update_center_is_unavailable() throws Exception { + when(updateCenterFactory.getUpdateCenter(anyBoolean())).thenReturn(Optional.absent()); + + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("No plugin with key 'pluginKey'"); + + underTest.handle(validRequest, response); + } + @Test public void if_plugin_has_an_update_download_is_triggered_with_latest_version_from_updatecenter() throws Exception { Version version = Version.create("1.0"); when(updateCenter.findPluginUpdates()).thenReturn(ImmutableList.of( PluginUpdate.createWithStatus(new Release(new Plugin(PLUGIN_KEY), version), Status.COMPATIBLE) - )); + )); underTest.handle(validRequest, response); diff --git a/sonar-core/src/main/java/org/sonar/core/platform/PluginInfoFunctions.java b/sonar-core/src/main/java/org/sonar/core/platform/PluginInfoFunctions.java new file mode 100644 index 00000000000..c0aaea96e83 --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/platform/PluginInfoFunctions.java @@ -0,0 +1,57 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube 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.core.platform; + +import com.google.common.base.Function; +import javax.annotation.Nonnull; + +public final class PluginInfoFunctions { + + private PluginInfoFunctions() { + // utility class + } + + public static Function toName() { + return PluginInfoToName.INSTANCE; + } + + public static Function toKey() { + return PluginInfoToKey.INSTANCE; + } + + private enum PluginInfoToName implements Function { + INSTANCE; + + @Override + public String apply(@Nonnull PluginInfo input) { + return input.getName(); + } + } + + private enum PluginInfoToKey implements Function { + INSTANCE; + + @Override + public String apply(@Nonnull PluginInfo input) { + return input.getKey(); + } + } +} -- 2.39.5