From 36c0197d53bf8e712a8813a610e1faa7130b6072 Mon Sep 17 00:00:00 2001 From: Julien HENRY Date: Wed, 17 Sep 2014 11:26:32 +0200 Subject: [PATCH] SONAR-5629 Call /batch/upload_report at the end of an analysis --- .../batch/bootstrap/JdbcDriverHolder.java | 2 +- .../sonar/batch/bootstrap/ServerClient.java | 25 ++++++++---- .../sonar/batch/phases/UpdateStatusJob.java | 20 ++++++---- .../qualitygate/QualityGateProvider.java | 9 ++--- .../org/sonar/batch/scan/LastSnapshots.java | 2 +- .../batch/phases/UpdateStatusJobTest.java | 12 +++--- .../sonar/batch/scan/LastSnapshotsTest.java | 10 ++--- .../org/sonar/api/utils/HttpDownloader.java | 38 +++++++++++++++---- .../sonar/api/utils/HttpDownloaderTest.java | 7 +--- 9 files changed, 80 insertions(+), 45 deletions(-) diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/JdbcDriverHolder.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/JdbcDriverHolder.java index 99f5f028978..46720c4e224 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/JdbcDriverHolder.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/JdbcDriverHolder.java @@ -143,7 +143,7 @@ public class JdbcDriverHolder { String indexContent = serverClient.request(url); // File is empty when H2 is used if (Strings.isNullOrEmpty(indexContent)) { - return new String[]{}; + return new String[] {}; } return indexContent.split("\\|"); } catch (Exception e) { diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ServerClient.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ServerClient.java index d43ef8e0e71..86130986d1f 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ServerClient.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ServerClient.java @@ -46,6 +46,7 @@ import java.net.URI; */ public class ServerClient implements BatchComponent { + private static final String GET = "GET"; private BootstrapProperties props; private HttpDownloader.BaseHttpDownloader downloader; @@ -64,7 +65,7 @@ public class ServerClient implements BatchComponent { public void download(String pathStartingWithSlash, File toFile, @Nullable Integer readTimeoutMillis) { try { - InputSupplier inputSupplier = doRequest(pathStartingWithSlash, readTimeoutMillis); + InputSupplier inputSupplier = doRequest(pathStartingWithSlash, GET, readTimeoutMillis); Files.copy(inputSupplier, toFile); } catch (HttpDownloader.HttpException he) { throw handleHttpException(he); @@ -74,15 +75,23 @@ public class ServerClient implements BatchComponent { } public String request(String pathStartingWithSlash) { - return request(pathStartingWithSlash, true); + return request(pathStartingWithSlash, GET, true); + } + + public String request(String pathStartingWithSlash, String requestMethod) { + return request(pathStartingWithSlash, requestMethod, true); } public String request(String pathStartingWithSlash, boolean wrapHttpException) { - return request(pathStartingWithSlash, wrapHttpException, null); + return request(pathStartingWithSlash, GET, wrapHttpException, null); + } + + public String request(String pathStartingWithSlash, String requestMethod, boolean wrapHttpException) { + return request(pathStartingWithSlash, requestMethod, wrapHttpException, null); } - public String request(String pathStartingWithSlash, boolean wrapHttpException, @Nullable Integer timeoutMillis) { - InputSupplier inputSupplier = doRequest(pathStartingWithSlash, timeoutMillis); + public String request(String pathStartingWithSlash, String requestMethod, boolean wrapHttpException, @Nullable Integer timeoutMillis) { + InputSupplier inputSupplier = doRequest(pathStartingWithSlash, requestMethod, timeoutMillis); try { return IOUtils.toString(inputSupplier.getInput(), "UTF-8"); } catch (HttpDownloader.HttpException e) { @@ -92,7 +101,7 @@ public class ServerClient implements BatchComponent { } } - private InputSupplier doRequest(String pathStartingWithSlash, @Nullable Integer timeoutMillis) { + private InputSupplier doRequest(String pathStartingWithSlash, String requestMethod, @Nullable Integer timeoutMillis) { Preconditions.checkArgument(pathStartingWithSlash.startsWith("/"), "Path must start with slash /"); String path = StringEscapeUtils.escapeHtml(pathStartingWithSlash); @@ -100,9 +109,9 @@ public class ServerClient implements BatchComponent { try { InputSupplier inputSupplier; if (Strings.isNullOrEmpty(getLogin())) { - inputSupplier = downloader.newInputSupplier(uri, timeoutMillis); + inputSupplier = downloader.newInputSupplier(uri, requestMethod, timeoutMillis); } else { - inputSupplier = downloader.newInputSupplier(uri, getLogin(), getPassword(), timeoutMillis); + inputSupplier = downloader.newInputSupplier(uri, requestMethod, getLogin(), getPassword(), timeoutMillis); } return inputSupplier; } catch (Exception e) { diff --git a/sonar-batch/src/main/java/org/sonar/batch/phases/UpdateStatusJob.java b/sonar-batch/src/main/java/org/sonar/batch/phases/UpdateStatusJob.java index d3faf902b48..fabac1e31d0 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/phases/UpdateStatusJob.java +++ b/sonar-batch/src/main/java/org/sonar/batch/phases/UpdateStatusJob.java @@ -29,7 +29,6 @@ import org.sonar.api.database.DatabaseSession; import org.sonar.api.database.model.Snapshot; import org.sonar.api.resources.Project; import org.sonar.api.resources.Scopes; -import org.sonar.api.utils.SonarException; import org.sonar.batch.bootstrap.AnalysisMode; import org.sonar.batch.bootstrap.ServerClient; import org.sonar.batch.index.ResourcePersister; @@ -65,21 +64,28 @@ public class UpdateStatusJob implements BatchComponent { public void execute() { disablePreviousSnapshot(); enableCurrentSnapshot(); - evictPreviewDB(); + uploadReport(); } @VisibleForTesting - void evictPreviewDB() { + void uploadReport() { if (analysisMode.isPreview()) { - // If this is a preview analysis then we should not evict remote preview database + // If this is a preview analysis then we should not upload reports return; } String url = "/batch_bootstrap/evict?project=" + project.getId(); try { - LOG.debug("Evict preview database"); - server.request(url); + LOG.debug("Upload report"); + server.request(url, "POST"); } catch (Exception e) { - throw new SonarException("Unable to evict preview database: " + url, e); + throw new IllegalStateException("Unable to evict preview database: " + url, e); + } + url = "/batch/upload_report?project=" + project.getEffectiveKey(); + try { + LOG.debug("Publish results"); + server.request(url, "POST"); + } catch (Exception e) { + throw new IllegalStateException("Unable to publish results: " + url, e); } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/qualitygate/QualityGateProvider.java b/sonar-batch/src/main/java/org/sonar/batch/qualitygate/QualityGateProvider.java index 7294e4e668b..5333c767ee1 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/qualitygate/QualityGateProvider.java +++ b/sonar-batch/src/main/java/org/sonar/batch/qualitygate/QualityGateProvider.java @@ -36,7 +36,6 @@ import java.net.HttpURLConnection; public class QualityGateProvider extends ProviderAdapter { - private static final Logger LOG = LoggerFactory.getLogger(QualityGateProvider.class); private static final String PROPERTY_QUALITY_GATE = "sonar.qualitygate"; @@ -86,9 +85,9 @@ public class QualityGateProvider extends ProviderAdapter { String jsonText = null; try { long qGateId = Long.valueOf(qualityGateSetting); - jsonText = client.request(SHOW_URL + "?id="+qGateId, false); - } catch(NumberFormatException configIsNameInsteadOfId) { - jsonText = client.request(SHOW_URL + "?name="+qualityGateSetting, false); + jsonText = client.request(SHOW_URL + "?id=" + qGateId, false); + } catch (NumberFormatException configIsNameInsteadOfId) { + jsonText = client.request(SHOW_URL + "?name=" + qualityGateSetting, false); } JsonParser parser = new JsonParser(); @@ -97,7 +96,7 @@ public class QualityGateProvider extends ProviderAdapter { QualityGate configuredGate = new QualityGate(root.get("name").getAsString()); if (root.has(ATTRIBUTE_CONDITIONS)) { - for (JsonElement condition: root.get(ATTRIBUTE_CONDITIONS).getAsJsonArray()) { + for (JsonElement condition : root.get(ATTRIBUTE_CONDITIONS).getAsJsonArray()) { JsonObject conditionObject = condition.getAsJsonObject(); configuredGate.add(new ResolvedCondition(conditionObject, metricFinder.findByKey(conditionObject.get("metric").getAsString()))); } diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/LastSnapshots.java b/sonar-batch/src/main/java/org/sonar/batch/scan/LastSnapshots.java index f3917d40f20..3f2b0225940 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan/LastSnapshots.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/LastSnapshots.java @@ -64,7 +64,7 @@ public class LastSnapshots implements BatchComponent { private String loadSourceFromWs(Resource resource) { TimeProfiler profiler = new TimeProfiler(LOG).start("Load previous source code of: " + resource.getEffectiveKey()).setLevelToDebug(); try { - return server.request("/api/sources?resource=" + resource.getEffectiveKey() + "&format=txt", false, analysisMode.getPreviewReadTimeoutSec() * 1000); + return server.request("/api/sources?resource=" + resource.getEffectiveKey() + "&format=txt", "GET", false, analysisMode.getPreviewReadTimeoutSec() * 1000); } catch (HttpDownloader.HttpException he) { if (he.getResponseCode() == 404) { return ""; diff --git a/sonar-batch/src/test/java/org/sonar/batch/phases/UpdateStatusJobTest.java b/sonar-batch/src/test/java/org/sonar/batch/phases/UpdateStatusJobTest.java index 9768619144e..b39d4c91832 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/phases/UpdateStatusJobTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/phases/UpdateStatusJobTest.java @@ -40,6 +40,7 @@ import javax.persistence.Query; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.contains; +import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -118,19 +119,20 @@ public class UpdateStatusJobTest extends AbstractDbUnitTestCase { } @Test - public void should_evict_cache_for_regular_analysis() throws Exception { + public void should_publish_results_for_regular_analysis() throws Exception { Settings settings = new Settings(); Project project = new Project("struts"); ServerClient serverClient = mock(ServerClient.class); UpdateStatusJob job = new UpdateStatusJob(settings, serverClient, mock(DatabaseSession.class), mock(ResourcePersister.class), project, mock(Snapshot.class), mode); - job.evictPreviewDB(); - verify(serverClient).request(contains("/batch_bootstrap/evict")); + job.uploadReport(); + verify(serverClient).request(contains("/batch_bootstrap/evict"), eq("POST")); + verify(serverClient).request(contains("/batch/upload_report"), eq("POST")); } @Test - public void should_not_evict_cache_for_preview_analysis() throws Exception { + public void should_not_publish_results_for_preview_analysis() throws Exception { Settings settings = new Settings(); when(mode.isPreview()).thenReturn(true); Project project = new Project("struts"); @@ -138,7 +140,7 @@ public class UpdateStatusJobTest extends AbstractDbUnitTestCase { UpdateStatusJob job = new UpdateStatusJob(settings, serverClient, mock(DatabaseSession.class), mock(ResourcePersister.class), project, mock(Snapshot.class), mode); - job.evictPreviewDB(); + job.uploadReport(); verify(serverClient, never()).request(anyString()); } } diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/LastSnapshotsTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/LastSnapshotsTest.java index d6cddb4447d..d0624082e96 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/scan/LastSnapshotsTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/scan/LastSnapshotsTest.java @@ -79,21 +79,21 @@ public class LastSnapshotsTest extends AbstractDbUnitTestCase { public void should_download_source_from_ws_if_preview_mode() { setupData("last_snapshot"); ServerClient server = mock(ServerClient.class); - when(server.request(anyString(), eq(false), eq(30 * 1000))).thenReturn("downloaded source of Bar.c"); + when(server.request(anyString(), eq("GET"), eq(false), eq(30 * 1000))).thenReturn("downloaded source of Bar.c"); when(mode.isPreview()).thenReturn(true); LastSnapshots lastSnapshots = new LastSnapshots(mode, getSession(), server); String source = lastSnapshots.getSource(newFile()); assertThat(source).isEqualTo("downloaded source of Bar.c"); - verify(server).request("/api/sources?resource=myproject:org/foo/Bar.c&format=txt", false, 30 * 1000); + verify(server).request("/api/sources?resource=myproject:org/foo/Bar.c&format=txt", "GET", false, 30 * 1000); } @Test public void should_fail_to_download_source_from_ws() throws URISyntaxException { setupData("last_snapshot"); ServerClient server = mock(ServerClient.class); - when(server.request(anyString(), eq(false), eq(30 * 1000))).thenThrow(new HttpDownloader.HttpException(new URI(""), 500)); + when(server.request(anyString(), eq("GET"), eq(false), eq(30 * 1000))).thenThrow(new HttpDownloader.HttpException(new URI(""), 500)); when(mode.isPreview()).thenReturn(true); LastSnapshots lastSnapshots = new LastSnapshots(mode, getSession(), server); @@ -106,14 +106,14 @@ public class LastSnapshotsTest extends AbstractDbUnitTestCase { public void should_return_empty_source_if_preview_mode_and_no_last_snapshot() throws URISyntaxException { setupData("last_snapshot"); ServerClient server = mock(ServerClient.class); - when(server.request(anyString(), eq(false), eq(30 * 1000))).thenThrow(new HttpDownloader.HttpException(new URI(""), 404)); + when(server.request(anyString(), eq("GET"), eq(false), eq(30 * 1000))).thenThrow(new HttpDownloader.HttpException(new URI(""), 404)); when(mode.isPreview()).thenReturn(true); LastSnapshots lastSnapshots = new LastSnapshots(mode, getSession(), server); String source = lastSnapshots.getSource(newFile()); assertThat(source).isEqualTo(""); - verify(server).request("/api/sources?resource=myproject:org/foo/Bar.c&format=txt", false, 30 * 1000); + verify(server).request("/api/sources?resource=myproject:org/foo/Bar.c&format=txt", "GET", false, 30 * 1000); } @Test diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/utils/HttpDownloader.java b/sonar-plugin-api/src/main/java/org/sonar/api/utils/HttpDownloader.java index 02bdd7138db..562c6f48b86 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/utils/HttpDownloader.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/utils/HttpDownloader.java @@ -145,6 +145,7 @@ public class HttpDownloader extends UriReader.SchemeProcessor implements BatchCo public static class BaseHttpDownloader { + private static final String GET = "GET"; private static final String HTTP_PROXY_USER = "http.proxyUser"; private static final String HTTP_PROXY_PASSWORD = "http.proxyPassword"; @@ -167,7 +168,7 @@ public class HttpDownloader extends UriReader.SchemeProcessor implements BatchCo } private void initUserAgent(String sonarVersion) { - userAgent = (sonarVersion == null ? "Sonar" : String.format("Sonar %s", sonarVersion)); + userAgent = (sonarVersion == null ? "SonarQube" : String.format("SonarQube %s", sonarVersion)); System.setProperty("http.agent", userAgent); } @@ -211,25 +212,43 @@ public class HttpDownloader extends UriReader.SchemeProcessor implements BatchCo } public InputSupplier newInputSupplier(URI uri) { - return new HttpInputSupplier(uri, userAgent, null, null, TIMEOUT_MILLISECONDS); + return new HttpInputSupplier(uri, GET, userAgent, null, null, TIMEOUT_MILLISECONDS); } public InputSupplier newInputSupplier(URI uri, @Nullable Integer readTimeoutMillis) { + return newInputSupplier(uri, GET, readTimeoutMillis); + } + + public InputSupplier newInputSupplier(URI uri, String requestMethod, @Nullable Integer readTimeoutMillis) { if (readTimeoutMillis != null) { - return new HttpInputSupplier(uri, userAgent, null, null, readTimeoutMillis); + return new HttpInputSupplier(uri, requestMethod, userAgent, null, null, readTimeoutMillis); } - return new HttpInputSupplier(uri, userAgent, null, null, TIMEOUT_MILLISECONDS); + return new HttpInputSupplier(uri, requestMethod, userAgent, null, null, TIMEOUT_MILLISECONDS); } public InputSupplier newInputSupplier(URI uri, String login, String password) { - return new HttpInputSupplier(uri, userAgent, login, password, TIMEOUT_MILLISECONDS); + return newInputSupplier(uri, GET, login, password); + } + + /** + * @since 5.0 + */ + public InputSupplier newInputSupplier(URI uri, String requestMethod, String login, String password) { + return new HttpInputSupplier(uri, requestMethod, userAgent, login, password, TIMEOUT_MILLISECONDS); } public InputSupplier newInputSupplier(URI uri, String login, String password, @Nullable Integer readTimeoutMillis) { + return newInputSupplier(uri, GET, login, password, readTimeoutMillis); + } + + /** + * @since 5.0 + */ + public InputSupplier newInputSupplier(URI uri, String requestMethod, String login, String password, @Nullable Integer readTimeoutMillis) { if (readTimeoutMillis != null) { - return new HttpInputSupplier(uri, userAgent, login, password, readTimeoutMillis); + return new HttpInputSupplier(uri, requestMethod, userAgent, login, password, readTimeoutMillis); } - return new HttpInputSupplier(uri, userAgent, login, password, TIMEOUT_MILLISECONDS); + return new HttpInputSupplier(uri, requestMethod, userAgent, login, password, TIMEOUT_MILLISECONDS); } private static class HttpInputSupplier implements InputSupplier { @@ -238,9 +257,11 @@ public class HttpDownloader extends UriReader.SchemeProcessor implements BatchCo private final URI uri; private final String userAgent; private final int readTimeoutMillis; + private final String requestMethod; - HttpInputSupplier(URI uri, String userAgent, String login, String password, int readTimeoutMillis) { + HttpInputSupplier(URI uri, String requestMethod, String userAgent, String login, String password, int readTimeoutMillis) { this.uri = uri; + this.requestMethod = requestMethod; this.userAgent = userAgent; this.login = login; this.password = password; @@ -251,6 +272,7 @@ public class HttpDownloader extends UriReader.SchemeProcessor implements BatchCo LoggerFactory.getLogger(getClass()).debug("Download: " + uri + " (" + getProxySynthesis(uri, ProxySelector.getDefault()) + ")"); HttpURLConnection connection = (HttpURLConnection) uri.toURL().openConnection(); + connection.setRequestMethod(requestMethod); HttpsTrust.INSTANCE.trust(connection); // allow both GZip and Deflate (ZLib) encodings diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/utils/HttpDownloaderTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/utils/HttpDownloaderTest.java index 79d44b9588e..5978438e8c6 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/utils/HttpDownloaderTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/utils/HttpDownloaderTest.java @@ -149,14 +149,11 @@ public class HttpDownloaderTest { thrown.expect(new BaseMatcher() { @Override public boolean matches(Object ex) { - // TODO Auto-generated method stub return ex instanceof SonarException && ((SonarException) ex).getCause() instanceof SocketTimeoutException; } @Override public void describeTo(Description arg0) { - // TODO Auto-generated method stub - } }); new HttpDownloader(new Settings(), 100).readString(new URI(baseUrl + "/timeout/"), Charsets.UTF_8); @@ -201,7 +198,7 @@ public class HttpDownloaderTest { props.load(stream); stream.close(); - assertThat(props.getProperty("agent")).isEqualTo("Sonar 2.2"); + assertThat(props.getProperty("agent")).isEqualTo("SonarQube 2.2"); } @Test @@ -220,7 +217,7 @@ public class HttpDownloaderTest { @Test public void shouldGetProxySynthesis() throws URISyntaxException { ProxySelector proxySelector = mock(ProxySelector.class); - when(proxySelector.select(any(URI.class))).thenReturn(Arrays. asList(new FakeProxy())); + when(proxySelector.select(any(URI.class))).thenReturn(Arrays.asList(new FakeProxy())); assertThat(HttpDownloader.BaseHttpDownloader.getProxySynthesis(new URI("http://an_url"), proxySelector)).isEqualTo("proxy: http://proxy_url:4040"); } -- 2.39.5