aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-batch/src
diff options
context:
space:
mode:
authorSimon Brandhof <simon.brandhof@sonarsource.com>2015-12-02 11:40:43 +0100
committerSimon Brandhof <simon.brandhof@sonarsource.com>2015-12-02 14:16:49 +0100
commit92b68fdb6bca9347e153424fb4f79ceae400fc3d (patch)
tree78c7cd28e588d4f69c37575d7d84d14c0e45ec1f /sonar-batch/src
parentb4201256a7e4d8b153ecf0cb074f6e264df67f17 (diff)
downloadsonarqube-92b68fdb6bca9347e153424fb4f79ceae400fc3d.tar.gz
sonarqube-92b68fdb6bca9347e153424fb4f79ceae400fc3d.zip
ws-client should not throw HttpException by default
Diffstat (limited to 'sonar-batch/src')
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/analysis/AnalysisWSLoaderProvider.java4
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginInstaller.java9
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchWsClient.java130
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchWsClientProvider.java (renamed from sonar-batch/src/main/java/org/sonar/batch/bootstrap/WsClientProvider.java)13
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/bootstrap/GlobalContainer.java2
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/bootstrap/WsClientLoggingInterceptor.java90
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/cache/StrategyWSLoaderProvider.java4
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/cache/WSLoader.java24
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/report/ReportPublisher.java49
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/repository/DefaultProjectRepositoriesLoader.java4
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/analysis/AnalysisWSLoaderProviderTest.java26
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchPluginInstallerTest.java11
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchWsClientProviderTest.java (renamed from sonar-batch/src/test/java/org/sonar/batch/bootstrap/WsClientProviderTest.java)20
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchWsClientTest.java142
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/bootstrap/WsClientLoggingInterceptorTest.java129
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/cache/StrategyWSLoaderProviderTest.java4
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/cache/WSLoaderTest.java40
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/report/ReportPublisherTest.java36
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/repository/DefaultProjectRepositoriesLoaderTest.java4
19 files changed, 378 insertions, 363 deletions
diff --git a/sonar-batch/src/main/java/org/sonar/batch/analysis/AnalysisWSLoaderProvider.java b/sonar-batch/src/main/java/org/sonar/batch/analysis/AnalysisWSLoaderProvider.java
index 328478d3f87..7ca47ae787a 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/analysis/AnalysisWSLoaderProvider.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/analysis/AnalysisWSLoaderProvider.java
@@ -21,15 +21,15 @@ package org.sonar.batch.analysis;
import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.api.batch.AnalysisMode;
+import org.sonar.batch.bootstrap.BatchWsClient;
import org.sonar.batch.cache.WSLoader;
import org.sonar.batch.cache.WSLoader.LoadStrategy;
import org.sonar.home.cache.PersistentCache;
-import org.sonarqube.ws.client.WsClient;
public class AnalysisWSLoaderProvider extends ProviderAdapter {
private WSLoader wsLoader;
- public WSLoader provide(AnalysisMode mode, PersistentCache cache, WsClient client) {
+ public WSLoader provide(AnalysisMode mode, PersistentCache cache, BatchWsClient client) {
if (wsLoader == null) {
// recreate cache directory if needed for this analysis
cache.reconfigure();
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginInstaller.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginInstaller.java
index 56b4199e8e6..950d3e9baf3 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginInstaller.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginInstaller.java
@@ -42,7 +42,6 @@ import org.sonar.core.platform.RemotePlugin;
import org.sonar.core.platform.RemotePluginFile;
import org.sonar.home.cache.FileCache;
import org.sonarqube.ws.client.GetRequest;
-import org.sonarqube.ws.client.WsClient;
import org.sonarqube.ws.client.WsResponse;
import static java.lang.String.format;
@@ -59,9 +58,9 @@ public class BatchPluginInstaller implements PluginInstaller {
private final WSLoader wsLoader;
private final FileCache fileCache;
private final BatchPluginPredicate pluginPredicate;
- private final WsClient wsClient;
+ private final BatchWsClient wsClient;
- public BatchPluginInstaller(WSLoader wsLoader, WsClient wsClient, FileCache fileCache, BatchPluginPredicate pluginPredicate) {
+ public BatchPluginInstaller(WSLoader wsLoader, BatchWsClient wsClient, FileCache fileCache, BatchPluginPredicate pluginPredicate) {
this.wsLoader = wsLoader;
this.fileCache = fileCache;
this.pluginPredicate = pluginPredicate;
@@ -151,8 +150,8 @@ public class BatchPluginInstaller implements PluginInstaller {
LOG.info("Download {}", filename);
}
- WsResponse response = wsClient.wsConnector().call(new GetRequest(url));
- try (InputStream stream = response.getContentStream()) {
+ WsResponse response = wsClient.call(new GetRequest(url));
+ try (InputStream stream = response.contentStream()) {
FileUtils.copyInputStreamToFile(stream, toFile);
}
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchWsClient.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchWsClient.java
new file mode 100644
index 00000000000..16bac82b84f
--- /dev/null
+++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchWsClient.java
@@ -0,0 +1,130 @@
+/*
+ * 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.batch.bootstrap;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Joiner;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import java.net.HttpURLConnection;
+import java.util.ArrayList;
+import java.util.List;
+import javax.annotation.Nullable;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.utils.MessageException;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.api.utils.log.Profiler;
+import org.sonarqube.ws.client.HttpException;
+import org.sonarqube.ws.client.WsClient;
+import org.sonarqube.ws.client.WsConnector;
+import org.sonarqube.ws.client.WsRequest;
+import org.sonarqube.ws.client.WsResponse;
+
+import static java.lang.String.format;
+
+public class BatchWsClient {
+
+ private static final Logger LOG = Loggers.get(BatchWsClient.class);
+
+ private final WsClient target;
+ private final boolean hasCredentials;
+ private final String publicBaseUrl;
+
+ public BatchWsClient(WsClient target, boolean hasCredentials, @Nullable String publicBaseUrl) {
+ this.target = target;
+ this.hasCredentials = hasCredentials;
+ if (StringUtils.isBlank(publicBaseUrl)) {
+ this.publicBaseUrl = target.wsConnector().baseUrl();
+ } else {
+ this.publicBaseUrl = publicBaseUrl.replaceAll("(/)+$", "") + "/";
+ }
+ }
+
+ /**
+ * @throws IllegalStateException if the request could not be executed due to
+ * a connectivity problem or timeout. Because networks can
+ * fail during an exchange, it is possible that the remote server
+ * accepted the request before the failure
+ * @throws HttpException if the response code is not in range [200..300)
+ */
+ public WsResponse call(WsRequest request) {
+ Profiler profiler = Profiler.createIfDebug(LOG).start();
+ WsResponse response = target.wsConnector().call(request);
+ profiler.stopDebug(format("%s %d %s", request.getMethod(), response.code(), response.requestUrl()));
+ failIfUnauthorized(response);
+ return response;
+ }
+
+ public String baseUrl() {
+ return target.wsConnector().baseUrl();
+ }
+
+ /**
+ * The public URL is optionally configured on server. If not, then the regular {@link #baseUrl()} is returned.
+ * URL has a trailing slash.
+ * See https://jira.sonarsource.com/browse/SONAR-4239
+ */
+ public String publicBaseUrl() {
+ return publicBaseUrl;
+ }
+
+ @VisibleForTesting
+ WsConnector wsConnector() {
+ return target.wsConnector();
+ }
+
+ private void failIfUnauthorized(WsResponse response) {
+ if (response.code() == HttpURLConnection.HTTP_UNAUTHORIZED) {
+ if (hasCredentials) {
+ // credentials are not valid
+ throw MessageException.of(format("Not authorized. Please check the properties %s and %s.",
+ CoreProperties.LOGIN, CoreProperties.PASSWORD));
+ }
+ // not authenticated - see https://jira.sonarsource.com/browse/SONAR-4048
+ throw MessageException.of(format("Not authorized. Analyzing this project requires to be authenticated. " +
+ "Please provide the values of the properties %s and %s.", CoreProperties.LOGIN, CoreProperties.PASSWORD));
+
+ }
+ if (response.code() == HttpURLConnection.HTTP_FORBIDDEN) {
+ // SONAR-4397 Details are in response content
+ throw MessageException.of(tryParseAsJsonError(response.content()));
+ }
+ response.failIfNotSuccessful();
+ }
+
+ private static String tryParseAsJsonError(String responseContent) {
+ try {
+ JsonParser parser = new JsonParser();
+ JsonObject obj = parser.parse(responseContent).getAsJsonObject();
+ JsonArray errors = obj.getAsJsonArray("errors");
+ List<String> errorMessages = new ArrayList<>();
+ for (JsonElement e : errors) {
+ errorMessages.add(e.getAsJsonObject().get("msg").getAsString());
+ }
+ return Joiner.on(", ").join(errorMessages);
+ } catch (Exception e) {
+ return responseContent;
+ }
+ }
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/WsClientProvider.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchWsClientProvider.java
index 78e50cc2ca2..a8ac402da35 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/WsClientProvider.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchWsClientProvider.java
@@ -25,22 +25,21 @@ import org.sonar.api.batch.BatchSide;
import org.sonar.batch.bootstrapper.EnvironmentInformation;
import org.sonarqube.ws.client.HttpConnector;
import org.sonarqube.ws.client.HttpWsClient;
-import org.sonarqube.ws.client.WsClient;
import static java.lang.Integer.parseInt;
import static java.lang.String.valueOf;
import static org.apache.commons.lang.StringUtils.defaultIfBlank;
@BatchSide
-public class WsClientProvider extends ProviderAdapter {
+public class BatchWsClientProvider extends ProviderAdapter {
static final int CONNECT_TIMEOUT_MS = 5_000;
static final String READ_TIMEOUT_SEC_PROPERTY = "sonar.ws.timeout";
static final int DEFAULT_READ_TIMEOUT_SEC = 60;
- private HttpWsClient wsClient;
+ private BatchWsClient wsClient;
- public synchronized WsClient provide(final GlobalProperties settings, final EnvironmentInformation env) {
+ public synchronized BatchWsClient provide(final GlobalProperties settings, final EnvironmentInformation env) {
if (wsClient == null) {
String url = defaultIfBlank(settings.property("sonar.host.url"), CoreProperties.SERVER_BASE_URL_DEFAULT_VALUE);
HttpConnector.Builder builder = new HttpConnector.Builder();
@@ -48,15 +47,15 @@ public class WsClientProvider extends ProviderAdapter {
// TODO proxy
String timeoutSec = defaultIfBlank(settings.property(READ_TIMEOUT_SEC_PROPERTY), valueOf(DEFAULT_READ_TIMEOUT_SEC));
+ String login = defaultIfBlank(settings.property(CoreProperties.LOGIN), null);
builder
.readTimeoutMilliseconds(parseInt(timeoutSec) * 1_000)
.connectTimeoutMilliseconds(CONNECT_TIMEOUT_MS)
.userAgent(env.toString())
.url(url)
- .credentials(settings.property(CoreProperties.LOGIN), settings.property(CoreProperties.PASSWORD))
- .interceptor(new WsClientLoggingInterceptor());
+ .credentials(login, settings.property(CoreProperties.PASSWORD));
- wsClient = new HttpWsClient(builder.build());
+ wsClient = new BatchWsClient(new HttpWsClient(builder.build()), login != null, settings.property(CoreProperties.SERVER_BASE_URL));
}
return wsClient;
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/GlobalContainer.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/GlobalContainer.java
index 40b5cacb9d1..0440645b5c3 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/GlobalContainer.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/GlobalContainer.java
@@ -91,7 +91,7 @@ public class GlobalContainer extends ComponentContainer {
CachesManager.class,
GlobalSettings.class,
- new WsClientProvider(),
+ new BatchWsClientProvider(),
DefaultServer.class,
new GlobalTempFolderProvider(),
DefaultHttpDownloader.class,
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/WsClientLoggingInterceptor.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/WsClientLoggingInterceptor.java
deleted file mode 100644
index f94bf084ee9..00000000000
--- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/WsClientLoggingInterceptor.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * 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.batch.bootstrap;
-
-import com.google.common.base.Joiner;
-import com.google.gson.JsonArray;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonObject;
-import com.google.gson.JsonParser;
-import com.squareup.okhttp.Interceptor;
-import com.squareup.okhttp.Request;
-import com.squareup.okhttp.Response;
-import java.io.IOException;
-import java.net.HttpURLConnection;
-import java.util.ArrayList;
-import java.util.List;
-import org.apache.commons.lang.StringUtils;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.utils.MessageException;
-import org.sonar.api.utils.log.Logger;
-import org.sonar.api.utils.log.Loggers;
-import org.sonar.api.utils.log.Profiler;
-
-import static java.lang.String.format;
-
-public class WsClientLoggingInterceptor implements Interceptor {
-
- private static final Logger LOG = Loggers.get(WsClientLoggingInterceptor.class);
-
- @Override
- public Response intercept(Chain chain) throws IOException {
- Response response = logAndSendRequest(chain);
- if (response.code() == HttpURLConnection.HTTP_UNAUTHORIZED) {
- if (StringUtils.isBlank(response.request().header("Authorization"))) {
- // not authenticated - see https://jira.sonarsource.com/browse/SONAR-4048
- throw MessageException.of(format("Not authorized. Analyzing this project requires to be authenticated. " +
- "Please provide the values of the properties %s and %s.", CoreProperties.LOGIN, CoreProperties.PASSWORD));
- }
- // credentials are not valid
- throw MessageException.of(format("Not authorized. Please check the properties %s and %s.",
- CoreProperties.LOGIN, CoreProperties.PASSWORD));
- }
- if (response.code() == HttpURLConnection.HTTP_FORBIDDEN) {
- // SONAR-4397 Details are in response content
- throw MessageException.of(tryParseAsJsonError(response.body().string()));
- }
- return response;
- }
-
- private Response logAndSendRequest(Chain chain) throws IOException {
- Request request = chain.request();
- Response response;
- Profiler profiler = Profiler.createIfDebug(LOG).startTrace(format("%s %s", request.method(), request.url()));
- response = chain.proceed(request);
- profiler.stopDebug(format("%s %d %s", request.method(), response.code(), request.url()));
- return response;
- }
-
- private static String tryParseAsJsonError(String responseContent) {
- try {
- JsonParser parser = new JsonParser();
- JsonObject obj = parser.parse(responseContent).getAsJsonObject();
- JsonArray errors = obj.getAsJsonArray("errors");
- List<String> errorMessages = new ArrayList<>();
- for (JsonElement e : errors) {
- errorMessages.add(e.getAsJsonObject().get("msg").getAsString());
- }
- return Joiner.on(", ").join(errorMessages);
- } catch (Exception e) {
- return responseContent;
- }
- }
-}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/cache/StrategyWSLoaderProvider.java b/sonar-batch/src/main/java/org/sonar/batch/cache/StrategyWSLoaderProvider.java
index e7c573753df..e6f7d6b00cb 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/cache/StrategyWSLoaderProvider.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/cache/StrategyWSLoaderProvider.java
@@ -20,9 +20,9 @@
package org.sonar.batch.cache;
import org.picocontainer.injectors.ProviderAdapter;
+import org.sonar.batch.bootstrap.BatchWsClient;
import org.sonar.batch.cache.WSLoader.LoadStrategy;
import org.sonar.home.cache.PersistentCache;
-import org.sonarqube.ws.client.WsClient;
public class StrategyWSLoaderProvider extends ProviderAdapter {
private final LoadStrategy strategy;
@@ -32,7 +32,7 @@ public class StrategyWSLoaderProvider extends ProviderAdapter {
this.strategy = strategy;
}
- public WSLoader provide(PersistentCache cache, WsClient client) {
+ public WSLoader provide(PersistentCache cache, BatchWsClient client) {
if (wsLoader == null) {
wsLoader = new WSLoader(strategy, cache, client);
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/cache/WSLoader.java b/sonar-batch/src/main/java/org/sonar/batch/cache/WSLoader.java
index 69e7c14538f..9864e574f9b 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/cache/WSLoader.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/cache/WSLoader.java
@@ -26,12 +26,13 @@ import java.nio.charset.StandardCharsets;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.apache.commons.io.IOUtils;
+import org.sonar.api.utils.MessageException;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
+import org.sonar.batch.bootstrap.BatchWsClient;
import org.sonar.home.cache.PersistentCache;
import org.sonarqube.ws.client.GetRequest;
import org.sonarqube.ws.client.HttpException;
-import org.sonarqube.ws.client.WsClient;
import static org.sonar.batch.cache.WSLoader.ServerStatus.ACCESSIBLE;
import static org.sonar.batch.cache.WSLoader.ServerStatus.NOT_ACCESSIBLE;
@@ -50,7 +51,7 @@ public class WSLoader {
}
private final LoadStrategy defautLoadStrategy;
- private final WsClient client;
+ private final BatchWsClient wsClient;
private final PersistentCache cache;
private ServerStatus serverStatus;
@@ -58,7 +59,7 @@ public class WSLoader {
@Override
public String load(String id) throws IOException {
GetRequest getRequest = new GetRequest(id);
- try (Reader reader = client.wsConnector().call(getRequest).getContentReader()) {
+ try (Reader reader = wsClient.call(getRequest).contentReader()) {
String str = IOUtils.toString(reader);
try {
cache.put(id, str.getBytes(StandardCharsets.UTF_8));
@@ -81,7 +82,7 @@ public class WSLoader {
@Override
public InputStream load(String id) throws IOException {
GetRequest getRequest = new GetRequest(id);
- try (InputStream is = client.wsConnector().call(getRequest).getContentStream()) {
+ try (InputStream is = wsClient.call(getRequest).contentStream()) {
try {
cache.put(id, is);
} catch (IOException e) {
@@ -111,11 +112,11 @@ public class WSLoader {
}
}
- public WSLoader(LoadStrategy strategy, PersistentCache cache, WsClient client) {
+ public WSLoader(LoadStrategy strategy, PersistentCache cache, BatchWsClient wsClient) {
this.defautLoadStrategy = strategy;
this.serverStatus = UNKNOWN;
this.cache = cache;
- this.client = client;
+ this.wsClient = wsClient;
}
@Nonnull
@@ -193,7 +194,7 @@ public class WSLoader {
throw new IllegalStateException(FAIL_MSG, serverNotAvailable.getCause());
}
}
- throw new IllegalStateException("Server is not available: " + client.wsConnector().baseUrl(), serverNotAvailable.getCause());
+ throw new IllegalStateException("Server is not available: " + wsClient.baseUrl(), serverNotAvailable.getCause());
}
}
@@ -201,7 +202,6 @@ public class WSLoader {
T load(String id) throws IOException;
}
- @Nonnull
private <T> WSLoaderResult<T> loadFromCache(String id, DataLoader<T> loader) throws NotAvailableException {
T result;
@@ -217,7 +217,6 @@ public class WSLoader {
return new WSLoaderResult<>(result, true);
}
- @Nonnull
private <T> WSLoaderResult<T> loadFromServer(String id, DataLoader<T> loader) throws NotAvailableException {
if (isOffline()) {
throw new NotAvailableException("Server not available");
@@ -226,11 +225,10 @@ public class WSLoader {
T t = loader.load(id);
switchToOnline();
return new WSLoaderResult<>(t, false);
+ } catch (HttpException | MessageException e) {
+ // fail fast if it could connect but there was a application-level error
+ throw e;
} catch (IllegalStateException e) {
- if (e.getCause() instanceof HttpException) {
- // fail fast if it could connect but there was a application-level error
- throw e;
- }
switchToOffline();
throw new NotAvailableException(e);
} catch (Exception e) {
diff --git a/sonar-batch/src/main/java/org/sonar/batch/report/ReportPublisher.java b/sonar-batch/src/main/java/org/sonar/batch/report/ReportPublisher.java
index 209dd29712f..524a9a034f5 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/report/ReportPublisher.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/report/ReportPublisher.java
@@ -20,10 +20,12 @@
package org.sonar.batch.report;
import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Throwables;
import com.google.common.io.Files;
import com.squareup.okhttp.HttpUrl;
import java.io.File;
import java.io.IOException;
+import java.io.InputStream;
import java.io.Writer;
import java.net.URL;
import java.nio.charset.StandardCharsets;
@@ -42,11 +44,13 @@ import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.api.utils.text.JsonWriter;
import org.sonar.batch.analysis.DefaultAnalysisMode;
+import org.sonar.batch.bootstrap.BatchWsClient;
import org.sonar.batch.protocol.output.BatchReportWriter;
import org.sonar.batch.scan.ImmutableProjectReactor;
+import org.sonarqube.ws.MediaTypes;
import org.sonarqube.ws.WsCe;
-import org.sonarqube.ws.client.WsClient;
-import org.sonarqube.ws.client.ce.SubmitWsRequest;
+import org.sonarqube.ws.client.PostRequest;
+import org.sonarqube.ws.client.WsResponse;
import static org.apache.commons.lang.StringUtils.defaultIfBlank;
@@ -60,7 +64,7 @@ public class ReportPublisher implements Startable {
public static final String METADATA_DUMP_FILENAME = "analysis-details.json";
private final Settings settings;
- private final WsClient wsClient;
+ private final BatchWsClient wsClient;
private final AnalysisContextReportPublisher contextPublisher;
private final ImmutableProjectReactor projectReactor;
private final DefaultAnalysisMode analysisMode;
@@ -70,7 +74,7 @@ public class ReportPublisher implements Startable {
private File reportDir;
private BatchReportWriter writer;
- public ReportPublisher(Settings settings, WsClient wsClient, AnalysisContextReportPublisher contextPublisher,
+ public ReportPublisher(Settings settings, BatchWsClient wsClient, AnalysisContextReportPublisher contextPublisher,
ImmutableProjectReactor projectReactor, DefaultAnalysisMode analysisMode, TempFolder temp, ReportPublisherStep[] publishers) {
this.settings = settings;
this.wsClient = wsClient;
@@ -145,15 +149,22 @@ public class ReportPublisher implements Startable {
LOG.debug("Upload report");
long startTime = System.currentTimeMillis();
ProjectDefinition projectDefinition = projectReactor.getRoot();
- SubmitWsRequest submitRequest = new SubmitWsRequest();
- submitRequest.setProjectKey(projectDefinition.getKey());
- submitRequest.setProjectName(projectDefinition.getName());
- submitRequest.setProjectBranch(projectDefinition.getBranch());
- submitRequest.setReport(report);
- WsCe.SubmitResponse submitResponse = wsClient.computeEngine().submit(submitRequest);
- long stopTime = System.currentTimeMillis();
- LOG.info("Analysis report uploaded in " + (stopTime - startTime) + "ms");
- return submitResponse.getTaskId();
+ PostRequest.Part filePart = new PostRequest.Part(MediaTypes.ZIP, report);
+ PostRequest post = new PostRequest("api/ce/submit")
+ .setMediaType(MediaTypes.PROTOBUF)
+ .setParam("projectKey", projectDefinition.getKey())
+ .setParam("projectName", projectDefinition.getName())
+ .setParam("projectBranch", projectDefinition.getBranch())
+ .setPart("report", filePart);
+ WsResponse response = wsClient.call(post).failIfNotSuccessful();
+ try (InputStream protobuf = response.contentStream()) {
+ return WsCe.SubmitResponse.parser().parseFrom(protobuf).getTaskId();
+ } catch (Exception e) {
+ throw Throwables.propagate(e);
+ } finally {
+ long stopTime = System.currentTimeMillis();
+ LOG.info("Analysis report uploaded in " + (stopTime - startTime) + "ms");
+ }
}
@VisibleForTesting
@@ -165,13 +176,13 @@ public class ReportPublisher implements Startable {
String effectiveKey = projectReactor.getRoot().getKeyWithBranch();
metadata.put("projectKey", effectiveKey);
- URL dashboardUrl = HttpUrl.parse(publicUrl()).newBuilder()
+ URL dashboardUrl = HttpUrl.parse(wsClient.publicBaseUrl()).newBuilder()
.addPathSegment("dashboard").addPathSegment("index").addPathSegment(effectiveKey)
.build()
.url();
metadata.put("dashboardUrl", dashboardUrl.toExternalForm());
- URL taskUrl = HttpUrl.parse(publicUrl()).newBuilder()
+ URL taskUrl = HttpUrl.parse(wsClient.publicBaseUrl()).newBuilder()
.addPathSegment("api").addPathSegment("ce").addPathSegment("task")
.addQueryParameter("id", taskId)
.build()
@@ -202,12 +213,4 @@ public class ReportPublisher implements Startable {
throw new IllegalStateException("Unable to dump " + file, e);
}
}
-
- /**
- * The public URL is optionally configured on server. If not, then the regular URL is returned.
- * See https://jira.sonarsource.com/browse/SONAR-4239
- */
- private String publicUrl() {
- return defaultIfBlank(settings.getString(CoreProperties.SERVER_BASE_URL), wsClient.wsConnector().baseUrl());
- }
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/repository/DefaultProjectRepositoriesLoader.java b/sonar-batch/src/main/java/org/sonar/batch/repository/DefaultProjectRepositoriesLoader.java
index 3a00c304aaa..8168c676b8a 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/repository/DefaultProjectRepositoriesLoader.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/repository/DefaultProjectRepositoriesLoader.java
@@ -36,6 +36,7 @@ import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.mutable.MutableBoolean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.sonar.api.utils.MessageException;
import org.sonar.batch.cache.WSLoader;
import org.sonar.batch.cache.WSLoaderResult;
import org.sonar.batch.util.BatchUtils;
@@ -88,6 +89,9 @@ public class DefaultProjectRepositoriesLoader implements ProjectRepositoriesLoad
HttpException http = (HttpException) t;
return http.code() != HttpURLConnection.HTTP_NOT_FOUND;
}
+ if (t instanceof MessageException) {
+ return true;
+ }
}
return false;
diff --git a/sonar-batch/src/test/java/org/sonar/batch/analysis/AnalysisWSLoaderProviderTest.java b/sonar-batch/src/test/java/org/sonar/batch/analysis/AnalysisWSLoaderProviderTest.java
index 5687ebdc27c..b175faa6bc6 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/analysis/AnalysisWSLoaderProviderTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/analysis/AnalysisWSLoaderProviderTest.java
@@ -19,39 +19,27 @@
*/
package org.sonar.batch.analysis;
-import org.junit.Before;
import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
import org.sonar.api.batch.AnalysisMode;
+import org.sonar.batch.bootstrap.BatchWsClient;
import org.sonar.batch.cache.WSLoader;
import org.sonar.batch.cache.WSLoader.LoadStrategy;
import org.sonar.home.cache.PersistentCache;
-import org.sonarqube.ws.client.WsClient;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
public class AnalysisWSLoaderProviderTest {
- @Mock
- private PersistentCache cache;
- @Mock
- private WsClient client;
+ PersistentCache cache = mock(PersistentCache.class);
+ BatchWsClient wsClient = mock(BatchWsClient.class);
+ AnalysisMode mode = mock(AnalysisMode.class);
- @Mock
- private AnalysisMode mode;
-
- private AnalysisWSLoaderProvider loaderProvider;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- loaderProvider = new AnalysisWSLoaderProvider();
- }
+ AnalysisWSLoaderProvider underTest = new AnalysisWSLoaderProvider();
@Test
public void testDefault() {
- WSLoader loader = loaderProvider.provide(mode, cache, client);
+ WSLoader loader = underTest.provide(mode, cache, wsClient);
assertThat(loader.getDefaultStrategy()).isEqualTo(LoadStrategy.SERVER_ONLY);
}
}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchPluginInstallerTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchPluginInstallerTest.java
index fdc159569a0..0acdb08e87c 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchPluginInstallerTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchPluginInstallerTest.java
@@ -29,7 +29,6 @@ import org.sonar.batch.cache.WSLoader;
import org.sonar.batch.cache.WSLoaderResult;
import org.sonar.core.platform.RemotePlugin;
import org.sonar.home.cache.FileCache;
-import org.sonarqube.ws.client.WsClient;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Matchers.any;
@@ -47,7 +46,7 @@ public class BatchPluginInstallerTest {
public ExpectedException thrown = ExpectedException.none();
FileCache fileCache = mock(FileCache.class);
- WsClient wsClient = mock(WsClient.class);
+ BatchWsClient wsClient = mock(BatchWsClient.class);
BatchPluginPredicate pluginPredicate = mock(BatchPluginPredicate.class);
@Test
@@ -55,9 +54,9 @@ public class BatchPluginInstallerTest {
WSLoader wsLoader = mock(WSLoader.class);
when(wsLoader.loadString("/deploy/plugins/index.txt")).thenReturn(new WSLoaderResult<>("checkstyle\nsqale", true));
- BatchPluginInstaller installer = new BatchPluginInstaller(wsLoader, wsClient, fileCache, pluginPredicate);
+ BatchPluginInstaller underTest = new BatchPluginInstaller(wsLoader, wsClient, fileCache, pluginPredicate);
- List<RemotePlugin> remotePlugins = installer.listRemotePlugins();
+ List<RemotePlugin> remotePlugins = underTest.listRemotePlugins();
assertThat(remotePlugins).extracting("key").containsOnly("checkstyle", "sqale");
}
@@ -67,10 +66,10 @@ public class BatchPluginInstallerTest {
when(fileCache.get(eq("checkstyle-plugin.jar"), eq("fakemd5_1"), any(FileCache.Downloader.class))).thenReturn(pluginJar);
WSLoader wsLoader = mock(WSLoader.class);
- BatchPluginInstaller installer = new BatchPluginInstaller(wsLoader, wsClient, fileCache, pluginPredicate);
+ BatchPluginInstaller underTest = new BatchPluginInstaller(wsLoader, wsClient, fileCache, pluginPredicate);
RemotePlugin remote = new RemotePlugin("checkstyle").setFile("checkstyle-plugin.jar", "fakemd5_1");
- File file = installer.download(remote);
+ File file = underTest.download(remote);
assertThat(file).isEqualTo(pluginJar);
}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/WsClientProviderTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchWsClientProviderTest.java
index ac5a9c86683..3b19135fde0 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/WsClientProviderTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchWsClientProviderTest.java
@@ -24,33 +24,29 @@ import java.util.Map;
import org.junit.Test;
import org.sonar.batch.bootstrapper.EnvironmentInformation;
import org.sonarqube.ws.client.HttpConnector;
-import org.sonarqube.ws.client.WsClient;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.batch.bootstrap.WsClientProvider.CONNECT_TIMEOUT_MS;
-import static org.sonar.batch.bootstrap.WsClientProvider.DEFAULT_READ_TIMEOUT_SEC;
-public class WsClientProviderTest {
+public class BatchWsClientProviderTest {
- WsClientProvider underTest = new WsClientProvider();
+ BatchWsClientProvider underTest = new BatchWsClientProvider();
EnvironmentInformation env = new EnvironmentInformation("Maven Plugin", "2.3");
@Test
public void provide_client_with_default_settings() {
GlobalProperties settings = new GlobalProperties(new HashMap<String, String>());
- WsClient client = underTest.provide(settings, env);
+ BatchWsClient client = underTest.provide(settings, env);
assertThat(client).isNotNull();
+ assertThat(client.baseUrl()).isEqualTo("http://localhost:9000/");
+ assertThat(client.publicBaseUrl()).isEqualTo("http://localhost:9000/");
HttpConnector httpConnector = (HttpConnector) client.wsConnector();
assertThat(httpConnector.baseUrl()).isEqualTo("http://localhost:9000/");
assertThat(httpConnector.okHttpClient().getProxy()).isNull();
assertThat(httpConnector.okHttpClient().getConnectTimeout()).isEqualTo(5_000);
assertThat(httpConnector.okHttpClient().getReadTimeout()).isEqualTo(60_000);
assertThat(httpConnector.userAgent()).isEqualTo("Maven Plugin/2.3");
- assertThat(httpConnector.okHttpClient().interceptors())
- .hasSize(1)
- .hasOnlyElementsOfType(WsClientLoggingInterceptor.class);
}
@Test
@@ -62,7 +58,7 @@ public class WsClientProviderTest {
props.put("sonar.ws.timeout", "42");
GlobalProperties settings = new GlobalProperties(props);
- WsClient client = underTest.provide(settings, env);
+ BatchWsClient client = underTest.provide(settings, env);
assertThat(client).isNotNull();
HttpConnector httpConnector = (HttpConnector) client.wsConnector();
@@ -74,8 +70,8 @@ public class WsClientProviderTest {
@Test
public void build_singleton() {
GlobalProperties settings = new GlobalProperties(new HashMap<String, String>());
- WsClient first = underTest.provide(settings, env);
- WsClient second = underTest.provide(settings, env);
+ BatchWsClient first = underTest.provide(settings, env);
+ BatchWsClient second = underTest.provide(settings, env);
assertThat(first).isSameAs(second);
}
}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchWsClientTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchWsClientTest.java
new file mode 100644
index 00000000000..f7b9a216b7b
--- /dev/null
+++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchWsClientTest.java
@@ -0,0 +1,142 @@
+/*
+ * 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.batch.bootstrap;
+
+import java.util.List;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.mockito.Mockito;
+import org.sonar.api.utils.MessageException;
+import org.sonar.api.utils.log.LogTester;
+import org.sonar.api.utils.log.LoggerLevel;
+import org.sonarqube.ws.client.GetRequest;
+import org.sonarqube.ws.client.MockWsResponse;
+import org.sonarqube.ws.client.WsClient;
+import org.sonarqube.ws.client.WsRequest;
+import org.sonarqube.ws.client.WsResponse;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class BatchWsClientTest {
+
+ @Rule
+ public LogTester logTester = new LogTester();
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ WsClient wsClient = mock(WsClient.class, Mockito.RETURNS_DEEP_STUBS);
+
+ @Test
+ public void define_public_url() {
+ when(wsClient.wsConnector().baseUrl()).thenReturn("https://local/");
+ BatchWsClient underTest = new BatchWsClient(wsClient, true, "https://public/");
+ assertThat(underTest.baseUrl()).isEqualTo("https://local/");
+ assertThat(underTest.publicBaseUrl()).isEqualTo("https://public/");
+ }
+
+ /**
+ * Returned URL has trailing slash, even if configured URL doesn't have.
+ * That's useful for {@link com.squareup.okhttp.HttpUrl}
+ */
+ @Test
+ public void public_url_has_trailing_slash() {
+ BatchWsClient underTest = new BatchWsClient(wsClient, true, "https://public");
+ assertThat(underTest.publicBaseUrl()).isEqualTo("https://public/");
+ }
+
+
+ @Test
+ public void public_url_is_the_base_url_by_default() {
+ when(wsClient.wsConnector().baseUrl()).thenReturn("https://local/");
+ BatchWsClient underTest = new BatchWsClient(wsClient, true, null);
+ assertThat(underTest.publicBaseUrl()).isEqualTo("https://local/");
+ }
+
+ @Test
+ public void log_and_profile_request_if_debug_level() throws Exception {
+ WsRequest request = newRequest();
+ WsResponse response = newResponse().setRequestUrl("https://local/api/issues/search");
+ when(wsClient.wsConnector().call(request)).thenReturn(response);
+
+ logTester.setLevel(LoggerLevel.DEBUG);
+ BatchWsClient underTest = new BatchWsClient(wsClient, false, null);
+
+ WsResponse result = underTest.call(request);
+
+ // do not fail the execution -> interceptor returns the response
+ assertThat(result).isSameAs(response);
+
+ // check logs
+ List<String> debugLogs = logTester.logs(LoggerLevel.DEBUG);
+ assertThat(debugLogs).hasSize(1);
+ assertThat(debugLogs.get(0)).contains("GET 200 https://local/api/issues/search | time=");
+ }
+
+ @Test
+ public void fail_if_requires_credentials() throws Exception {
+ expectedException.expect(MessageException.class);
+ expectedException
+ .expectMessage("Not authorized. Analyzing this project requires to be authenticated. Please provide the values of the properties sonar.login and sonar.password.");
+
+ WsRequest request = newRequest();
+ WsResponse response = newResponse().setCode(401);
+ when(wsClient.wsConnector().call(request)).thenReturn(response);
+
+ new BatchWsClient(wsClient, false, null).call(request);
+ }
+
+ @Test
+ public void fail_if_credentials_are_not_valid() throws Exception {
+ expectedException.expect(MessageException.class);
+ expectedException.expectMessage("Not authorized. Please check the properties sonar.login and sonar.password.");
+
+ WsRequest request = newRequest();
+ WsResponse response = newResponse().setCode(401);
+ when(wsClient.wsConnector().call(request)).thenReturn(response);
+
+ new BatchWsClient(wsClient, /* credentials are configured */true, null).call(request);
+ }
+
+ @Test
+ public void fail_if_requires_permission() throws Exception {
+ expectedException.expect(MessageException.class);
+ expectedException.expectMessage("missing scan permission, missing another permission");
+
+ WsRequest request = newRequest();
+ WsResponse response = newResponse()
+ .setCode(403)
+ .setContent("{\"errors\":[{\"msg\":\"missing scan permission\"}, {\"msg\":\"missing another permission\"}]}");
+ when(wsClient.wsConnector().call(request)).thenReturn(response);
+
+ new BatchWsClient(wsClient, true, null).call(request);
+ }
+
+ private MockWsResponse newResponse() {
+ return new MockWsResponse().setRequestUrl("https://local/api/issues/search");
+ }
+
+ private WsRequest newRequest() {
+ return new GetRequest("api/issues/search");
+ }
+}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/WsClientLoggingInterceptorTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/WsClientLoggingInterceptorTest.java
deleted file mode 100644
index 4655371e88e..00000000000
--- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/WsClientLoggingInterceptorTest.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * 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.batch.bootstrap;
-
-import com.squareup.okhttp.Interceptor;
-import com.squareup.okhttp.MediaType;
-import com.squareup.okhttp.Protocol;
-import com.squareup.okhttp.Request;
-import com.squareup.okhttp.Response;
-import com.squareup.okhttp.ResponseBody;
-import java.util.List;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.sonar.api.utils.MessageException;
-import org.sonar.api.utils.log.LogTester;
-import org.sonar.api.utils.log.LoggerLevel;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class WsClientLoggingInterceptorTest {
-
- @Rule
- public LogTester logTester = new LogTester();
-
- @Rule
- public ExpectedException expectedException = ExpectedException.none();
-
- WsClientLoggingInterceptor underTest = new WsClientLoggingInterceptor();
- Interceptor.Chain chain = mock(Interceptor.Chain.class);
-
- @Test
- public void log_and_profile_request_if_debug_level() throws Exception {
- Request request = newRequest();
- Response response = newResponse(request, 200, "");
- when(chain.request()).thenReturn(request);
- when(chain.proceed(request)).thenReturn(response);
-
- logTester.setLevel(LoggerLevel.DEBUG);
- Response result = underTest.intercept(chain);
-
- // do not fail the execution -> interceptor returns the response
- assertThat(result).isSameAs(response);
-
- // check logs
- List<String> debugLogs = logTester.logs(LoggerLevel.DEBUG);
- assertThat(debugLogs).hasSize(1);
- assertThat(debugLogs.get(0)).contains("GET 200 https://localhost:9000/api/issues/search | time=");
- List<String> traceLogs = logTester.logs(LoggerLevel.TRACE);
- assertThat(traceLogs).hasSize(1);
- assertThat(traceLogs.get(0)).isEqualTo("GET https://localhost:9000/api/issues/search");
- }
-
- @Test
- public void fail_if_requires_authentication() throws Exception {
- expectedException.expect(MessageException.class);
- expectedException
- .expectMessage("Not authorized. Analyzing this project requires to be authenticated. Please provide the values of the properties sonar.login and sonar.password.");
-
- Request request = newRequest();
- Response response = newResponse(request, 401, "");
- when(chain.request()).thenReturn(request);
- when(chain.proceed(request)).thenReturn(response);
-
- underTest.intercept(chain);
- }
-
- @Test
- public void fail_if_credentials_are_not_valid() throws Exception {
- expectedException.expect(MessageException.class);
- expectedException.expectMessage("Not authorized. Please check the properties sonar.login and sonar.password.");
-
- Request request = new Request.Builder()
- .url("https://localhost:9000/api/issues/search")
- .header("Authorization", "Basic BAD_CREDENTIALS")
- .get()
- .build();
- Response response = newResponse(request, 401, "");
- when(chain.request()).thenReturn(request);
- when(chain.proceed(request)).thenReturn(response);
-
- underTest.intercept(chain);
- }
-
- @Test
- public void fail_if_requires_permission() throws Exception {
- expectedException.expect(MessageException.class);
- expectedException.expectMessage("missing scan permission, missing another permission");
-
- Request request = newRequest();
- Response response = newResponse(request, 403, "{\"errors\":[{\"msg\":\"missing scan permission\"}, {\"msg\":\"missing another permission\"}]}");
- when(chain.request()).thenReturn(request);
- when(chain.proceed(request)).thenReturn(response);
-
- underTest.intercept(chain);
- }
-
- private Request newRequest() {
- return new Request.Builder().url("https://localhost:9000/api/issues/search").get().build();
- }
-
- private Response newResponse(Request getRequest, int code, String jsonBody) {
- return new Response.Builder().request(getRequest)
- .code(code)
- .protocol(Protocol.HTTP_1_1)
- .body(ResponseBody.create(MediaType.parse("application/json"), jsonBody))
- .build();
- }
-
-}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/cache/StrategyWSLoaderProviderTest.java b/sonar-batch/src/test/java/org/sonar/batch/cache/StrategyWSLoaderProviderTest.java
index 4134b7f6653..0b36dfd3997 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/cache/StrategyWSLoaderProviderTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/cache/StrategyWSLoaderProviderTest.java
@@ -23,9 +23,9 @@ import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.sonar.batch.bootstrap.BatchWsClient;
import org.sonar.batch.cache.WSLoader.LoadStrategy;
import org.sonar.home.cache.PersistentCache;
-import org.sonarqube.ws.client.WsClient;
import static org.assertj.core.api.Assertions.assertThat;
@@ -34,7 +34,7 @@ public class StrategyWSLoaderProviderTest {
private PersistentCache cache;
@Mock
- private WsClient client;
+ private BatchWsClient client;
@Before
public void setUp() {
diff --git a/sonar-batch/src/test/java/org/sonar/batch/cache/WSLoaderTest.java b/sonar-batch/src/test/java/org/sonar/batch/cache/WSLoaderTest.java
index 2db585445f8..8b553e8eb02 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/cache/WSLoaderTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/cache/WSLoaderTest.java
@@ -28,11 +28,11 @@ import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.mockito.InOrder;
import org.mockito.Mockito;
+import org.sonar.batch.bootstrap.BatchWsClient;
import org.sonar.batch.cache.WSLoader.LoadStrategy;
import org.sonar.home.cache.PersistentCache;
import org.sonarqube.ws.client.HttpException;
import org.sonarqube.ws.client.MockWsResponse;
-import org.sonarqube.ws.client.WsClient;
import org.sonarqube.ws.client.WsConnector;
import org.sonarqube.ws.client.WsRequest;
@@ -55,7 +55,7 @@ public class WSLoaderTest {
@Rule
public ExpectedException exception = ExpectedException.none();
- WsClient ws = mock(WsClient.class, Mockito.RETURNS_DEEP_STUBS);
+ BatchWsClient ws = mock(BatchWsClient.class, Mockito.RETURNS_DEEP_STUBS);
PersistentCache cache = mock(PersistentCache.class);
@Test
@@ -88,7 +88,7 @@ public class WSLoaderTest {
public void put_stream_in_cache() throws IOException {
InputStream input = IOUtils.toInputStream("is");
- when(ws.wsConnector().call(any(WsRequest.class))).thenReturn(new MockWsResponse().setContent(input));
+ when(ws.call(any(WsRequest.class))).thenReturn(new MockWsResponse().setContent(input));
when(cache.getStream(ID)).thenReturn(input);
// SERVER_FIRST -> load from server then put to cache
@@ -96,25 +96,24 @@ public class WSLoaderTest {
WSLoaderResult<InputStream> result = underTest.loadStream(ID);
assertThat(result.get()).isEqualTo(input);
- WsConnector wsConnector = ws.wsConnector();
- InOrder inOrder = inOrder(wsConnector, cache);
- inOrder.verify(wsConnector).call(any(WsRequest.class));
+ InOrder inOrder = inOrder(ws, cache);
+ inOrder.verify(ws).call(any(WsRequest.class));
inOrder.verify(cache).put(eq(ID), any(InputStream.class));
inOrder.verify(cache).getStream(ID);
- verifyNoMoreInteractions(cache, wsConnector);
+ verifyNoMoreInteractions(cache, ws);
}
@Test
public void test_cache_strategy_fallback() throws IOException {
turnCacheEmpty();
- when(ws.wsConnector().call(any(WsRequest.class))).thenReturn(new MockWsResponse().setContent(serverValue));
+ when(ws.call(any(WsRequest.class))).thenReturn(new MockWsResponse().setContent(serverValue));
WSLoader loader = new WSLoader(LoadStrategy.CACHE_FIRST, cache, ws);
assertResult(loader.loadString(ID), serverValue, false);
- InOrder inOrder = inOrder(ws.wsConnector(), cache);
+ InOrder inOrder = inOrder(ws, cache);
inOrder.verify(cache).getString(ID);
- inOrder.verify(ws.wsConnector()).call(any(WsRequest.class));
+ inOrder.verify(ws).call(any(WsRequest.class));
}
@Test
@@ -125,14 +124,14 @@ public class WSLoaderTest {
assertResult(loader.loadString(ID), cacheValue, true);
- InOrder inOrder = inOrder(ws.wsConnector(), cache);
- inOrder.verify(ws.wsConnector()).call(any(WsRequest.class));
+ InOrder inOrder = inOrder(ws, cache);
+ inOrder.verify(ws).call(any(WsRequest.class));
inOrder.verify(cache).getString(ID);
}
@Test
public void test_put_cache() throws IOException {
- when(ws.wsConnector().call(any(WsRequest.class))).thenReturn(new MockWsResponse().setContent(serverValue));
+ when(ws.call(any(WsRequest.class))).thenReturn(new MockWsResponse().setContent(serverValue));
WSLoader loader = new WSLoader(LoadStrategy.SERVER_FIRST, cache, ws);
loader.loadString(ID);
verify(cache).put(ID, serverValue.getBytes());
@@ -171,17 +170,14 @@ public class WSLoaderTest {
@Test
public void test_throw_http_exceptions() {
- HttpException httpException = new HttpException("url", 500, "Internal Error");
- IllegalStateException wrapperException = new IllegalStateException(httpException);
-
- when(ws.wsConnector().call(any(WsRequest.class))).thenThrow(wrapperException);
+ when(ws.call(any(WsRequest.class))).thenThrow(new HttpException("url", 500));
WSLoader loader = new WSLoader(LoadStrategy.SERVER_FIRST, cache, ws);
try {
loader.loadString(ID);
fail("IllegalStateException expected");
- } catch (IllegalStateException e) {
+ } catch (HttpException e) {
// cache should not be used
verifyNoMoreInteractions(cache);
}
@@ -223,7 +219,7 @@ public class WSLoaderTest {
@Test
public void test_server_strategy() throws IOException {
- when(ws.wsConnector().call(any(WsRequest.class))).thenReturn(new MockWsResponse().setContent(serverValue));
+ when(ws.call(any(WsRequest.class))).thenReturn(new MockWsResponse().setContent(serverValue));
WSLoader loader = new WSLoader(LoadStrategy.SERVER_FIRST, cache, ws);
assertResult(loader.loadString(ID), serverValue, false);
@@ -241,7 +237,7 @@ public class WSLoaderTest {
@Test
public void test_string() {
- when(ws.wsConnector().call(any(WsRequest.class))).thenReturn(new MockWsResponse().setContent(serverValue));
+ when(ws.call(any(WsRequest.class))).thenReturn(new MockWsResponse().setContent(serverValue));
WSLoader loader = new WSLoader(LoadStrategy.SERVER_FIRST, cache, ws);
assertResult(loader.loadString(ID), serverValue, false);
}
@@ -251,7 +247,7 @@ public class WSLoaderTest {
}
private void assertUsedServer(int times) {
- verify(ws.wsConnector(), times(times)).call(any(WsRequest.class));
+ verify(ws, times(times)).call(any(WsRequest.class));
}
private void assertResult(WSLoaderResult<String> result, String expected, boolean fromCache) {
@@ -261,7 +257,7 @@ public class WSLoaderTest {
}
private void turnServerOffline() {
- when(ws.wsConnector().call(any(WsRequest.class))).thenThrow(new IllegalStateException());
+ when(ws.call(any(WsRequest.class))).thenThrow(new IllegalStateException());
}
private void turnCacheEmpty() throws IOException {
diff --git a/sonar-batch/src/test/java/org/sonar/batch/report/ReportPublisherTest.java b/sonar-batch/src/test/java/org/sonar/batch/report/ReportPublisherTest.java
index d1c5e1a93c6..dce14a13b8e 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/report/ReportPublisherTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/report/ReportPublisherTest.java
@@ -35,9 +35,9 @@ import org.sonar.api.utils.TempFolder;
import org.sonar.api.utils.log.LogTester;
import org.sonar.api.utils.log.LoggerLevel;
import org.sonar.batch.analysis.DefaultAnalysisMode;
+import org.sonar.batch.bootstrap.BatchWsClient;
import org.sonar.batch.scan.ImmutableProjectReactor;
import org.sonar.test.JsonAssert;
-import org.sonarqube.ws.client.WsClient;
import static org.apache.commons.io.FileUtils.readFileToString;
import static org.assertj.core.api.Assertions.assertThat;
@@ -54,7 +54,7 @@ public class ReportPublisherTest {
DefaultAnalysisMode mode = mock(DefaultAnalysisMode.class);
Settings settings = new Settings();
- WsClient wsClient = mock(WsClient.class, Mockito.RETURNS_DEEP_STUBS);
+ BatchWsClient wsClient = mock(BatchWsClient.class, Mockito.RETURNS_DEEP_STUBS);
ImmutableProjectReactor reactor = mock(ImmutableProjectReactor.class);
ProjectDefinition root;
AnalysisContextReportPublisher contextPublisher = mock(AnalysisContextReportPublisher.class);
@@ -63,7 +63,8 @@ public class ReportPublisherTest {
public void setUp() {
root = ProjectDefinition.create().setKey("struts").setWorkDir(temp.getRoot());
when(reactor.getRoot()).thenReturn(root);
- when(wsClient.wsConnector().baseUrl()).thenReturn("https://localhost");
+ when(wsClient.baseUrl()).thenReturn("https://localhost/");
+ when(wsClient.publicBaseUrl()).thenReturn("https://public/");
}
@Test
@@ -73,42 +74,21 @@ public class ReportPublisherTest {
underTest.logSuccess("TASK-123");
assertThat(logTester.logs(LoggerLevel.INFO))
- .contains("ANALYSIS SUCCESSFUL, you can browse https://localhost/dashboard/index/struts")
+ .contains("ANALYSIS SUCCESSFUL, you can browse https://public/dashboard/index/struts")
.contains("Note that you will be able to access the updated dashboard once the server has processed the submitted analysis report")
- .contains("More about the report processing at https://localhost/api/ce/task?id=TASK-123");
+ .contains("More about the report processing at https://public/api/ce/task?id=TASK-123");
File detailsFile = new File(temp.getRoot(), "analysis-details.json");
JsonAssert.assertJson(readFileToString(detailsFile)).isSimilarTo("{" +
"\"projectKey\": \"struts\"," +
- "\"dashboardUrl\": \"https://localhost/dashboard/index/struts\"," +
+ "\"dashboardUrl\": \"https://public/dashboard/index/struts\"," +
"\"ceTaskId\": \"TASK-123\"," +
- "\"ceTaskUrl\": \"https://localhost/api/ce/task?id=TASK-123\"" +
+ "\"ceTaskUrl\": \"https://public/api/ce/task?id=TASK-123\"" +
"}"
);
}
@Test
- public void log_public_url_if_defined() throws IOException {
- settings.setProperty(CoreProperties.SERVER_BASE_URL, "https://publicserver/sonarqube");
- ReportPublisher underTest = new ReportPublisher(settings, wsClient, contextPublisher, reactor, mode, mock(TempFolder.class), new ReportPublisherStep[0]);
-
- underTest.logSuccess("TASK-123");
-
- assertThat(logTester.logs(LoggerLevel.INFO))
- .contains("ANALYSIS SUCCESSFUL, you can browse https://publicserver/sonarqube/dashboard/index/struts")
- .contains("More about the report processing at https://publicserver/sonarqube/api/ce/task?id=TASK-123");
-
- File detailsFile = new File(temp.getRoot(), "analysis-details.json");
- JsonAssert.assertJson(readFileToString(detailsFile)).isSimilarTo("{" +
- "\"projectKey\": \"struts\"," +
- "\"dashboardUrl\": \"https://publicserver/sonarqube/dashboard/index/struts\"," +
- "\"ceTaskId\": \"TASK-123\"," +
- "\"ceTaskUrl\": \"https://publicserver/sonarqube/api/ce/task?id=TASK-123\"" +
- "}"
- );
- }
-
- @Test
public void log_but_not_dump_information_when_report_is_not_uploaded() {
ReportPublisher underTest = new ReportPublisher(settings, wsClient, contextPublisher, reactor, mode, mock(TempFolder.class), new ReportPublisherStep[0]);
diff --git a/sonar-batch/src/test/java/org/sonar/batch/repository/DefaultProjectRepositoriesLoaderTest.java b/sonar-batch/src/test/java/org/sonar/batch/repository/DefaultProjectRepositoriesLoaderTest.java
index e0eebd486d3..5d59cf28121 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/repository/DefaultProjectRepositoriesLoaderTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/repository/DefaultProjectRepositoriesLoaderTest.java
@@ -75,7 +75,7 @@ public class DefaultProjectRepositoriesLoaderTest {
@Test(expected = IllegalStateException.class)
public void failFastHttpError() {
- HttpException http = new HttpException("url", 403, "Forbidden");
+ HttpException http = new HttpException("url", 403);
IllegalStateException e = new IllegalStateException("http error", http);
when(wsLoader.loadStream(anyString())).thenThrow(e);
loader.load(PROJECT_KEY, false, null);
@@ -86,7 +86,7 @@ public class DefaultProjectRepositoriesLoaderTest {
thrown.expect(MessageException.class);
thrown.expectMessage("http error");
- HttpException http = new HttpException("uri", 403, "Forbidden");
+ HttpException http = new HttpException("uri", 403);
MessageException e = MessageException.of("http error", http);
when(wsLoader.loadStream(anyString())).thenThrow(e);
loader.load(PROJECT_KEY, false, null);