]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-5383 improve SonarClient#get() and #post()
authorSimon Brandhof <simon.brandhof@sonarsource.com>
Mon, 25 Aug 2014 17:51:23 +0000 (19:51 +0200)
committerSimon Brandhof <simon.brandhof@sonarsource.com>
Mon, 25 Aug 2014 17:51:52 +0000 (19:51 +0200)
* add helpful get(String relativeUrl, Object... params) and post(String relativeUrl, Object... params)
* support relativeUrl that does not start with slash /

server/sonar-ws-client/src/main/java/org/sonar/wsclient/SonarClient.java
server/sonar-ws-client/src/main/java/org/sonar/wsclient/internal/HttpRequestFactory.java
server/sonar-ws-client/src/main/java/org/sonar/wsclient/project/internal/DefaultProjectClient.java
server/sonar-ws-client/src/test/java/org/sonar/wsclient/SonarClientTest.java
server/sonar-ws-client/src/test/java/org/sonar/wsclient/internal/HttpRequestFactoryTest.java

index 06ae374c2d744b107ea22ec322a53002b4d5498e..bd97afb9ad405faa4e39e1b60924ffb763fc6942 100644 (file)
@@ -39,6 +39,8 @@ import org.sonar.wsclient.user.internal.DefaultUserClient;
 
 import javax.annotation.Nullable;
 
