From ccc6c59808ebc6ddcbcc2e0bcf66c2491e0de15a Mon Sep 17 00:00:00 2001 From: Simon Brandhof Date: Wed, 12 Jun 2013 23:28:00 +0200 Subject: [PATCH] Improve error handling of ws-client --- sonar-ws-client/pom.xml | 6 +- .../java/org/sonar/wsclient/SonarClient.java | 44 ++++- .../sonar/wsclient/base/HttpException.java | 43 +++++ .../wsclient/{issue => base}/Paging.java | 8 +- .../wsclient/internal/EncodingUtils.java | 2 +- .../wsclient/internal/HttpRequestFactory.java | 32 +++- .../org/sonar/wsclient/issue/ActionPlan.java | 60 ++----- .../sonar/wsclient/issue/ActionPlanQuery.java | 2 +- .../java/org/sonar/wsclient/issue/Issue.java | 112 +++---------- .../org/sonar/wsclient/issue/IssueClient.java | 19 +++ .../sonar/wsclient/issue/IssueComment.java | 31 +--- .../org/sonar/wsclient/issue/IssueQuery.java | 6 +- .../java/org/sonar/wsclient/issue/Issues.java | 120 +++----------- .../sonar/wsclient/issue/NewActionPlan.java | 3 +- .../org/sonar/wsclient/issue/NewIssue.java | 4 +- .../wsclient/issue/UpdateActionPlan.java | 3 +- .../issue/internal/DefaultActionPlan.java | 94 +++++++++++ .../DefaultActionPlanClient.java | 49 ++---- .../wsclient/issue/internal/DefaultIssue.java | 155 ++++++++++++++++++ .../{ => internal}/DefaultIssueClient.java | 84 +++------- .../issue/internal/DefaultIssueComment.java | 53 ++++++ .../issue/internal/DefaultIssues.java | 146 +++++++++++++++++ .../issue/{ => internal}/IssueJsonParser.java | 40 ++--- .../wsclient/issue/internal/package-info.java | 21 +++ .../wsclient/user/DefaultUserClient.java | 9 +- .../org/sonar/wsclient/SonarClientTest.java | 4 +- .../wsclient/base/HttpExceptionTest.java | 34 ++++ .../internal/HttpRequestFactoryTest.java | 57 ++++--- .../sonar/wsclient/issue/IssueQueryTest.java | 12 +- .../DefaultActionPlanClientTest.java | 13 +- .../DefaultIssueClientTest.java | 13 +- .../{ => internal}/IssueJsonParserTest.java | 24 ++- .../add_comment_result.json | 0 .../IssueJsonParserTest}/empty.json | 0 .../IssueJsonParserTest}/getTransitions.json | 0 .../issue-with-action-plans.json | 0 .../issue-with-comments.json | 0 .../issue-with-components.json | 0 .../issue-with-projects.json | 0 .../issue-with-users.json | 0 .../IssueJsonParserTest}/search.json | 0 41 files changed, 860 insertions(+), 443 deletions(-) create mode 100644 sonar-ws-client/src/main/java/org/sonar/wsclient/base/HttpException.java rename sonar-ws-client/src/main/java/org/sonar/wsclient/{issue => base}/Paging.java (93%) create mode 100644 sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/DefaultActionPlan.java rename sonar-ws-client/src/main/java/org/sonar/wsclient/issue/{ => internal}/DefaultActionPlanClient.java (55%) create mode 100644 sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/DefaultIssue.java rename sonar-ws-client/src/main/java/org/sonar/wsclient/issue/{ => internal}/DefaultIssueClient.java (50%) create mode 100644 sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/DefaultIssueComment.java create mode 100644 sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/DefaultIssues.java rename sonar-ws-client/src/main/java/org/sonar/wsclient/issue/{ => internal}/IssueJsonParser.java (71%) create mode 100644 sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/package-info.java create mode 100644 sonar-ws-client/src/test/java/org/sonar/wsclient/base/HttpExceptionTest.java rename sonar-ws-client/src/test/java/org/sonar/wsclient/issue/{ => internal}/DefaultActionPlanClientTest.java (92%) rename sonar-ws-client/src/test/java/org/sonar/wsclient/issue/{ => internal}/DefaultIssueClientTest.java (94%) rename sonar-ws-client/src/test/java/org/sonar/wsclient/issue/{ => internal}/IssueJsonParserTest.java (89%) rename sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/{ => internal}/DefaultIssueClientTest/add_comment_result.json (100%) rename sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/{IssueParserTest => internal/IssueJsonParserTest}/empty.json (100%) rename sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/{IssueParserTest => internal/IssueJsonParserTest}/getTransitions.json (100%) rename sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/{IssueParserTest => internal/IssueJsonParserTest}/issue-with-action-plans.json (100%) rename sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/{IssueParserTest => internal/IssueJsonParserTest}/issue-with-comments.json (100%) rename sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/{IssueParserTest => internal/IssueJsonParserTest}/issue-with-components.json (100%) rename sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/{IssueParserTest => internal/IssueJsonParserTest}/issue-with-projects.json (100%) rename sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/{IssueParserTest => internal/IssueJsonParserTest}/issue-with-users.json (100%) rename sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/{IssueParserTest => internal/IssueJsonParserTest}/search.json (100%) diff --git a/sonar-ws-client/pom.xml b/sonar-ws-client/pom.xml index 70cadb60435..eb61c38a516 100644 --- a/sonar-ws-client/pom.xml +++ b/sonar-ws-client/pom.xml @@ -9,7 +9,7 @@ sonar-ws-client jar Sonar :: Web Service Client - Java library to request Sonar web services + Java Client Library for Sonar Web Services 4.2.2 @@ -132,10 +132,12 @@ org.apache.httpcomponents.httpcore;bundle-version="${httpclient4.version}";optional="true" !.,org.sonar.wsclient, + org.sonar.wsclient.component, org.sonar.wsclient.connectors, org.sonar.wsclient.services, org.sonar.wsclient.issue, - org.sonar.wsclient.rule + org.sonar.wsclient.rule, + org.sonar.wsclient.user JavaSE-1.6 diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/SonarClient.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/SonarClient.java index 1ecc19f01ab..767070141e1 100644 --- a/sonar-ws-client/src/main/java/org/sonar/wsclient/SonarClient.java +++ b/sonar-ws-client/src/main/java/org/sonar/wsclient/SonarClient.java @@ -21,8 +21,8 @@ package org.sonar.wsclient; import org.sonar.wsclient.internal.HttpRequestFactory; import org.sonar.wsclient.issue.ActionPlanClient; -import org.sonar.wsclient.issue.DefaultActionPlanClient; -import org.sonar.wsclient.issue.DefaultIssueClient; +import org.sonar.wsclient.issue.internal.DefaultActionPlanClient; +import org.sonar.wsclient.issue.internal.DefaultIssueClient; import org.sonar.wsclient.issue.IssueClient; import org.sonar.wsclient.user.DefaultUserClient; import org.sonar.wsclient.user.UserClient; @@ -30,6 +30,14 @@ import org.sonar.wsclient.user.UserClient; import javax.annotation.Nullable; /** + * Entry point of the Java Client for Sonar Web Services. It does not support all web services yet. + *

+ * Example: + *

+ *   SonarClient client = SonarClient.create("http://localhost:9000");
+ *   IssueClient issueClient = client.issueClient();
+ * 
+ * * @since 3.6 */ public class SonarClient { @@ -54,24 +62,37 @@ public class SonarClient { .setReadTimeoutInMilliseconds(builder.readTimeoutMs); } + /** + * New client to interact with web services related to issues + */ public IssueClient issueClient() { return new DefaultIssueClient(requestFactory); } + /** + * New client to interact with web services related to issue action plans + */ public ActionPlanClient actionPlanClient() { return new DefaultActionPlanClient(requestFactory); } + /** + * New client to interact with web services related to users + */ public UserClient userClient() { return new DefaultUserClient(requestFactory); } + /** + * Create a builder of {@link SonarClient}s. + */ public static Builder builder() { return new Builder(); } /** - * Create a client with default configuration. Use {@link #builder()} to define a custom configuration. + * Create a client with default configuration. Use {@link #builder()} to define + * a custom configuration (credentials, HTTP proxy, HTTP timeouts). */ public static SonarClient create(String serverUrl) { return builder().url(serverUrl).build(); @@ -85,22 +106,34 @@ public class SonarClient { private Builder() { } + /** + * Mandatory HTTP server URL, eg "http://localhost:9000" + */ public Builder url(String url) { this.url = url; return this; } + /** + * Optional login, for example "admin" + */ public Builder login(@Nullable String login) { this.login = login; return this; } + /** + * Optional password related to {@link #login(String)}, for example "admin" + */ public Builder password(@Nullable String password) { this.password = password; return this; } - public Builder proxy(String proxyHost, int proxyPort) { + /** + * Host and port of the optional HTTP proxy + */ + public Builder proxy(@Nullable String proxyHost, int proxyPort) { this.proxyHost = proxyHost; this.proxyPort = proxyPort; return this; @@ -134,6 +167,9 @@ public class SonarClient { return this; } + /** + * Build a new client + */ public SonarClient build() { if (url == null || "".equals(url)) { throw new IllegalStateException("Server URL must be set"); diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/base/HttpException.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/base/HttpException.java new file mode 100644 index 00000000000..94d9bfbcead --- /dev/null +++ b/sonar-ws-client/src/main/java/org/sonar/wsclient/base/HttpException.java @@ -0,0 +1,43 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 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.wsclient.base; + +/** + * @since 3.6 + */ +public class HttpException extends RuntimeException { + + private final String url; + private final int status; + + public HttpException(String url, int status) { + super(String.format("Error %d on %s", status, url)); + this.url = url; + this.status = status; + } + + public String url() { + return url; + } + + public int status() { + return status; + } +} diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/Paging.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/base/Paging.java similarity index 93% rename from sonar-ws-client/src/main/java/org/sonar/wsclient/issue/Paging.java rename to sonar-ws-client/src/main/java/org/sonar/wsclient/base/Paging.java index cd24f2beaf4..d803bdd956a 100644 --- a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/Paging.java +++ b/sonar-ws-client/src/main/java/org/sonar/wsclient/base/Paging.java @@ -18,7 +18,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package org.sonar.wsclient.issue; +package org.sonar.wsclient.base; import org.sonar.wsclient.unmarshallers.JsonUtils; @@ -26,13 +26,15 @@ import java.util.Map; /** * @since 3.6 - * TODO move outside this package */ public class Paging { private final Map json; - Paging(Map json) { + /** + * For internal use + */ + public Paging(Map json) { this.json = json; } diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/internal/EncodingUtils.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/internal/EncodingUtils.java index 698500541ec..99be0b4af2f 100644 --- a/sonar-ws-client/src/main/java/org/sonar/wsclient/internal/EncodingUtils.java +++ b/sonar-ws-client/src/main/java/org/sonar/wsclient/internal/EncodingUtils.java @@ -25,7 +25,7 @@ import java.util.LinkedHashMap; import java.util.Map; /** - * Not an API, please do not directly use this class. + * Not an API. Please do not use this class, except maybe for unit tests. */ public class EncodingUtils { diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/internal/HttpRequestFactory.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/internal/HttpRequestFactory.java index a601df34efc..e454a585448 100644 --- a/sonar-ws-client/src/main/java/org/sonar/wsclient/internal/HttpRequestFactory.java +++ b/sonar-ws-client/src/main/java/org/sonar/wsclient/internal/HttpRequestFactory.java @@ -20,13 +20,13 @@ package org.sonar.wsclient.internal; import com.github.kevinsawicki.http.HttpRequest; +import org.sonar.wsclient.base.HttpException; import javax.annotation.Nullable; - import java.util.Map; /** - * Not an API, please do not directly use this class. + * Not an API. Please do not use this class, except maybe for unit tests. */ public class HttpRequestFactory { @@ -116,17 +116,34 @@ public class HttpRequestFactory { return readTimeoutInMilliseconds; } - public HttpRequest get(String wsUrl, Map queryParams) { + public String get(String wsUrl, Map queryParams) { HttpRequest request = HttpRequest.get(baseUrl + wsUrl, queryParams, true); - return prepare(request); + return execute(request); } - public HttpRequest post(String wsUrl, Map queryParams) { + public String post(String wsUrl, Map queryParams) { HttpRequest request = HttpRequest.post(baseUrl + wsUrl, queryParams, true); - return prepare(request); + return execute(request); + } + + private String execute(HttpRequest request) { + try { + prepare(request); + if (request.ok()) { + return request.body("UTF-8"); + } + // TODO handle error messages + throw new HttpException(request.url().toString(), request.code()); + + } catch (HttpException e) { + throw e; + + } catch (HttpRequest.HttpRequestException e) { + throw new IllegalStateException(e.getCause()); + } } - private HttpRequest prepare(HttpRequest request) { + private void prepare(HttpRequest request) { if (proxyHost != null) { request.useProxy(proxyHost, proxyPort); if (proxyLogin != null) { @@ -145,6 +162,5 @@ public class HttpRequestFactory { if (login != null) { request.basic(login, password); } - return request; } } diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/ActionPlan.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/ActionPlan.java index d7c40630111..daf45ba7124 100644 --- a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/ActionPlan.java +++ b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/ActionPlan.java @@ -11,84 +11,52 @@ * 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. + * Lesser General License for more details. * - * You should have received a copy of the GNU Lesser General Public License + * You should have received a copy of the GNU Lesser General 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.wsclient.issue; -import org.sonar.wsclient.unmarshallers.JsonUtils; - import javax.annotation.CheckForNull; - import java.util.Date; -import java.util.Map; /** * @since 3.6 */ -public class ActionPlan { - - private final Map json; - - ActionPlan(Map json) { - this.json = json; - } +public interface ActionPlan { /** * Unique key */ - public String key() { - return JsonUtils.getString(json, "key"); - } + String key(); - public String project() { - return JsonUtils.getString(json, "project"); - } + String project(); - public String name() { - return JsonUtils.getString(json, "name"); - } + String name(); @CheckForNull - public String description() { - return JsonUtils.getString(json, "desc"); - } + String description(); - public String status() { - return JsonUtils.getString(json, "status"); - } + String status(); /** * Login of the user who created the action plan. */ - public String userLogin() { - return JsonUtils.getString(json, "userLogin"); - } + String userLogin(); @CheckForNull - public Date deadLine() { - return JsonUtils.getDateTime(json, "deadLine"); - } + Date deadLine(); - public Date createdAt() { - return JsonUtils.getDateTime(json, "createdAt"); - } + Date createdAt(); - public Date updatedAt() { - return JsonUtils.getDateTime(json, "updatedAt"); - } + Date updatedAt(); @CheckForNull - public Integer totalIssues() { - return JsonUtils.getInteger(json, "totalIssues"); - } + Integer totalIssues(); @CheckForNull - public Integer unresolvedIssues() { - return JsonUtils.getInteger(json, "unresolvedIssues"); - } + Integer unresolvedIssues(); } diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/ActionPlanQuery.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/ActionPlanQuery.java index aa7124f5cd0..3f77468b783 100644 --- a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/ActionPlanQuery.java +++ b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/ActionPlanQuery.java @@ -27,7 +27,7 @@ import java.util.Map; */ public class ActionPlanQuery { - static final String BASE_URL = "/api/action_plans/search"; + public static final String BASE_URL = "/api/action_plans/search"; private final Map params = new HashMap(); diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/Issue.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/Issue.java index b5b555087e5..3294fa81f65 100644 --- a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/Issue.java +++ b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/Issue.java @@ -11,144 +11,86 @@ * 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. + * Lesser General License for more details. * - * You should have received a copy of the GNU Lesser General Public License + * You should have received a copy of the GNU Lesser General 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.wsclient.issue; -import org.sonar.wsclient.unmarshallers.JsonUtils; - import javax.annotation.CheckForNull; - -import java.util.*; +import java.util.Date; +import java.util.List; +import java.util.Map; /** * @since 3.6 */ -public class Issue { - - private final Map json; - - Issue(Map json) { - this.json = json; - } +public interface Issue { /** * Unique key */ - public String key() { - return JsonUtils.getString(json, "key"); - } + String key(); - public String componentKey() { - return JsonUtils.getString(json, "component"); - } + String componentKey(); - public String projectKey() { - return JsonUtils.getString(json, "project"); - } + String projectKey(); - public String ruleKey() { - return JsonUtils.getString(json, "rule"); - } + String ruleKey(); - public String severity() { - return JsonUtils.getString(json, "severity"); - } + String severity(); @CheckForNull - public String message() { - return JsonUtils.getString(json, "message"); - } + String message(); @CheckForNull - public Integer line() { - return JsonUtils.getInteger(json, "line"); - } + Integer line(); @CheckForNull - public Double effortToFix() { - return JsonUtils.getDouble(json, "effortToFix"); - } + Double effortToFix(); - public String status() { - return JsonUtils.getString(json, "status"); - } + String status(); /** * The resolution type. Null if the issue is not resolved. */ @CheckForNull - public String resolution() { - return JsonUtils.getString(json, "resolution"); - } + String resolution(); @CheckForNull - public String reporter() { - return JsonUtils.getString(json, "reporter"); - } + String reporter(); /** * Login of assignee. Null if issue is not assigned. */ @CheckForNull - public String assignee() { - return JsonUtils.getString(json, "assignee"); - } + String assignee(); /** * SCM account */ @CheckForNull - public String author() { - return JsonUtils.getString(json, "author"); - } + String author(); @CheckForNull - public String actionPlan() { - return JsonUtils.getString(json, "actionPlan"); - } + String actionPlan(); - public Date creationDate() { - return JsonUtils.getDateTime(json, "creationDate"); - } + Date creationDate(); - public Date updateDate() { - return JsonUtils.getDateTime(json, "updateDate"); - } + Date updateDate(); @CheckForNull - public Date closeDate() { - return JsonUtils.getDateTime(json, "closeDate"); - } + Date closeDate(); @CheckForNull - public String attribute(String key) { - return attributes().get(key); - } - - public Map attributes() { - Map attr = (Map) json.get("attr"); - if (attr == null) { - return Collections.emptyMap(); - } - return attr; - } + String attribute(String key); + + Map attributes(); /** * Non-null list of comments */ - public List comments() { - List comments = new ArrayList(); - List jsonComments = (List) json.get("comments"); - if (jsonComments != null) { - for (Map jsonComment : jsonComments) { - comments.add(new IssueComment(jsonComment)); - } - } - return comments; - } + List comments(); } diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/IssueClient.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/IssueClient.java index 3527938710a..1e1fd52df4f 100644 --- a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/IssueClient.java +++ b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/IssueClient.java @@ -24,16 +24,35 @@ import javax.annotation.Nullable; import java.util.List; /** + * This client is a wrapper over the web services related to issues + * * @since 3.6 */ public interface IssueClient { + /** + * Wrap the web service /api/issues/search in order to search for issues. + */ Issues find(IssueQuery query); + /** + * Assign an existing issue to a user. A null assignee removes the assignee. + * + * @return the updated issue + */ Issue assign(String issueKey, @Nullable String assignee); + /** + * Change the severity of an existing issue. Supported values are "INFO", "MINOR", + * "MAJOR", "CRITICAL" and "BLOCKER". + * + * @return the updated issue + */ Issue setSeverity(String issueKey, String severity); + /** + * Link an existing issue to an action plan. A null action plan unlinks the issue. + */ Issue plan(String issueKey, @Nullable String actionPlan); IssueComment addComment(String issueKey, String markdownText); diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/IssueComment.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/IssueComment.java index f649d573b8f..2ce101d0ac7 100644 --- a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/IssueComment.java +++ b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/IssueComment.java @@ -11,42 +11,25 @@ * 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. + * Lesser General License for more details. * - * You should have received a copy of the GNU Lesser General Public License + * You should have received a copy of the GNU Lesser General 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.wsclient.issue; -import org.sonar.wsclient.unmarshallers.JsonUtils; - import java.util.Date; -import java.util.Map; /** * @since 3.6 */ -public class IssueComment { - private final Map json; - - IssueComment(Map json) { - this.json = json; - } - - public String key() { - return JsonUtils.getString(json, "key"); - } +public interface IssueComment { + String key(); - public String htmlText() { - return JsonUtils.getString(json, "htmlText"); - } + String htmlText(); - public String login() { - return JsonUtils.getString(json, "login"); - } + String login(); - public Date createdAt() { - return JsonUtils.getDateTime(json, "createdAt"); - } + Date createdAt(); } diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/IssueQuery.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/IssueQuery.java index db597021e08..f291d31051a 100644 --- a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/IssueQuery.java +++ b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/IssueQuery.java @@ -30,7 +30,6 @@ import java.util.Map; */ public class IssueQuery { - static final String BASE_URL = "/api/issues/search"; private final Map params = new HashMap(); private IssueQuery() { @@ -40,7 +39,10 @@ public class IssueQuery { return new IssueQuery(); } - Map urlParams() { + /** + * URL query string, for internal use + */ + public Map urlParams() { return params; } diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/Issues.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/Issues.java index ff761f26cdf..43d5cf687ac 100644 --- a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/Issues.java +++ b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/Issues.java @@ -11,133 +11,57 @@ * 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. + * Lesser General License for more details. * - * You should have received a copy of the GNU Lesser General Public License + * You should have received a copy of the GNU Lesser General 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.wsclient.issue; +import org.sonar.wsclient.base.Paging; import org.sonar.wsclient.component.Component; import org.sonar.wsclient.rule.Rule; import org.sonar.wsclient.user.User; import javax.annotation.CheckForNull; - -import java.util.*; +import java.util.Collection; +import java.util.List; /** * @since 3.6 */ -public class Issues { +public interface Issues { + List list(); - private final List list = new ArrayList(); - private final Map rulesByKey = new HashMap(); - private final Map usersByKey = new HashMap(); - private final Map componentsByKey = new HashMap(); - private final Map projectsByKey = new HashMap(); - private final Map actionPlansByKey = new HashMap(); - private Paging paging; - private Boolean maxResultsReached; + int size(); - public List list() { - return list; - } + Collection rules(); - public int size() { - return list.size(); - } + Rule rule(Issue issue); - public Collection rules() { - return rulesByKey.values(); - } + Collection users(); - public Rule rule(Issue issue) { - return rulesByKey.get(issue.ruleKey()); - } + @CheckForNull + User user(String login); - public Collection users() { - return usersByKey.values(); - } + Collection components(); @CheckForNull - public User user(String login) { - return usersByKey.get(login); - } + Component component(Issue issue); - public Collection components() { - return componentsByKey.values(); - } + Collection projects(); @CheckForNull - public Component component(Issue issue) { - return componentsByKey.get(issue.componentKey()); - } + Component project(Issue issue); - public Collection projects() { - return projectsByKey.values(); - } + Collection actionPlans(); @CheckForNull - public Component project(Issue issue) { - return projectsByKey.get(issue.projectKey()); - } + ActionPlan actionPlans(Issue issue); - public Collection actionPlans() { - return actionPlansByKey.values(); - } + Paging paging(); + + Boolean maxResultsReached(); - @CheckForNull - public ActionPlan actionPlans(Issue issue) { - return actionPlansByKey.get(issue.actionPlan()); - } - - public Paging paging() { - return paging; - } - - public Boolean maxResultsReached() { - return maxResultsReached; - } - - Issues add(Issue issue) { - list.add(issue); - return this; - } - - Issues add(Rule rule) { - rulesByKey.put(rule.key(), rule); - return this; - } - - Issues add(User user) { - usersByKey.put(user.login(), user); - return this; - } - - Issues add(ActionPlan actionPlan) { - actionPlansByKey.put(actionPlan.key(), actionPlan); - return this; - } - - Issues addComponent(Component c) { - componentsByKey.put(c.key(), c); - return this; - } - - Issues addProject(Component c) { - projectsByKey.put(c.key(), c); - return this; - } - - Issues setPaging(Paging paging) { - this.paging = paging; - return this; - } - - Issues setMaxResultsReached(Boolean maxResultsReached) { - this.maxResultsReached = maxResultsReached; - return this; - } } diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/NewActionPlan.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/NewActionPlan.java index 74c92acbfe8..19655b9edeb 100644 --- a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/NewActionPlan.java +++ b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/NewActionPlan.java @@ -30,7 +30,6 @@ import java.util.Map; */ public class NewActionPlan { - static final String BASE_URL = "/api/action_plans/create"; private final Map params = new HashMap(); private NewActionPlan() { @@ -40,7 +39,7 @@ public class NewActionPlan { return new NewActionPlan(); } - Map urlParams() { + public Map urlParams() { return params; } diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/NewIssue.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/NewIssue.java index 4b8932c2a11..8bda9a02fc2 100644 --- a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/NewIssue.java +++ b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/NewIssue.java @@ -27,7 +27,7 @@ import java.util.Map; * @since 3.6 */ public class NewIssue { - static final String BASE_URL = "/api/issues/create"; + private final Map params = new HashMap(); private NewIssue() { @@ -37,7 +37,7 @@ public class NewIssue { return new NewIssue(); } - Map urlParams() { + public Map urlParams() { return params; } diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/UpdateActionPlan.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/UpdateActionPlan.java index 2ca316217b3..c8aace9c92c 100644 --- a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/UpdateActionPlan.java +++ b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/UpdateActionPlan.java @@ -30,7 +30,6 @@ import java.util.Map; */ public class UpdateActionPlan { - static final String BASE_URL = "/api/action_plans/update"; private final Map params = new HashMap(); private UpdateActionPlan() { @@ -40,7 +39,7 @@ public class UpdateActionPlan { return new UpdateActionPlan(); } - Map urlParams() { + public Map urlParams() { return params; } diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/DefaultActionPlan.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/DefaultActionPlan.java new file mode 100644 index 00000000000..afa077b47b7 --- /dev/null +++ b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/DefaultActionPlan.java @@ -0,0 +1,94 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 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.wsclient.issue.internal; + +import org.sonar.wsclient.issue.ActionPlan; +import org.sonar.wsclient.unmarshallers.JsonUtils; + +import javax.annotation.CheckForNull; +import java.util.Date; +import java.util.Map; + +/** + * @since 3.6 + */ +public class DefaultActionPlan implements ActionPlan { + + private final Map json; + + DefaultActionPlan(Map json) { + this.json = json; + } + + /** + * Unique key + */ + public String key() { + return JsonUtils.getString(json, "key"); + } + + public String project() { + return JsonUtils.getString(json, "project"); + } + + public String name() { + return JsonUtils.getString(json, "name"); + } + + @CheckForNull + public String description() { + return JsonUtils.getString(json, "desc"); + } + + public String status() { + return JsonUtils.getString(json, "status"); + } + + /** + * Login of the user who created the action plan. + */ + public String userLogin() { + return JsonUtils.getString(json, "userLogin"); + } + + @CheckForNull + public Date deadLine() { + return JsonUtils.getDateTime(json, "deadLine"); + } + + public Date createdAt() { + return JsonUtils.getDateTime(json, "createdAt"); + } + + public Date updatedAt() { + return JsonUtils.getDateTime(json, "updatedAt"); + } + + @CheckForNull + public Integer totalIssues() { + return JsonUtils.getInteger(json, "totalIssues"); + } + + @CheckForNull + public Integer unresolvedIssues() { + return JsonUtils.getInteger(json, "unresolvedIssues"); + } + +} diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/DefaultActionPlanClient.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/DefaultActionPlanClient.java similarity index 55% rename from sonar-ws-client/src/main/java/org/sonar/wsclient/issue/DefaultActionPlanClient.java rename to sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/DefaultActionPlanClient.java index 651800edeff..3a187b1d3e6 100644 --- a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/DefaultActionPlanClient.java +++ b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/DefaultActionPlanClient.java @@ -17,12 +17,12 @@ * 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.wsclient.issue; +package org.sonar.wsclient.issue.internal; -import com.github.kevinsawicki.http.HttpRequest; import org.json.simple.JSONValue; import org.sonar.wsclient.internal.EncodingUtils; import org.sonar.wsclient.internal.HttpRequestFactory; +import org.sonar.wsclient.issue.*; import java.util.ArrayList; import java.util.List; @@ -44,17 +44,13 @@ public class DefaultActionPlanClient implements ActionPlanClient { @Override public List find(String projectKey) { - HttpRequest request = requestFactory.get(ActionPlanQuery.BASE_URL, EncodingUtils.toMap("project", projectKey)); - if (!request.ok()) { - throw new IllegalStateException("Fail to search for action plans. Bad HTTP response status: " + request.code()); - } + String json = requestFactory.get(ActionPlanQuery.BASE_URL, EncodingUtils.toMap("project", projectKey)); List result = new ArrayList(); - String json = request.body("UTF-8"); Map jsonRoot = (Map) JSONValue.parse(json); - List jsonActionPlans = (List) jsonRoot.get("actionPlans"); + List jsonActionPlans = (List) jsonRoot.get("actionPlans"); if (jsonActionPlans != null) { for (Map jsonActionPlan : jsonActionPlans) { - result.add(new ActionPlan(jsonActionPlan)); + result.add(new DefaultActionPlan(jsonActionPlan)); } } return result; @@ -62,20 +58,14 @@ public class DefaultActionPlanClient implements ActionPlanClient { @Override public ActionPlan create(NewActionPlan newActionPlan) { - HttpRequest request = requestFactory.post(NewActionPlan.BASE_URL, newActionPlan.urlParams()); - if (!request.ok()) { - throw new IllegalStateException("Fail to create action plan. Bad HTTP response status: " + request.code()); - } - return createActionPlanResult(request); + String json = requestFactory.post("/api/action_plans/create", newActionPlan.urlParams()); + return createActionPlanResult(json); } @Override public ActionPlan update(UpdateActionPlan updateActionPlan) { - HttpRequest request = requestFactory.post(UpdateActionPlan.BASE_URL, updateActionPlan.urlParams()); - if (!request.ok()) { - throw new IllegalStateException("Fail to update action plan. Bad HTTP response status: " + request.code()); - } - return createActionPlanResult(request); + String json = requestFactory.post("/api/action_plans/update", updateActionPlan.urlParams()); + return createActionPlanResult(json); } @Override @@ -85,28 +75,23 @@ public class DefaultActionPlanClient implements ActionPlanClient { @Override public ActionPlan open(String actionPlanKey) { - HttpRequest request = executeSimpleAction(actionPlanKey, "open"); - return createActionPlanResult(request); + String json = executeSimpleAction(actionPlanKey, "open"); + return createActionPlanResult(json); } @Override public ActionPlan close(String actionPlanKey) { - HttpRequest request = executeSimpleAction(actionPlanKey, "close"); - return createActionPlanResult(request); + String json = executeSimpleAction(actionPlanKey, "close"); + return createActionPlanResult(json); } - private HttpRequest executeSimpleAction(String actionPlanKey, String action) { - HttpRequest request = requestFactory.post("/api/action_plans/" + action, EncodingUtils.toMap("key", actionPlanKey)); - if (!request.ok()) { - throw new IllegalStateException("Fail to " + action + " action plan. Bad HTTP response status: " + request.code()); - } - return request; + private String executeSimpleAction(String actionPlanKey, String action) { + return requestFactory.post("/api/action_plans/" + action, EncodingUtils.toMap("key", actionPlanKey)); } - private ActionPlan createActionPlanResult(HttpRequest request){ - String json = request.body("UTF-8"); + private ActionPlan createActionPlanResult(String json) { Map jsonRoot = (Map) JSONValue.parse(json); - return new ActionPlan((Map) jsonRoot.get("actionPlan")); + return new DefaultActionPlan((Map) jsonRoot.get("actionPlan")); } } diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/DefaultIssue.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/DefaultIssue.java new file mode 100644 index 00000000000..36f25bc8d30 --- /dev/null +++ b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/DefaultIssue.java @@ -0,0 +1,155 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 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.wsclient.issue.internal; + +import org.sonar.wsclient.issue.Issue; +import org.sonar.wsclient.issue.IssueComment; +import org.sonar.wsclient.unmarshallers.JsonUtils; + +import javax.annotation.CheckForNull; +import java.util.*; + +/** + * @since 3.6 + */ +public class DefaultIssue implements Issue { + + private final Map json; + + DefaultIssue(Map json) { + this.json = json; + } + + /** + * Unique key + */ + public String key() { + return JsonUtils.getString(json, "key"); + } + + public String componentKey() { + return JsonUtils.getString(json, "component"); + } + + public String projectKey() { + return JsonUtils.getString(json, "project"); + } + + public String ruleKey() { + return JsonUtils.getString(json, "rule"); + } + + public String severity() { + return JsonUtils.getString(json, "severity"); + } + + @CheckForNull + public String message() { + return JsonUtils.getString(json, "message"); + } + + @CheckForNull + public Integer line() { + return JsonUtils.getInteger(json, "line"); + } + + @CheckForNull + public Double effortToFix() { + return JsonUtils.getDouble(json, "effortToFix"); + } + + public String status() { + return JsonUtils.getString(json, "status"); + } + + /** + * The resolution type. Null if the issue is not resolved. + */ + @CheckForNull + public String resolution() { + return JsonUtils.getString(json, "resolution"); + } + + @CheckForNull + public String reporter() { + return JsonUtils.getString(json, "reporter"); + } + + /** + * Login of assignee. Null if issue is not assigned. + */ + @CheckForNull + public String assignee() { + return JsonUtils.getString(json, "assignee"); + } + + /** + * SCM account + */ + @CheckForNull + public String author() { + return JsonUtils.getString(json, "author"); + } + + @CheckForNull + public String actionPlan() { + return JsonUtils.getString(json, "actionPlan"); + } + + public Date creationDate() { + return JsonUtils.getDateTime(json, "creationDate"); + } + + public Date updateDate() { + return JsonUtils.getDateTime(json, "updateDate"); + } + + @CheckForNull + public Date closeDate() { + return JsonUtils.getDateTime(json, "closeDate"); + } + + @CheckForNull + public String attribute(String key) { + return attributes().get(key); + } + + public Map attributes() { + Map attr = (Map) json.get("attr"); + if (attr == null) { + return Collections.emptyMap(); + } + return attr; + } + + /** + * Non-null list of comments + */ + public List comments() { + List comments = new ArrayList(); + List jsonComments = (List) json.get("comments"); + if (jsonComments != null) { + for (Map jsonComment : jsonComments) { + comments.add(new DefaultIssueComment(jsonComment)); + } + } + return comments; + } +} diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/DefaultIssueClient.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/DefaultIssueClient.java similarity index 50% rename from sonar-ws-client/src/main/java/org/sonar/wsclient/issue/DefaultIssueClient.java rename to sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/DefaultIssueClient.java index 4dd1972e2ba..c4b2f326555 100644 --- a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/DefaultIssueClient.java +++ b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/DefaultIssueClient.java @@ -17,15 +17,14 @@ * 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.wsclient.issue; +package org.sonar.wsclient.issue.internal; -import com.github.kevinsawicki.http.HttpRequest; import org.json.simple.JSONValue; import org.sonar.wsclient.internal.EncodingUtils; import org.sonar.wsclient.internal.HttpRequestFactory; +import org.sonar.wsclient.issue.*; import javax.annotation.Nullable; - import java.util.List; import java.util.Map; @@ -34,122 +33,87 @@ import java.util.Map; */ public class DefaultIssueClient implements IssueClient { + private static final String SEARCH_URL = "/api/issues/search"; + private final HttpRequestFactory requestFactory; private final IssueJsonParser parser; - /** - * For internal use. Use {@link org.sonar.wsclient.SonarClient} to get an instance. - */ public DefaultIssueClient(HttpRequestFactory requestFactory) { this.requestFactory = requestFactory; this.parser = new IssueJsonParser(); } public Issues find(IssueQuery query) { - HttpRequest request = requestFactory.get(IssueQuery.BASE_URL, query.urlParams()); - if (!request.ok()) { - throw new IllegalStateException("Fail to search for issues. Bad HTTP response status: " + request.code()); - } - String json = request.body("UTF-8"); + String json = requestFactory.get(SEARCH_URL, query.urlParams()); return parser.parseIssues(json); } @Override public Issue create(NewIssue newIssue) { - HttpRequest request = requestFactory.post(NewIssue.BASE_URL, newIssue.urlParams()); - if (!request.ok()) { - throw new IllegalStateException("Fail to create issue. Bad HTTP response status: " + request.code()); - } - return createIssueResult(request); + String json = requestFactory.post("/api/issues/create", newIssue.urlParams()); + return jsonToIssue(json); } @Override public Issue setSeverity(String issueKey, String severity) { Map params = EncodingUtils.toMap("issue", issueKey, "severity", severity); - HttpRequest request = requestFactory.post("/api/issues/set_severity", params); - if (!request.ok()) { - throw new IllegalStateException("Fail to set severity. Bad HTTP response status: " + request.code()); - } - return createIssueResult(request); + String json = requestFactory.post("/api/issues/set_severity", params); + return jsonToIssue(json); } @Override public Issue assign(String issueKey, @Nullable String assignee) { Map params = EncodingUtils.toMap("issue", issueKey, "assignee", assignee); - HttpRequest request = requestFactory.post("/api/issues/assign", params); - if (!request.ok()) { - throw new IllegalStateException("Fail to assign issue to user. Bad HTTP response status: " + request.code()); - } - return createIssueResult(request); + String json = requestFactory.post("/api/issues/assign", params); + return jsonToIssue(json); } @Override public Issue plan(String issueKey, @Nullable String actionPlanKey) { Map params = EncodingUtils.toMap("issue", issueKey, "plan", actionPlanKey); - HttpRequest request = requestFactory.post("/api/issues/plan", params); - if (!request.ok()) { - throw new IllegalStateException("Fail to link action plan. Bad HTTP response status: " + request.code()); - } - return createIssueResult(request); + String json = requestFactory.post("/api/issues/plan", params); + return jsonToIssue(json); } @Override public IssueComment addComment(String issueKey, String markdownText) { Map params = EncodingUtils.toMap("issue", issueKey, "text", markdownText); - HttpRequest request = requestFactory.post("/api/issues/add_comment", params); - if (!request.ok()) { - throw new IllegalStateException("Fail to add issue comment. Bad HTTP response status: " + request.code()); - } - Map rootJson = (Map) JSONValue.parse(request.body()); - return new IssueComment((Map)rootJson.get("comment")); + String json = requestFactory.post("/api/issues/add_comment", params); + Map rootJson = (Map) JSONValue.parse(json); + return new DefaultIssueComment((Map) rootJson.get("comment")); } @Override public List transitions(String issueKey) { Map queryParams = EncodingUtils.toMap("issue", issueKey); - HttpRequest request = requestFactory.get("/api/issues/transitions", queryParams); - if (!request.ok()) { - throw new IllegalStateException("Fail to return transitions for issue. Bad HTTP response status: " + request.code()); - } - String json = request.body("UTF-8"); + String json = requestFactory.get("/api/issues/transitions", queryParams); return parser.parseTransitions(json); } @Override public Issue doTransition(String issueKey, String transition) { Map params = EncodingUtils.toMap("issue", issueKey, "transition", transition); - HttpRequest request = requestFactory.post("/api/issues/do_transition", params); - if (!request.ok()) { - throw new IllegalStateException("Fail to execute transition on issue " + issueKey + ".Bad HTTP response status: " + request.code()); - } - return createIssueResult(request); + String json = requestFactory.post("/api/issues/do_transition", params); + return jsonToIssue(json); } @Override public List actions(String issueKey) { Map queryParams = EncodingUtils.toMap("issue", issueKey); - HttpRequest request = requestFactory.get("/api/issues/actions", queryParams); - if (!request.ok()) { - throw new IllegalStateException("Fail to return actions for issue. Bad HTTP response status: " + request.code()); - } - String json = request.body("UTF-8"); + String json = requestFactory.get("/api/issues/actions", queryParams); return parser.parseActions(json); } @Override public Issue doAction(String issueKey, String action) { Map params = EncodingUtils.toMap("issue", issueKey, "actionKey", action); - HttpRequest request = requestFactory.post("/api/issues/do_action", params); - if (!request.ok()) { - throw new IllegalStateException("Fail to execute action on issue " + issueKey + ".Bad HTTP response status: " + request.code()); - } - return createIssueResult(request); + String json = requestFactory.post("/api/issues/do_action", params); + return jsonToIssue(json); } - private Issue createIssueResult(HttpRequest request){ - String json = request.body("UTF-8"); + private Issue jsonToIssue(String json) { Map jsonRoot = (Map) JSONValue.parse(json); - return new Issue((Map) jsonRoot.get("issue")); + return new DefaultIssue((Map) jsonRoot.get("issue")); } } diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/DefaultIssueComment.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/DefaultIssueComment.java new file mode 100644 index 00000000000..bcd42560403 --- /dev/null +++ b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/DefaultIssueComment.java @@ -0,0 +1,53 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 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.wsclient.issue.internal; + +import org.sonar.wsclient.issue.IssueComment; +import org.sonar.wsclient.unmarshallers.JsonUtils; + +import java.util.Date; +import java.util.Map; + +/** + * @since 3.6 + */ +public class DefaultIssueComment implements IssueComment { + private final Map json; + + DefaultIssueComment(Map json) { + this.json = json; + } + + public String key() { + return JsonUtils.getString(json, "key"); + } + + public String htmlText() { + return JsonUtils.getString(json, "htmlText"); + } + + public String login() { + return JsonUtils.getString(json, "login"); + } + + public Date createdAt() { + return JsonUtils.getDateTime(json, "createdAt"); + } +} diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/DefaultIssues.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/DefaultIssues.java new file mode 100644 index 00000000000..37b5348fa88 --- /dev/null +++ b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/DefaultIssues.java @@ -0,0 +1,146 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 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.wsclient.issue.internal; + +import org.sonar.wsclient.component.Component; +import org.sonar.wsclient.issue.ActionPlan; +import org.sonar.wsclient.issue.Issue; +import org.sonar.wsclient.issue.Issues; +import org.sonar.wsclient.base.Paging; +import org.sonar.wsclient.rule.Rule; +import org.sonar.wsclient.user.User; + +import javax.annotation.CheckForNull; +import java.util.*; + +/** + * @since 3.6 + */ +public class DefaultIssues implements Issues { + + private final List list = new ArrayList(); + private final Map rulesByKey = new HashMap(); + private final Map usersByKey = new HashMap(); + private final Map componentsByKey = new HashMap(); + private final Map projectsByKey = new HashMap(); + private final Map actionPlansByKey = new HashMap(); + private Paging paging; + private Boolean maxResultsReached; + + public List list() { + return list; + } + + public int size() { + return list.size(); + } + + public Collection rules() { + return rulesByKey.values(); + } + + public Rule rule(Issue issue) { + return rulesByKey.get(issue.ruleKey()); + } + + public Collection users() { + return usersByKey.values(); + } + + @CheckForNull + public User user(String login) { + return usersByKey.get(login); + } + + public Collection components() { + return componentsByKey.values(); + } + + @CheckForNull + public Component component(Issue issue) { + return componentsByKey.get(issue.componentKey()); + } + + public Collection projects() { + return projectsByKey.values(); + } + + @CheckForNull + public Component project(Issue issue) { + return projectsByKey.get(issue.projectKey()); + } + + public Collection actionPlans() { + return actionPlansByKey.values(); + } + + @CheckForNull + public ActionPlan actionPlans(Issue issue) { + return actionPlansByKey.get(issue.actionPlan()); + } + + public Paging paging() { + return paging; + } + + public Boolean maxResultsReached() { + return maxResultsReached; + } + + DefaultIssues add(Issue issue) { + list.add(issue); + return this; + } + + DefaultIssues add(Rule rule) { + rulesByKey.put(rule.key(), rule); + return this; + } + + DefaultIssues add(User user) { + usersByKey.put(user.login(), user); + return this; + } + + DefaultIssues add(ActionPlan actionPlan) { + actionPlansByKey.put(actionPlan.key(), actionPlan); + return this; + } + + DefaultIssues addComponent(Component c) { + componentsByKey.put(c.key(), c); + return this; + } + + DefaultIssues addProject(Component c) { + projectsByKey.put(c.key(), c); + return this; + } + + DefaultIssues setPaging(Paging paging) { + this.paging = paging; + return this; + } + + DefaultIssues setMaxResultsReached(Boolean maxResultsReached) { + this.maxResultsReached = maxResultsReached; + return this; + } +} diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/IssueJsonParser.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/IssueJsonParser.java similarity index 71% rename from sonar-ws-client/src/main/java/org/sonar/wsclient/issue/IssueJsonParser.java rename to sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/IssueJsonParser.java index 906929ce308..d123e9779cb 100644 --- a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/IssueJsonParser.java +++ b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/IssueJsonParser.java @@ -17,10 +17,12 @@ * 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.wsclient.issue; +package org.sonar.wsclient.issue.internal; import org.json.simple.JSONValue; import org.sonar.wsclient.component.Component; +import org.sonar.wsclient.issue.Issues; +import org.sonar.wsclient.base.Paging; import org.sonar.wsclient.rule.Rule; import org.sonar.wsclient.unmarshallers.JsonUtils; import org.sonar.wsclient.user.User; @@ -32,15 +34,15 @@ import java.util.Map; /** * @since 3.6 */ -class IssueJsonParser { +public class IssueJsonParser { - Issues parseIssues(String json) { - Issues result = new Issues(); + public Issues parseIssues(String json) { + DefaultIssues result = new DefaultIssues(); Map jsonRoot = (Map) JSONValue.parse(json); - List jsonIssues = (List) jsonRoot.get("issues"); + List jsonIssues = (List) jsonRoot.get("issues"); if (jsonIssues != null) { for (Map jsonIssue : jsonIssues) { - result.add(new Issue(jsonIssue)); + result.add(new DefaultIssue(jsonIssue)); } } parseRules(result, jsonRoot); @@ -52,14 +54,14 @@ class IssueJsonParser { return result; } - private void parsePaging(Issues result, Map jsonRoot) { + private void parsePaging(DefaultIssues result, Map jsonRoot) { Map paging = (Map) jsonRoot.get("paging"); result.setPaging(new Paging(paging)); result.setMaxResultsReached(JsonUtils.getBoolean(jsonRoot, "maxResultsReached")); } - private void parseProjects(Issues result, Map jsonRoot) { - List jsonProjects = (List) jsonRoot.get("projects"); + private void parseProjects(DefaultIssues result, Map jsonRoot) { + List jsonProjects = (List) jsonRoot.get("projects"); if (jsonProjects != null) { for (Map jsonProject : jsonProjects) { result.addProject(new Component(jsonProject)); @@ -67,8 +69,8 @@ class IssueJsonParser { } } - private void parseComponents(Issues result, Map jsonRoot) { - List jsonComponents = (List) jsonRoot.get("components"); + private void parseComponents(DefaultIssues result, Map jsonRoot) { + List jsonComponents = (List) jsonRoot.get("components"); if (jsonComponents != null) { for (Map jsonComponent : jsonComponents) { result.addComponent(new Component(jsonComponent)); @@ -76,8 +78,8 @@ class IssueJsonParser { } } - private void parseUsers(Issues result, Map jsonRoot) { - List jsonUsers = (List) jsonRoot.get("users"); + private void parseUsers(DefaultIssues result, Map jsonRoot) { + List jsonUsers = (List) jsonRoot.get("users"); if (jsonUsers != null) { for (Map jsonUser : jsonUsers) { result.add(new User(jsonUser)); @@ -85,8 +87,8 @@ class IssueJsonParser { } } - private void parseRules(Issues result, Map jsonRoot) { - List jsonRules = (List) jsonRoot.get("rules"); + private void parseRules(DefaultIssues result, Map jsonRoot) { + List jsonRules = (List) jsonRoot.get("rules"); if (jsonRules != null) { for (Map jsonRule : jsonRules) { result.add(new Rule(jsonRule)); @@ -94,11 +96,11 @@ class IssueJsonParser { } } - private void parseActionPlans(Issues result, Map jsonRoot) { + private void parseActionPlans(DefaultIssues result, Map jsonRoot) { List jsonRules = (List) jsonRoot.get("actionPlans"); if (jsonRules != null) { for (Map jsonRule : jsonRules) { - result.add(new ActionPlan(jsonRule)); + result.add(new DefaultActionPlan(jsonRule)); } } } @@ -106,7 +108,7 @@ class IssueJsonParser { List parseTransitions(String json) { List transitions = new ArrayList(); Map jRoot = (Map) JSONValue.parse(json); - List jTransitions = (List) jRoot.get("transitions"); + List jTransitions = (List) jRoot.get("transitions"); for (String jTransition : jTransitions) { transitions.add(jTransition); } @@ -116,7 +118,7 @@ class IssueJsonParser { List parseActions(String json) { List actions = new ArrayList(); Map jRoot = (Map) JSONValue.parse(json); - List jActions = (List) jRoot.get("actions"); + List jActions = (List) jRoot.get("actions"); for (String jAction : jActions) { actions.add(jAction); } diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/package-info.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/package-info.java new file mode 100644 index 00000000000..bd54aab693e --- /dev/null +++ b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/package-info.java @@ -0,0 +1,21 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 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. + */ +@javax.annotation.ParametersAreNonnullByDefault +package org.sonar.wsclient.issue.internal; \ No newline at end of file diff --git a/sonar-ws-client/src/main/java/org/sonar/wsclient/user/DefaultUserClient.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/user/DefaultUserClient.java index fd842df823c..b7c60866991 100644 --- a/sonar-ws-client/src/main/java/org/sonar/wsclient/user/DefaultUserClient.java +++ b/sonar-ws-client/src/main/java/org/sonar/wsclient/user/DefaultUserClient.java @@ -19,7 +19,6 @@ */ package org.sonar.wsclient.user; -import com.github.kevinsawicki.http.HttpRequest; import org.json.simple.JSONValue; import org.sonar.wsclient.internal.HttpRequestFactory; @@ -43,14 +42,10 @@ public class DefaultUserClient implements UserClient { @Override public List find(UserQuery query) { - HttpRequest request = requestFactory.get(UserQuery.BASE_URL, query.urlParams()); - if (!request.ok()) { - throw new IllegalStateException("Fail to search for users. Bad HTTP response status: " + request.code()); - } + String json = requestFactory.get(UserQuery.BASE_URL, query.urlParams()); List result = new ArrayList(); - String json = request.body("UTF-8"); Map jsonRoot = (Map) JSONValue.parse(json); - List jsonUsers = (List) jsonRoot.get("users"); + List jsonUsers = (List) jsonRoot.get("users"); if (jsonUsers != null) { for (Map jsonUser : jsonUsers) { result.add(new User(jsonUser)); diff --git a/sonar-ws-client/src/test/java/org/sonar/wsclient/SonarClientTest.java b/sonar-ws-client/src/test/java/org/sonar/wsclient/SonarClientTest.java index 8216d88767e..74b601c3f3d 100644 --- a/sonar-ws-client/src/test/java/org/sonar/wsclient/SonarClientTest.java +++ b/sonar-ws-client/src/test/java/org/sonar/wsclient/SonarClientTest.java @@ -20,8 +20,8 @@ package org.sonar.wsclient; import org.junit.Test; -import org.sonar.wsclient.issue.DefaultActionPlanClient; -import org.sonar.wsclient.issue.DefaultIssueClient; +import org.sonar.wsclient.issue.internal.DefaultActionPlanClient; +import org.sonar.wsclient.issue.internal.DefaultIssueClient; import org.sonar.wsclient.user.DefaultUserClient; import static org.fest.assertions.Assertions.assertThat; diff --git a/sonar-ws-client/src/test/java/org/sonar/wsclient/base/HttpExceptionTest.java b/sonar-ws-client/src/test/java/org/sonar/wsclient/base/HttpExceptionTest.java new file mode 100644 index 00000000000..d0a41a02cf2 --- /dev/null +++ b/sonar-ws-client/src/test/java/org/sonar/wsclient/base/HttpExceptionTest.java @@ -0,0 +1,34 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 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.wsclient.base; + +import org.junit.Test; + +import static org.fest.assertions.Assertions.assertThat; + +public class HttpExceptionTest { + @Test + public void test_exception() throws Exception { + HttpException exception = new HttpException("http://localhost:9000/api/search", 500); + assertThat(exception.status()).isEqualTo(500); + assertThat(exception.url()).isEqualTo("http://localhost:9000/api/search"); + assertThat(exception.getMessage()).isEqualTo("Error 500 on http://localhost:9000/api/search"); + } +} diff --git a/sonar-ws-client/src/test/java/org/sonar/wsclient/internal/HttpRequestFactoryTest.java b/sonar-ws-client/src/test/java/org/sonar/wsclient/internal/HttpRequestFactoryTest.java index 0006ad7295b..9969090a1ee 100644 --- a/sonar-ws-client/src/test/java/org/sonar/wsclient/internal/HttpRequestFactoryTest.java +++ b/sonar-ws-client/src/test/java/org/sonar/wsclient/internal/HttpRequestFactoryTest.java @@ -19,20 +19,21 @@ */ package org.sonar.wsclient.internal; -import com.github.kevinsawicki.http.HttpRequest; import org.junit.Rule; import org.junit.Test; import org.sonar.wsclient.MockHttpServerInterceptor; -import org.sonar.wsclient.issue.DefaultIssueClient; import org.sonar.wsclient.issue.IssueClient; import org.sonar.wsclient.issue.IssueQuery; +import org.sonar.wsclient.issue.internal.DefaultIssueClient; +import java.net.ConnectException; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Collections; import java.util.Date; import static org.fest.assertions.Assertions.assertThat; +import static org.fest.assertions.Fail.fail; public class HttpRequestFactoryTest { @Rule @@ -40,56 +41,62 @@ public class HttpRequestFactoryTest { @Test public void test_get() { - httpServer.doReturnStatus(200).doReturnBody("list of issues"); + httpServer.doReturnStatus(200).doReturnBody("{'issues': []}"); HttpRequestFactory factory = new HttpRequestFactory(httpServer.url()); - HttpRequest request = factory.get("/api/issues", Collections.emptyMap()); + String json = factory.get("/api/issues", Collections.emptyMap()); - assertThat(request.method()).isEqualTo("GET"); - assertThat(request.body()).isEqualTo("list of issues"); - assertThat(request.code()).isEqualTo(200); + assertThat(json).isEqualTo("{'issues': []}"); assertThat(httpServer.requestedPath()).isEqualTo("/api/issues"); } + @Test + public void should_throw_illegal_state_exc_if_connect_exception() { + HttpRequestFactory factory = new HttpRequestFactory("http://localhost:1"); + try { + factory.get("/api/issues", Collections.emptyMap()); + fail(); + } catch (Exception e) { + assertThat(e).isInstanceOf(IllegalStateException.class); + assertThat(e).hasMessage("java.net.ConnectException: Connection refused"); + } + } + @Test public void test_post() { - httpServer.doReturnStatus(200); + httpServer.doReturnStatus(200).doReturnBody("{}"); HttpRequestFactory factory = new HttpRequestFactory(httpServer.url()); - HttpRequest request = factory.post("/api/issues/change", Collections.emptyMap()); + String json = factory.post("/api/issues/change", Collections.emptyMap()); - assertThat(request.method()).isEqualTo("POST"); - assertThat(request.code()).isEqualTo(200); + assertThat(json).isEqualTo("{}"); assertThat(httpServer.requestedPath()).isEqualTo("/api/issues/change"); } @Test public void test_authentication() { - httpServer.doReturnStatus(200).doReturnBody("list of issues"); + httpServer.doReturnStatus(200).doReturnBody("{}"); HttpRequestFactory factory = new HttpRequestFactory(httpServer.url()).setLogin("karadoc").setPassword("legrascestlavie"); - HttpRequest request = factory.get("/api/issues", Collections.emptyMap()); + String json = factory.get("/api/issues", Collections.emptyMap()); - assertThat(request.body()).isEqualTo("list of issues"); - assertThat(request.code()).isEqualTo(200); + assertThat(json).isEqualTo("{}"); assertThat(httpServer.requestedPath()).isEqualTo("/api/issues"); assertThat(httpServer.requestHeaders().get("Authorization")).isEqualTo("Basic a2FyYWRvYzpsZWdyYXNjZXN0bGF2aWU="); } @Test public void test_proxy() throws Exception { - HttpRequestFactory factory = new HttpRequestFactory(httpServer.url()).setProxyHost("localhost").setProxyPort(5020); - HttpRequest request = factory.get("/api/issues", Collections.emptyMap()); - // it's not possible to check that the proxy is correctly configured - } - - @Test - public void test_proxy_credentials() throws Exception { HttpRequestFactory factory = new HttpRequestFactory(httpServer.url()) - .setProxyHost("localhost").setProxyPort(5020) + .setProxyHost("localhost").setProxyPort(1) .setProxyLogin("john").setProxyPassword("smith"); - HttpRequest request = factory.get("/api/issues", Collections.emptyMap()); - // it's not possible to check that the proxy is correctly configured + try { + factory.get("/api/issues", Collections.emptyMap()); + fail(); + } catch (IllegalStateException e) { + // it's not possible to check that the proxy is correctly configured + assertThat(e.getCause()).isInstanceOf(ConnectException.class); + } } @Test diff --git a/sonar-ws-client/src/test/java/org/sonar/wsclient/issue/IssueQueryTest.java b/sonar-ws-client/src/test/java/org/sonar/wsclient/issue/IssueQueryTest.java index bd1ddc18e01..941894aee78 100644 --- a/sonar-ws-client/src/test/java/org/sonar/wsclient/issue/IssueQueryTest.java +++ b/sonar-ws-client/src/test/java/org/sonar/wsclient/issue/IssueQueryTest.java @@ -21,6 +21,9 @@ package org.sonar.wsclient.issue; import org.junit.Test; +import java.text.ParseException; +import java.text.SimpleDateFormat; + import static org.fest.assertions.Assertions.assertThat; import static org.fest.assertions.MapAssert.entry; @@ -32,7 +35,8 @@ public class IssueQueryTest { } @Test - public void get_all_issues_by_parameter() { + public void get_all_issues_by_parameter() throws ParseException { + SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm"); IssueQuery query = IssueQuery.create() .issues("ABCDE", "FGHIJ") .assignees("arthur", "perceval") @@ -47,12 +51,14 @@ public class IssueQueryTest { .statuses("OPEN", "CLOSED") .severities("BLOCKER", "INFO") .reporters("login1", "login2") + .createdBefore(df.parse("2015-12-13T05:59")) + .createdAfter(df.parse("2012-01-23T13:40")) .sort("ASSIGNEE") .asc(false) .pageSize(5) .pageIndex(4); - assertThat(query.urlParams()).hasSize(17); + assertThat(query.urlParams()).hasSize(19); assertThat(query.urlParams()).includes(entry("issues", "ABCDE,FGHIJ")); assertThat(query.urlParams()).includes(entry("assignees", "arthur,perceval")); assertThat(query.urlParams()).includes(entry("assigned", true)); @@ -66,6 +72,8 @@ public class IssueQueryTest { assertThat(query.urlParams()).includes(entry("statuses", "OPEN,CLOSED")); assertThat(query.urlParams()).includes(entry("severities", "BLOCKER,INFO")); assertThat(query.urlParams()).includes(entry("reporters", "login1,login2")); + assertThat((String)query.urlParams().get("createdBefore")).startsWith("2015-12-13T05:59"); + assertThat((String)query.urlParams().get("createdAfter")).startsWith("2012-01-23T13:40:00"); assertThat(query.urlParams()).includes(entry("sort", "ASSIGNEE")); assertThat(query.urlParams()).includes(entry("asc", false)); assertThat(query.urlParams()).includes(entry("pageSize", 5)); diff --git a/sonar-ws-client/src/test/java/org/sonar/wsclient/issue/DefaultActionPlanClientTest.java b/sonar-ws-client/src/test/java/org/sonar/wsclient/issue/internal/DefaultActionPlanClientTest.java similarity index 92% rename from sonar-ws-client/src/test/java/org/sonar/wsclient/issue/DefaultActionPlanClientTest.java rename to sonar-ws-client/src/test/java/org/sonar/wsclient/issue/internal/DefaultActionPlanClientTest.java index e56572fc2b1..2e74730df14 100644 --- a/sonar-ws-client/src/test/java/org/sonar/wsclient/issue/DefaultActionPlanClientTest.java +++ b/sonar-ws-client/src/test/java/org/sonar/wsclient/issue/internal/DefaultActionPlanClientTest.java @@ -18,12 +18,17 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package org.sonar.wsclient.issue; +package org.sonar.wsclient.issue.internal; import org.junit.Rule; import org.junit.Test; import org.sonar.wsclient.MockHttpServerInterceptor; +import org.sonar.wsclient.base.HttpException; import org.sonar.wsclient.internal.HttpRequestFactory; +import org.sonar.wsclient.issue.ActionPlan; +import org.sonar.wsclient.issue.ActionPlanClient; +import org.sonar.wsclient.issue.NewActionPlan; +import org.sonar.wsclient.issue.UpdateActionPlan; import java.text.ParseException; import java.text.SimpleDateFormat; @@ -115,8 +120,10 @@ public class DefaultActionPlanClientTest { try { client.delete("382f6f2e-ad9d-424a-b973-9b065e04348a"); fail(); - } catch (IllegalStateException e) { - assertThat(e).hasMessage("Fail to delete action plan. Bad HTTP response status: 500"); + } catch (HttpException e) { + assertThat(e.status()).isEqualTo(500); + assertThat(e.url()).startsWith("http://localhost"); + assertThat(e.url()).endsWith("/api/action_plans/delete?key=382f6f2e-ad9d-424a-b973-9b065e04348a"); } } diff --git a/sonar-ws-client/src/test/java/org/sonar/wsclient/issue/DefaultIssueClientTest.java b/sonar-ws-client/src/test/java/org/sonar/wsclient/issue/internal/DefaultIssueClientTest.java similarity index 94% rename from sonar-ws-client/src/test/java/org/sonar/wsclient/issue/DefaultIssueClientTest.java rename to sonar-ws-client/src/test/java/org/sonar/wsclient/issue/internal/DefaultIssueClientTest.java index 7ad6f6df3c8..d262073e26e 100644 --- a/sonar-ws-client/src/test/java/org/sonar/wsclient/issue/DefaultIssueClientTest.java +++ b/sonar-ws-client/src/test/java/org/sonar/wsclient/issue/internal/DefaultIssueClientTest.java @@ -17,13 +17,16 @@ * 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.wsclient.issue; +package org.sonar.wsclient.issue.internal; import org.apache.commons.io.IOUtils; import org.junit.Rule; import org.junit.Test; import org.sonar.wsclient.MockHttpServerInterceptor; +import org.sonar.wsclient.base.HttpException; import org.sonar.wsclient.internal.HttpRequestFactory; +import org.sonar.wsclient.issue.*; +import org.sonar.wsclient.issue.internal.DefaultIssueClient; import java.util.List; @@ -57,8 +60,10 @@ public class DefaultIssueClientTest { try { client.find(IssueQuery.create()); fail(); - } catch (IllegalStateException e) { - assertThat(e).hasMessage("Fail to search for issues. Bad HTTP response status: 500"); + } catch (HttpException e) { + assertThat(e.status()).isEqualTo(500); + assertThat(e.url()).startsWith("http://localhost"); + assertThat(e.url()).endsWith("/api/issues/search"); } } @@ -167,7 +172,7 @@ public class DefaultIssueClientTest { @Test public void should_add_comment() throws Exception { HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url()); - httpServer.doReturnBody(IOUtils.toString(getClass().getResourceAsStream("/org/sonar/wsclient/issue/DefaultIssueClientTest/add_comment_result.json"))); + httpServer.doReturnBody(IOUtils.toString(getClass().getResourceAsStream("/org/sonar/wsclient/issue/internal/DefaultIssueClientTest/add_comment_result.json"))); IssueClient client = new DefaultIssueClient(requestFactory); IssueComment comment = client.addComment("ISSUE-1", "this is my comment"); diff --git a/sonar-ws-client/src/test/java/org/sonar/wsclient/issue/IssueJsonParserTest.java b/sonar-ws-client/src/test/java/org/sonar/wsclient/issue/internal/IssueJsonParserTest.java similarity index 89% rename from sonar-ws-client/src/test/java/org/sonar/wsclient/issue/IssueJsonParserTest.java rename to sonar-ws-client/src/test/java/org/sonar/wsclient/issue/internal/IssueJsonParserTest.java index 09cb3941742..c84bfe8c001 100644 --- a/sonar-ws-client/src/test/java/org/sonar/wsclient/issue/IssueJsonParserTest.java +++ b/sonar-ws-client/src/test/java/org/sonar/wsclient/issue/internal/IssueJsonParserTest.java @@ -17,11 +17,17 @@ * 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.wsclient.issue; +package org.sonar.wsclient.issue.internal; import org.apache.commons.io.IOUtils; import org.junit.Test; +import org.sonar.wsclient.base.Paging; import org.sonar.wsclient.component.Component; +import org.sonar.wsclient.issue.ActionPlan; +import org.sonar.wsclient.issue.Issue; +import org.sonar.wsclient.issue.IssueComment; +import org.sonar.wsclient.issue.Issues; +import org.sonar.wsclient.issue.internal.IssueJsonParser; import org.sonar.wsclient.user.User; import java.util.List; @@ -31,7 +37,7 @@ import static org.fest.assertions.Assertions.assertThat; public class IssueJsonParserTest { @Test public void test_GET_search() throws Exception { - String json = IOUtils.toString(getClass().getResourceAsStream("/org/sonar/wsclient/issue/IssueParserTest/search.json")); + String json = IOUtils.toString(getClass().getResourceAsStream("/org/sonar/wsclient/issue/internal/IssueJsonParserTest/search.json")); Issues issues = new IssueJsonParser().parseIssues(json); assertThat(issues).isNotNull(); List list = issues.list(); @@ -86,7 +92,7 @@ public class IssueJsonParserTest { @Test public void test_GET_empty_search() throws Exception { - String json = IOUtils.toString(getClass().getResourceAsStream("/org/sonar/wsclient/issue/IssueParserTest/empty.json")); + String json = IOUtils.toString(getClass().getResourceAsStream("/org/sonar/wsclient/issue/internal/IssueJsonParserTest/empty.json")); Issues issues = new IssueJsonParser().parseIssues(json); assertThat(issues).isNotNull(); assertThat(issues.list()).isEmpty(); @@ -96,7 +102,7 @@ public class IssueJsonParserTest { @Test public void test_GET_transitions() throws Exception { - String json = IOUtils.toString(getClass().getResourceAsStream("/org/sonar/wsclient/issue/IssueParserTest/getTransitions.json")); + String json = IOUtils.toString(getClass().getResourceAsStream("/org/sonar/wsclient/issue/internal/IssueJsonParserTest/getTransitions.json")); List transitions = new IssueJsonParser().parseTransitions(json); assertThat(transitions).isNotNull(); @@ -106,7 +112,7 @@ public class IssueJsonParserTest { @Test public void should_parse_comments() throws Exception { - String json = IOUtils.toString(getClass().getResourceAsStream("/org/sonar/wsclient/issue/IssueParserTest/issue-with-comments.json")); + String json = IOUtils.toString(getClass().getResourceAsStream("/org/sonar/wsclient/issue/internal/IssueJsonParserTest/issue-with-comments.json")); Issues issues = new IssueJsonParser().parseIssues(json); assertThat(issues.size()).isEqualTo(1); @@ -128,7 +134,7 @@ public class IssueJsonParserTest { @Test public void should_parse_users() throws Exception { - String json = IOUtils.toString(getClass().getResourceAsStream("/org/sonar/wsclient/issue/IssueParserTest/issue-with-users.json")); + String json = IOUtils.toString(getClass().getResourceAsStream("/org/sonar/wsclient/issue/internal/IssueJsonParserTest/issue-with-users.json")); Issues issues = new IssueJsonParser().parseIssues(json); assertThat(issues.users()).hasSize(2); @@ -148,7 +154,7 @@ public class IssueJsonParserTest { @Test public void should_parse_components() throws Exception { - String json = IOUtils.toString(getClass().getResourceAsStream("/org/sonar/wsclient/issue/IssueParserTest/issue-with-components.json")); + String json = IOUtils.toString(getClass().getResourceAsStream("/org/sonar/wsclient/issue/internal/IssueJsonParserTest/issue-with-components.json")); Issues issues = new IssueJsonParser().parseIssues(json); assertThat(issues.components()).hasSize(1); @@ -162,7 +168,7 @@ public class IssueJsonParserTest { @Test public void should_parse_projects() throws Exception { - String json = IOUtils.toString(getClass().getResourceAsStream("/org/sonar/wsclient/issue/IssueParserTest/issue-with-projects.json")); + String json = IOUtils.toString(getClass().getResourceAsStream("/org/sonar/wsclient/issue/internal/IssueJsonParserTest/issue-with-projects.json")); Issues issues = new IssueJsonParser().parseIssues(json); assertThat(issues.projects()).hasSize(1); @@ -176,7 +182,7 @@ public class IssueJsonParserTest { @Test public void should_parse_action_plans() throws Exception { - String json = IOUtils.toString(getClass().getResourceAsStream("/org/sonar/wsclient/issue/IssueParserTest/issue-with-action-plans.json")); + String json = IOUtils.toString(getClass().getResourceAsStream("/org/sonar/wsclient/issue/internal/IssueJsonParserTest/issue-with-action-plans.json")); Issues issues = new IssueJsonParser().parseIssues(json); assertThat(issues.actionPlans()).hasSize(1); diff --git a/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/DefaultIssueClientTest/add_comment_result.json b/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/DefaultIssueClientTest/add_comment_result.json similarity index 100% rename from sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/DefaultIssueClientTest/add_comment_result.json rename to sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/DefaultIssueClientTest/add_comment_result.json diff --git a/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/IssueParserTest/empty.json b/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/empty.json similarity index 100% rename from sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/IssueParserTest/empty.json rename to sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/empty.json diff --git a/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/IssueParserTest/getTransitions.json b/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/getTransitions.json similarity index 100% rename from sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/IssueParserTest/getTransitions.json rename to sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/getTransitions.json diff --git a/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/IssueParserTest/issue-with-action-plans.json b/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/issue-with-action-plans.json similarity index 100% rename from sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/IssueParserTest/issue-with-action-plans.json rename to sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/issue-with-action-plans.json diff --git a/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/IssueParserTest/issue-with-comments.json b/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/issue-with-comments.json similarity index 100% rename from sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/IssueParserTest/issue-with-comments.json rename to sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/issue-with-comments.json diff --git a/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/IssueParserTest/issue-with-components.json b/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/issue-with-components.json similarity index 100% rename from sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/IssueParserTest/issue-with-components.json rename to sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/issue-with-components.json diff --git a/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/IssueParserTest/issue-with-projects.json b/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/issue-with-projects.json similarity index 100% rename from sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/IssueParserTest/issue-with-projects.json rename to sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/issue-with-projects.json diff --git a/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/IssueParserTest/issue-with-users.json b/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/issue-with-users.json similarity index 100% rename from sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/IssueParserTest/issue-with-users.json rename to sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/issue-with-users.json diff --git a/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/IssueParserTest/search.json b/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/search.json similarity index 100% rename from sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/IssueParserTest/search.json rename to sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/search.json -- 2.39.5