From: Simon Brandhof Date: Mon, 19 Nov 2012 17:42:05 +0000 (+0100) Subject: SONAR-3941 Improve the batch logs when unauthorized credentials X-Git-Tag: 3.4~325 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=9adcfb71589fb7d8b1520593fde26d0d5533d118;p=sonarqube.git SONAR-3941 Improve the batch logs when unauthorized credentials --- diff --git a/sonar-batch/pom.xml b/sonar-batch/pom.xml index 6e75f40ba40..29421ca58e7 100644 --- a/sonar-batch/pom.xml +++ b/sonar-batch/pom.xml @@ -78,5 +78,10 @@ sonar-testing-harness test + + org.mortbay.jetty + jetty + test + 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 e06c2f53cea..eabee747fa5 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 @@ -32,7 +32,6 @@ import org.sonar.api.utils.SonarException; import org.sonar.batch.bootstrapper.EnvironmentInformation; import java.io.File; -import java.io.IOException; import java.io.InputStream; import java.net.URI; @@ -58,6 +57,8 @@ public class ServerClient implements BatchComponent { try { InputSupplier inputSupplier = doRequest(pathStartingWithSlash); Files.copy(inputSupplier, toFile); + } catch (HttpDownloader.HttpException he) { + throw handleHttpException(he); } catch (Exception e) { throw new SonarException(String.format("Unable to download '%s' to: %s", pathStartingWithSlash, toFile), e); } @@ -67,7 +68,9 @@ public class ServerClient implements BatchComponent { InputSupplier inputSupplier = doRequest(pathStartingWithSlash); try { return IOUtils.toString(inputSupplier.getInput(), "UTF-8"); - } catch (IOException e) { + } catch (HttpDownloader.HttpException he) { + throw handleHttpException(he); + } catch (Exception e) { throw new SonarException(String.format("Unable to request: %s", pathStartingWithSlash), e); } } @@ -91,4 +94,11 @@ public class ServerClient implements BatchComponent { } } + private SonarException handleHttpException(HttpDownloader.HttpException he) { + if (he.getResponseCode() == 401) { + throw new SonarException(String.format("Not authorized. Please check the properties %s and %s.", CoreProperties.LOGIN, CoreProperties.PASSWORD)); + } + throw new SonarException(String.format("Fail to execute request [code=%s, url=%s]", he.getResponseCode(), he.getUri()), he); + } + } diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ServerClientTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ServerClientTest.java index baf74ae58c4..3a0d2dfa570 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ServerClientTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ServerClientTest.java @@ -19,9 +19,30 @@ */ package org.sonar.batch.bootstrap; +import com.google.common.base.Charsets; +import com.google.common.io.Files; +import org.apache.commons.io.IOUtils; +import org.junit.After; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.rules.TemporaryFolder; +import org.mortbay.jetty.Handler; +import org.mortbay.jetty.HttpConnection; +import org.mortbay.jetty.Request; +import org.mortbay.jetty.Server; +import org.mortbay.jetty.handler.AbstractHandler; import org.sonar.batch.bootstrapper.EnvironmentInformation; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import java.io.File; +import java.io.IOException; + +import static javax.servlet.http.HttpServletResponse.SC_OK; +import static org.apache.commons.io.IOUtils.write; import static org.fest.assertions.Assertions.assertThat; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; @@ -30,13 +51,153 @@ import static org.mockito.Mockito.when; public class ServerClientTest { + MockHttpServer server = null; + + @Rule + public TemporaryFolder temp = new TemporaryFolder(); + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @After + public void stopServer() { + if (server != null) { + server.stop(); + } + } + @Test public void shouldRemoveUrlEndingSlash() throws Exception { BootstrapSettings settings = mock(BootstrapSettings.class); when(settings.getProperty(eq("sonar.host.url"), anyString())).thenReturn("http://localhost:8080/sonar/"); - ServerClient server = new ServerClient(settings, new EnvironmentInformation("Junit", "4")); + ServerClient client = new ServerClient(settings, new EnvironmentInformation("Junit", "4")); + + assertThat(client.getURL()).isEqualTo("http://localhost:8080/sonar"); + } + + @Test + public void should_request_url() throws Exception { + server = new MockHttpServer(); + server.start(); + server.setMockResponseData("this is the content"); + + assertThat(newServerClient().request("/foo")).isEqualTo("this is the content"); + } + + @Test + public void should_download_file() throws Exception { + server = new MockHttpServer(); + server.start(); + server.setMockResponseData("this is the content"); + + File file = temp.newFile(); + newServerClient().download("/foo", file); + assertThat(Files.toString(file, Charsets.UTF_8)).isEqualTo("this is the content"); + } + + @Test + public void should_fail_if_unauthorized() throws Exception { + server = new MockHttpServer(); + server.start(); + server.setMockResponseStatus(401); + + thrown.expectMessage("Not authorized. Please check the properties sonar.login and sonar.password"); + newServerClient().request("/foo"); + } + + @Test + public void should_fail_if_error() throws Exception { + server = new MockHttpServer(); + server.start(); + server.setMockResponseStatus(500); + + thrown.expectMessage("Fail to execute request [code=500, url=http://localhost:" + server.getPort() + "/foo]"); + newServerClient().request("/foo"); + } - assertThat(server.getURL()).isEqualTo("http://localhost:8080/sonar"); + private ServerClient newServerClient() { + BootstrapSettings settings = mock(BootstrapSettings.class); + when(settings.getProperty(eq("sonar.host.url"), anyString())).thenReturn("http://localhost:" + server.getPort()); + return new ServerClient(settings, new EnvironmentInformation("Junit", "4")); } + + + static class MockHttpServer { + private Server server; + private String responseBody; + private String requestBody; + private String mockResponseData; + private int mockResponseStatus = SC_OK; + + public void start() throws Exception { + server = new Server(0); + server.setHandler(getMockHandler()); + server.start(); + } + + /** + * Creates an {@link org.mortbay.jetty.handler.AbstractHandler handler} returning an arbitrary String as a response. + * + * @return never null. + */ + public Handler getMockHandler() { + Handler handler = new AbstractHandler() { + + public void handle(String target, HttpServletRequest request, HttpServletResponse response, int dispatch) throws IOException, ServletException { + Request baseRequest = request instanceof Request ? (Request) request : HttpConnection.getCurrentConnection().getRequest(); + setResponseBody(getMockResponseData()); + setRequestBody(IOUtils.toString(baseRequest.getInputStream())); + response.setStatus(mockResponseStatus); + response.setContentType("text/xml;charset=utf-8"); + write(getResponseBody(), response.getOutputStream()); + baseRequest.setHandled(true); + } + }; + return handler; + } + + public void stop() { + try { + if (server != null) { + server.stop(); + } + } catch (Exception e) { + throw new IllegalStateException("Fail to stop HTTP server", e); + } + } + + public void setResponseBody(String responseBody) { + this.responseBody = responseBody; + } + + public String getResponseBody() { + return responseBody; + } + + public void setRequestBody(String requestBody) { + this.requestBody = requestBody; + } + + public String getRequestBody() { + return requestBody; + } + + public void setMockResponseData(String mockResponseData) { + this.mockResponseData = mockResponseData; + } + + public void setMockResponseStatus(int status) { + this.mockResponseStatus = status; + } + + public String getMockResponseData() { + return mockResponseData; + } + + public int getPort() { + return server.getConnectors()[0].getLocalPort(); + } + } + } 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 2e739d1edbe..a9bccf870ec 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 @@ -249,7 +249,7 @@ public class HttpDownloader extends UriReader.SchemeProcessor implements BatchCo } } - public static class HttpException extends IOException { + public static class HttpException extends RuntimeException { private final URI uri; private final int responseCode; diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/batch_bootstrap_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/batch_bootstrap_controller.rb index cf89bddff6b..592870aa354 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/batch_bootstrap_controller.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/batch_bootstrap_controller.rb @@ -19,7 +19,7 @@ # # Since 3.4 -class BatchBootstrapController < ApplicationController +class BatchBootstrapController < Api::ApiController # GET /batch_bootstrap/db?project= def db