+import java.util.Arrays;
+import java.util.HashMap;
 import java.util.Map;
 
 /**
@@ -63,7 +65,7 @@ public class SonarClient {
   final HttpRequestFactory requestFactory;
 
   private SonarClient(Builder builder) {
-    requestFactory = new HttpRequestFactory(builder.url)
+    this(new HttpRequestFactory(builder.url)
       .setLogin(builder.login)
       .setPassword(builder.password)
       .setProxyHost(builder.proxyHost)
@@ -71,7 +73,14 @@ public class SonarClient {
       .setProxyLogin(builder.proxyLogin)
       .setProxyPassword(builder.proxyPassword)
       .setConnectTimeoutInMilliseconds(builder.connectTimeoutMs)
-      .setReadTimeoutInMilliseconds(builder.readTimeoutMs);
+      .setReadTimeoutInMilliseconds(builder.readTimeoutMs));
+  }
+
+  /**
+   * Visible for testing
+   */
+  SonarClient(HttpRequestFactory requestFactory) {
+    this.requestFactory = requestFactory;
   }
 
   /**
@@ -117,7 +126,7 @@ public class SonarClient {
   }
 
   /**
-   * New client to interact with web services related to quality profilesgates
+   * New client to interact with web services related to quality profiles
    */
   public QProfileClient qProfileClient() {
     return new DefaultQProfileClient(requestFactory);
@@ -143,7 +152,15 @@ public class SonarClient {
   }
 
   /**
-   * Send a POST request on the given relativeUrl, with provided parameters (can be empty)
+   * Send a POST request on the given relativeUrl, with provided parameters (can be empty).
+   * The beginning slash (/) of relativeUrl is supported but not mandatory.
+   * <p/>
+   * Example:
+   * <pre>  {@code
+   *   Map<String,Object> params = new HashMap<>();
+   *   params.put("name", "My Quality Gate");
+   *   client.post("api/qualitygates/create", params);
+   * }</pre>
    * @since 4.5
    * @return the response body
    */
@@ -152,7 +169,16 @@ public class SonarClient {
   }
 
   /**
-   * Send a GET request on the given relativeUrl, with provided parameters (can be empty)
+   * Same as {@link #post(String, java.util.Map)} but parameters are defined as an array
+   * of even number of elements (key1, value1, key, value2, ...). Keys must not be null.
+   */
+  public String post(String relativeUrl, Object... params) {
+    return post(relativeUrl, paramsAsMap(params));
+  }
+
+  /**
+   * Send a GET request on the given relativeUrl, with provided parameters (can be empty).
+   * The beginning slash (/) of relativeUrl is supported but not mandatory.
    * @since 4.5
    * @return the response body
    */
@@ -160,6 +186,31 @@ public class SonarClient {
     return requestFactory.get(relativeUrl, params);
   }
 
+  /**
+   * Same as {@link #get(String, java.util.Map)} but parameters are defined as an array
+   * of even number of elements (key1, value1, key, value2, ...). Keys must not be null.
+   */
+  public String get(String relativeUrl, Object... params) {
+    return get(relativeUrl, paramsAsMap(params));
+  }
+
+  private Map<String, Object> paramsAsMap(Object[] params) {
+    if (params.length % 2 == 1) {
+      throw new IllegalArgumentException(String.format(
+        "Expecting even number of elements. Got %s", Arrays.toString(params)));
+    }
+    Map<String, Object> map = new HashMap<String, Object>();
+    for (int index = 0; index < params.length; index++) {
+      if (params[index] == null) {
+        throw new IllegalArgumentException(String.format(
+          "Parameter key can't be null at index %d of %s", index, Arrays.toString(params)));
+      }
+      map.put(params[index].toString(), params[index + 1]);
+      index++;
+    }
+    return map;
+  }
+
   public static class Builder {
     private String login, password, url, proxyHost, proxyLogin, proxyPassword;
     private int proxyPort = 0;
index a6f43be762e0a3890a314e423c672919606c403f..d88cf76c32f66feb3573fd796dac4ae210e4ad4d 100644 (file)
@@ -23,10 +23,13 @@ import com.github.kevinsawicki.http.HttpRequest;
 import org.sonar.wsclient.base.HttpException;
 
 import javax.annotation.Nullable;
+
 import java.util.Arrays;
 import java.util.Map;
 
-import static java.net.HttpURLConnection.*;
+import static java.net.HttpURLConnection.HTTP_CREATED;
+import static java.net.HttpURLConnection.HTTP_NO_CONTENT;
+import static java.net.HttpURLConnection.HTTP_OK;
 
 /**
  * Not an API. Please do not use this class, except maybe for unit tests.
@@ -122,15 +125,25 @@ public class HttpRequestFactory {
   }
 
   public String get(String wsUrl, Map<String, Object> queryParams) {
-    HttpRequest request = prepare(HttpRequest.get(baseUrl + wsUrl, queryParams, true));
+    HttpRequest request = prepare(HttpRequest.get(buildUrl(wsUrl), queryParams, true));
     return execute(request);
   }
 
   public String post(String wsUrl, Map<String, Object> queryParams) {
-    HttpRequest request = prepare(HttpRequest.post(baseUrl + wsUrl, true)).form(queryParams, HttpRequest.CHARSET_UTF8);
+    HttpRequest request = prepare(HttpRequest.post(buildUrl(wsUrl), true)).form(queryParams, HttpRequest.CHARSET_UTF8);
     return execute(request);
   }
 
+  private String buildUrl(String part) {
+    StringBuilder url = new StringBuilder();
+    url.append(baseUrl);
+    if (!part.startsWith("/")) {
+      url.append('/');
+    }
+    url.append(part);
+    return url.toString();
+  }
+
   private String execute(HttpRequest request) {
     try {
       if (isSuccess(request)) {
index 7419b687f1728e2a3e9dcd689ecff63d7a443b90..23cc942a8cf13930e2005cf5890bdb5debeefe49 100644 (file)
@@ -50,6 +50,6 @@ public class DefaultProjectClient implements ProjectClient {
   @SuppressWarnings({"rawtypes", "unchecked"})
   private Project jsonToProject(String json) {
     Map jsonRoot = (Map) JSONValue.parse(json);
-    return new DefaultProject((Map) jsonRoot);
+    return new DefaultProject(jsonRoot);
   }
 }
index e6e82045b96797d4edb41d71b747c5df146f1be6..fc23e4d7c9ef089b8db9ac97efefb26ba4cdcdfe 100644 (file)
  */
 package org.sonar.wsclient;
 
+import org.fest.assertions.MapAssert;
 import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.sonar.wsclient.internal.HttpRequestFactory;
 import org.sonar.wsclient.issue.internal.DefaultActionPlanClient;
 import org.sonar.wsclient.issue.internal.DefaultIssueClient;
 import org.sonar.wsclient.permissions.internal.DefaultPermissionClient;
@@ -29,8 +32,13 @@ import org.sonar.wsclient.qualitygate.internal.DefaultQualityGateClient;
 import org.sonar.wsclient.system.internal.DefaultSystemClient;
 import org.sonar.wsclient.user.internal.DefaultUserClient;
 
+import java.util.Map;
+
 import static org.fest.assertions.Assertions.assertThat;
 import static org.fest.assertions.Fail.fail;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 
 public class SonarClientTest {
   @Test
@@ -102,4 +110,59 @@ public class SonarClientTest {
     assertThat(client.requestFactory.getProxyLogin()).isEqualTo("proxyLogin");
     assertThat(client.requestFactory.getProxyPassword()).isEqualTo("proxyPass");
   }
+
+  @Test
+  public void get() throws Exception {
+    HttpRequestFactory requestFactory = mock(HttpRequestFactory.class);
+    SonarClient client = new SonarClient(requestFactory);
+
+    client.get("api/foo", "key", "the_key", "max", 10);
+
+    ArgumentCaptor<Map> paramsCapture = ArgumentCaptor.forClass(Map.class);
+    verify(requestFactory).get(eq("api/foo"), paramsCapture.capture());
+    Map params = paramsCapture.getValue();
+    assertThat(params).hasSize(2);
+    assertThat(params).includes(MapAssert.entry("key", "the_key"));
+    assertThat(params).includes(MapAssert.entry("max", 10));
+  }
+
+  @Test
+  public void post() throws Exception {
+    HttpRequestFactory requestFactory = mock(HttpRequestFactory.class);
+    SonarClient client = new SonarClient(requestFactory);
+
+    client.post("api/foo", "max", 10);
+
+    ArgumentCaptor<Map> paramsCapture = ArgumentCaptor.forClass(Map.class);
+    verify(requestFactory).post(eq("api/foo"), paramsCapture.capture());
+    Map params = paramsCapture.getValue();
+    assertThat(params).hasSize(1);
+    assertThat(params).includes(MapAssert.entry("max", 10));
+  }
+
+  @Test
+  public void fail_if_odd_number_arguments() throws Exception {
+    HttpRequestFactory requestFactory = mock(HttpRequestFactory.class);
+    SonarClient client = new SonarClient(requestFactory);
+
+    try {
+      client.post("api/foo", "max", 10, "min");
+      fail();
+    } catch (IllegalArgumentException e) {
+      assertThat(e).hasMessage("Expecting even number of elements. Got [max, 10, min]");
+    }
+  }
+
+  @Test
+  public void fail_if_null_property_key() throws Exception {
+    HttpRequestFactory requestFactory = mock(HttpRequestFactory.class);
+    SonarClient client = new SonarClient(requestFactory);
+
+    try {
+      client.post("api/foo", "max", 10, null, 5);
+      fail();
+    } catch (IllegalArgumentException e) {
+      assertThat(e).hasMessage("Parameter key can't be null at index 2 of [max, 10, null, 5]");
+    }
+  }
 }
index 82d5e63f6012f3ca6bcb8277512f2547f57fb1ec..a4ff84c215acbc5d60afde59ed61dc2e9ca34bff 100644 (file)
@@ -122,6 +122,16 @@ public class HttpRequestFactoryTest {
     }
   }
 
+  @Test
+  public void beginning_slash_is_optional() throws Exception {
+    HttpRequestFactory factory = new HttpRequestFactory(httpServer.url());
+    factory.get("api/foo", Collections.<String, Object>emptyMap());
+    assertThat(httpServer.requestedPath()).isEqualTo("/api/foo");
+
+    factory.get("/api/bar", Collections.<String, Object>emptyMap());
+    assertThat(httpServer.requestedPath()).isEqualTo("/api/bar");
+  }
+
   @Test
   public void should_encode_characters() {
     HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url());