From: Simon Brandhof Date: Wed, 12 Jun 2013 21:28:00 +0000 (+0200) Subject: Improve error handling of ws-client X-Git-Tag: 3.7~491 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=9678ebc554ee2c2581268c956040e3ebc7adcb12;p=sonarqube.git Improve error handling of ws-client --- diff --git a/sonar-ws-client/pom.xml b/sonar-ws-client/pom.xml index 2b307d7c435..7b9135ea8e7 100644 --- a/sonar-ws-client/pom.xml +++ b/sonar-ws-client/pom.xml @@ -10,7 +10,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 @@ -133,10 +133,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/base/Paging.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/base/Paging.java new file mode 100644 index 00000000000..d803bdd956a --- /dev/null +++ b/sonar-ws-client/src/main/java/org/sonar/wsclient/base/Paging.java @@ -0,0 +1,57 @@ +/* + * 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.sonar.wsclient.unmarshallers.JsonUtils; + +import java.util.Map; + +/** + * @since 3.6 + */ +public class Paging { + + private final Map json; + + /** + * For internal use + */ + public Paging(Map json) { + this.json = json; + } + + public Integer pageSize() { + return JsonUtils.getInteger(json, "pageSize"); + } + + public Integer pageIndex() { + return JsonUtils.getInteger(json, "pageIndex"); + } + + public Integer total() { + return JsonUtils.getInteger(json, "total"); + } + + public Integer pages() { + return JsonUtils.getInteger(json, "pages"); + } + +} 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/DefaultActionPlanClient.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/DefaultActionPlanClient.java deleted file mode 100644 index 651800edeff..00000000000 --- a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/DefaultActionPlanClient.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * 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; - -import com.github.kevinsawicki.http.HttpRequest; -import org.json.simple.JSONValue; -import org.sonar.wsclient.internal.EncodingUtils; -import org.sonar.wsclient.internal.HttpRequestFactory; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -/** - * Do not instantiate this class, but use {@link org.sonar.wsclient.SonarClient#actionPlanClient()}. - */ -public class DefaultActionPlanClient implements ActionPlanClient { - - private final HttpRequestFactory requestFactory; - - /** - * For internal use. Use {@link org.sonar.wsclient.SonarClient} to get an instance. - */ - public DefaultActionPlanClient(HttpRequestFactory requestFactory) { - this.requestFactory = requestFactory; - } - - @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()); - } - List result = new ArrayList(); - String json = request.body("UTF-8"); - Map jsonRoot = (Map) JSONValue.parse(json); - List jsonActionPlans = (List) jsonRoot.get("actionPlans"); - if (jsonActionPlans != null) { - for (Map jsonActionPlan : jsonActionPlans) { - result.add(new ActionPlan(jsonActionPlan)); - } - } - return result; - } - - @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); - } - - @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); - } - - @Override - public void delete(String actionPlanKey) { - executeSimpleAction(actionPlanKey, "delete"); - } - - @Override - public ActionPlan open(String actionPlanKey) { - HttpRequest request = executeSimpleAction(actionPlanKey, "open"); - return createActionPlanResult(request); - } - - @Override - public ActionPlan close(String actionPlanKey) { - HttpRequest request = executeSimpleAction(actionPlanKey, "close"); - return createActionPlanResult(request); - } - - 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 ActionPlan createActionPlanResult(HttpRequest request){ - String json = request.body("UTF-8"); - Map jsonRoot = (Map) JSONValue.parse(json); - return new ActionPlan((Map) jsonRoot.get("actionPlan")); - } - -} 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/DefaultIssueClient.java deleted file mode 100644 index 4dd1972e2ba..00000000000 --- a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/DefaultIssueClient.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * 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; - -import com.github.kevinsawicki.http.HttpRequest; -import org.json.simple.JSONValue; -import org.sonar.wsclient.internal.EncodingUtils; -import org.sonar.wsclient.internal.HttpRequestFactory; - -import javax.annotation.Nullable; - -import java.util.List; -import java.util.Map; - -/** - * Do not instantiate this class, but use {@link org.sonar.wsclient.SonarClient#issueClient()}. - */ -public class DefaultIssueClient implements IssueClient { - - 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"); - 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); - } - - @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); - } - - @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); - } - - @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); - } - - @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")); - } - - @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"); - 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); - } - - @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"); - 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); - } - - private Issue createIssueResult(HttpRequest request){ - String json = request.body("UTF-8"); - Map jsonRoot = (Map) JSONValue.parse(json); - return new Issue((Map) jsonRoot.get("issue")); - } - -} 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/IssueJsonParser.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/IssueJsonParser.java deleted file mode 100644 index 906929ce308..00000000000 --- a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/IssueJsonParser.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * 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; - -import org.json.simple.JSONValue; -import org.sonar.wsclient.component.Component; -import org.sonar.wsclient.rule.Rule; -import org.sonar.wsclient.unmarshallers.JsonUtils; -import org.sonar.wsclient.user.User; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -/** - * @since 3.6 - */ -class IssueJsonParser { - - Issues parseIssues(String json) { - Issues result = new Issues(); - Map jsonRoot = (Map) JSONValue.parse(json); - List jsonIssues = (List) jsonRoot.get("issues"); - if (jsonIssues != null) { - for (Map jsonIssue : jsonIssues) { - result.add(new Issue(jsonIssue)); - } - } - parseRules(result, jsonRoot); - parseUsers(result, jsonRoot); - parseComponents(result, jsonRoot); - parseProjects(result, jsonRoot); - parseActionPlans(result, jsonRoot); - parsePaging(result, jsonRoot); - return result; - } - - private void parsePaging(Issues 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"); - if (jsonProjects != null) { - for (Map jsonProject : jsonProjects) { - result.addProject(new Component(jsonProject)); - } - } - } - - private void parseComponents(Issues result, Map jsonRoot) { - List jsonComponents = (List) jsonRoot.get("components"); - if (jsonComponents != null) { - for (Map jsonComponent : jsonComponents) { - result.addComponent(new Component(jsonComponent)); - } - } - } - - private void parseUsers(Issues result, Map jsonRoot) { - List jsonUsers = (List) jsonRoot.get("users"); - if (jsonUsers != null) { - for (Map jsonUser : jsonUsers) { - result.add(new User(jsonUser)); - } - } - } - - private void parseRules(Issues result, Map jsonRoot) { - List jsonRules = (List) jsonRoot.get("rules"); - if (jsonRules != null) { - for (Map jsonRule : jsonRules) { - result.add(new Rule(jsonRule)); - } - } - } - - private void parseActionPlans(Issues result, Map jsonRoot) { - List jsonRules = (List) jsonRoot.get("actionPlans"); - if (jsonRules != null) { - for (Map jsonRule : jsonRules) { - result.add(new ActionPlan(jsonRule)); - } - } - } - - List parseTransitions(String json) { - List transitions = new ArrayList(); - Map jRoot = (Map) JSONValue.parse(json); - List jTransitions = (List) jRoot.get("transitions"); - for (String jTransition : jTransitions) { - transitions.add(jTransition); - } - return transitions; - } - - List parseActions(String json) { - List actions = new ArrayList(); - Map jRoot = (Map) JSONValue.parse(json); - List jActions = (List) jRoot.get("actions"); - for (String jAction : jActions) { - actions.add(jAction); - } - return actions; - } -} 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/Paging.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/Paging.java deleted file mode 100644 index cd24f2beaf4..00000000000 --- a/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/Paging.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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; - -import org.sonar.wsclient.unmarshallers.JsonUtils; - -import java.util.Map; - -/** - * @since 3.6 - * TODO move outside this package - */ -public class Paging { - - private final Map json; - - Paging(Map json) { - this.json = json; - } - - public Integer pageSize() { - return JsonUtils.getInteger(json, "pageSize"); - } - - public Integer pageIndex() { - return JsonUtils.getInteger(json, "pageIndex"); - } - - public Integer total() { - return JsonUtils.getInteger(json, "total"); - } - - public Integer pages() { - return JsonUtils.getInteger(json, "pages"); - } - -} 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/internal/DefaultActionPlanClient.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/DefaultActionPlanClient.java new file mode 100644 index 00000000000..3a187b1d3e6 --- /dev/null +++ b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/DefaultActionPlanClient.java @@ -0,0 +1,97 @@ +/* + * 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.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; +import java.util.Map; + +/** + * Do not instantiate this class, but use {@link org.sonar.wsclient.SonarClient#actionPlanClient()}. + */ +public class DefaultActionPlanClient implements ActionPlanClient { + + private final HttpRequestFactory requestFactory; + + /** + * For internal use. Use {@link org.sonar.wsclient.SonarClient} to get an instance. + */ + public DefaultActionPlanClient(HttpRequestFactory requestFactory) { + this.requestFactory = requestFactory; + } + + @Override + public List find(String projectKey) { + String json = requestFactory.get(ActionPlanQuery.BASE_URL, EncodingUtils.toMap("project", projectKey)); + List result = new ArrayList(); + Map jsonRoot = (Map) JSONValue.parse(json); + List jsonActionPlans = (List) jsonRoot.get("actionPlans"); + if (jsonActionPlans != null) { + for (Map jsonActionPlan : jsonActionPlans) { + result.add(new DefaultActionPlan(jsonActionPlan)); + } + } + return result; + } + + @Override + public ActionPlan create(NewActionPlan newActionPlan) { + String json = requestFactory.post("/api/action_plans/create", newActionPlan.urlParams()); + return createActionPlanResult(json); + } + + @Override + public ActionPlan update(UpdateActionPlan updateActionPlan) { + String json = requestFactory.post("/api/action_plans/update", updateActionPlan.urlParams()); + return createActionPlanResult(json); + } + + @Override + public void delete(String actionPlanKey) { + executeSimpleAction(actionPlanKey, "delete"); + } + + @Override + public ActionPlan open(String actionPlanKey) { + String json = executeSimpleAction(actionPlanKey, "open"); + return createActionPlanResult(json); + } + + @Override + public ActionPlan close(String actionPlanKey) { + String json = executeSimpleAction(actionPlanKey, "close"); + return createActionPlanResult(json); + } + + private String executeSimpleAction(String actionPlanKey, String action) { + return requestFactory.post("/api/action_plans/" + action, EncodingUtils.toMap("key", actionPlanKey)); + } + + private ActionPlan createActionPlanResult(String json) { + Map jsonRoot = (Map) JSONValue.parse(json); + 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/internal/DefaultIssueClient.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/DefaultIssueClient.java new file mode 100644 index 00000000000..c4b2f326555 --- /dev/null +++ b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/DefaultIssueClient.java @@ -0,0 +1,119 @@ +/* + * 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.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; + +/** + * Do not instantiate this class, but use {@link org.sonar.wsclient.SonarClient#issueClient()}. + */ +public class DefaultIssueClient implements IssueClient { + + private static final String SEARCH_URL = "/api/issues/search"; + + private final HttpRequestFactory requestFactory; + private final IssueJsonParser parser; + + public DefaultIssueClient(HttpRequestFactory requestFactory) { + this.requestFactory = requestFactory; + this.parser = new IssueJsonParser(); + } + + public Issues find(IssueQuery query) { + String json = requestFactory.get(SEARCH_URL, query.urlParams()); + return parser.parseIssues(json); + } + + @Override + public Issue create(NewIssue newIssue) { + 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); + 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); + 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); + 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); + 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); + 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); + String json = requestFactory.post("/api/issues/do_transition", params); + return jsonToIssue(json); + } + + @Override + public List actions(String issueKey) { + Map queryParams = EncodingUtils.toMap("issue", issueKey); + 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); + String json = requestFactory.post("/api/issues/do_action", params); + return jsonToIssue(json); + } + + private Issue jsonToIssue(String json) { + Map jsonRoot = (Map) JSONValue.parse(json); + 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/internal/IssueJsonParser.java b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/IssueJsonParser.java new file mode 100644 index 00000000000..d123e9779cb --- /dev/null +++ b/sonar-ws-client/src/main/java/org/sonar/wsclient/issue/internal/IssueJsonParser.java @@ -0,0 +1,127 @@ +/* + * 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.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; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * @since 3.6 + */ +public class IssueJsonParser { + + public Issues parseIssues(String json) { + DefaultIssues result = new DefaultIssues(); + Map jsonRoot = (Map) JSONValue.parse(json); + List jsonIssues = (List) jsonRoot.get("issues"); + if (jsonIssues != null) { + for (Map jsonIssue : jsonIssues) { + result.add(new DefaultIssue(jsonIssue)); + } + } + parseRules(result, jsonRoot); + parseUsers(result, jsonRoot); + parseComponents(result, jsonRoot); + parseProjects(result, jsonRoot); + parseActionPlans(result, jsonRoot); + parsePaging(result, jsonRoot); + return result; + } + + 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(DefaultIssues result, Map jsonRoot) { + List jsonProjects = (List) jsonRoot.get("projects"); + if (jsonProjects != null) { + for (Map jsonProject : jsonProjects) { + result.addProject(new Component(jsonProject)); + } + } + } + + 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)); + } + } + } + + 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)); + } + } + } + + 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)); + } + } + } + + private void parseActionPlans(DefaultIssues result, Map jsonRoot) { + List jsonRules = (List) jsonRoot.get("actionPlans"); + if (jsonRules != null) { + for (Map jsonRule : jsonRules) { + result.add(new DefaultActionPlan(jsonRule)); + } + } + } + + List parseTransitions(String json) { + List transitions = new ArrayList(); + Map jRoot = (Map) JSONValue.parse(json); + List jTransitions = (List) jRoot.get("transitions"); + for (String jTransition : jTransitions) { + transitions.add(jTransition); + } + return transitions; + } + + List parseActions(String json) { + List actions = new ArrayList(); + Map jRoot = (Map) JSONValue.parse(json); + List jActions = (List) jRoot.get("actions"); + for (String jAction : jActions) { + actions.add(jAction); + } + return actions; + } +} 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/DefaultActionPlanClientTest.java b/sonar-ws-client/src/test/java/org/sonar/wsclient/issue/DefaultActionPlanClientTest.java deleted file mode 100644 index e56572fc2b1..00000000000 --- a/sonar-ws-client/src/test/java/org/sonar/wsclient/issue/DefaultActionPlanClientTest.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * 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; - -import org.junit.Rule; -import org.junit.Test; -import org.sonar.wsclient.MockHttpServerInterceptor; -import org.sonar.wsclient.internal.HttpRequestFactory; - -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.List; - -import static org.fest.assertions.Assertions.assertThat; -import static org.fest.assertions.Fail.fail; - -public class DefaultActionPlanClientTest { - - @Rule - public MockHttpServerInterceptor httpServer = new MockHttpServerInterceptor(); - - @Test - public void should_find_action_plans() { - HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url()); - httpServer.doReturnBody("{\"actionPlans\": [{\"key\": \"382f6f2e-ad9d-424a-b973-9b065e04348a\",\n" + - "\"name\": \"Long term\",\n" + - "\"status\": \"CLOSED\",\n" + - "\"project\": \"com.sonarsource.it.samples:simple-sample\",\n" + - "\"userLogin\": \"admin\",\n" + - "\"deadLine\": \"2013-05-30T00:00:00+0200\",\n" + - "\"totalIssues\": 3,\n" + - "\"unresolvedIssues\": 2,\n" + - "\"createdAt\": \"2013-05-13T12:50:29+0200\",\n" + - "\"updatedAt\": \"2013-05-13T12:50:44+0200\"}]}"); - - ActionPlanClient client = new DefaultActionPlanClient(requestFactory); - List actionPlans = client.find("com.sonarsource.it.samples:simple-sample"); - - assertThat(httpServer.requestedPath()).isEqualTo("/api/action_plans/search?project=com.sonarsource.it.samples:simple-sample"); - assertThat(actionPlans).hasSize(1); - ActionPlan actionPlan = actionPlans.get(0); - assertThat(actionPlan.key()).isEqualTo("382f6f2e-ad9d-424a-b973-9b065e04348a"); - assertThat(actionPlan.name()).isEqualTo("Long term"); - assertThat(actionPlan.project()).isEqualTo("com.sonarsource.it.samples:simple-sample"); - assertThat(actionPlan.status()).isEqualTo("CLOSED"); - assertThat(actionPlan.userLogin()).isEqualTo("admin"); - assertThat(actionPlan.deadLine()).isNotNull(); - assertThat(actionPlan.totalIssues()).isEqualTo(3); - assertThat(actionPlan.unresolvedIssues()).isEqualTo(2); - assertThat(actionPlan.createdAt()).isNotNull(); - assertThat(actionPlan.updatedAt()).isNotNull(); - } - - @Test - public void should_create_action_plan() throws Exception { - HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url()); - httpServer.doReturnBody("{\"actionPlan\": {\"key\": \"382f6f2e-ad9d-424a-b973-9b065e04348a\"}}"); - - ActionPlanClient client = new DefaultActionPlanClient(requestFactory); - ActionPlan result = client.create( - NewActionPlan.create().name("Short term").project("org.sonar.Sample").description("Short term issues").deadLine(stringToDate("2014-01-01"))); - - assertThat(httpServer.requestedPath()).isEqualTo("/api/action_plans/create?project=org.sonar.Sample&description=Short%20term%20issues&name=Short%20term&deadLine=2014-01-01"); - assertThat(result).isNotNull(); - } - - @Test - public void should_update_action_plan() { - HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url()); - httpServer.doReturnBody("{\"actionPlan\": {\"key\": \"382f6f2e-ad9d-424a-b973-9b065e04348a\"}}"); - - ActionPlanClient client = new DefaultActionPlanClient(requestFactory); - ActionPlan result = client.update( - UpdateActionPlan.create().key("382f6f2e-ad9d-424a-b973-9b065e04348a").name("Short term").description("Short term issues").deadLine(stringToDate("2014-01-01"))); - - assertThat(httpServer.requestedPath()).isEqualTo("/api/action_plans/update?description=Short%20term%20issues&name=Short%20term&deadLine=2014-01-01&key=382f6f2e-ad9d-424a-b973-9b065e04348a"); - assertThat(result).isNotNull(); - } - - @Test - public void should_delete_action_plan() { - HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url()); - - ActionPlanClient client = new DefaultActionPlanClient(requestFactory); - client.delete("382f6f2e-ad9d-424a-b973-9b065e04348a"); - - assertThat(httpServer.requestedPath()).isEqualTo("/api/action_plans/delete?key=382f6f2e-ad9d-424a-b973-9b065e04348a"); - } - - @Test - public void should_fail_to_delete_action_plan() { - HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url()); - httpServer.doReturnStatus(500); - - ActionPlanClient client = new DefaultActionPlanClient(requestFactory); - 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"); - } - } - - @Test - public void should_open_action_plan() { - HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url()); - httpServer.doReturnBody("{\"actionPlan\": {\"key\": \"382f6f2e-ad9d-424a-b973-9b065e04348a\"}}"); - - ActionPlanClient client = new DefaultActionPlanClient(requestFactory); - ActionPlan result = client.open("382f6f2e-ad9d-424a-b973-9b065e04348a"); - - assertThat(httpServer.requestedPath()).isEqualTo("/api/action_plans/open?key=382f6f2e-ad9d-424a-b973-9b065e04348a"); - assertThat(result).isNotNull(); - } - - @Test - public void should_close_action_plan() { - HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url()); - httpServer.doReturnBody("{\"actionPlan\": {\"key\": \"382f6f2e-ad9d-424a-b973-9b065e04348a\"}}"); - - ActionPlanClient client = new DefaultActionPlanClient(requestFactory); - ActionPlan result = client.close("382f6f2e-ad9d-424a-b973-9b065e04348a"); - - assertThat(httpServer.requestedPath()).isEqualTo("/api/action_plans/close?key=382f6f2e-ad9d-424a-b973-9b065e04348a"); - assertThat(result).isNotNull(); - } - - private static Date stringToDate(String sDate) { - try { - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-dd-MM"); - return sdf.parse(sDate); - } catch (ParseException e) { - throw new RuntimeException(e); - } - } - -} 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/DefaultIssueClientTest.java deleted file mode 100644 index 7ad6f6df3c8..00000000000 --- a/sonar-ws-client/src/test/java/org/sonar/wsclient/issue/DefaultIssueClientTest.java +++ /dev/null @@ -1,212 +0,0 @@ -/* - * 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; - -import org.apache.commons.io.IOUtils; -import org.junit.Rule; -import org.junit.Test; -import org.sonar.wsclient.MockHttpServerInterceptor; -import org.sonar.wsclient.internal.HttpRequestFactory; - -import java.util.List; - -import static org.fest.assertions.Assertions.assertThat; -import static org.fest.assertions.Fail.fail; - -public class DefaultIssueClientTest { - @Rule - public MockHttpServerInterceptor httpServer = new MockHttpServerInterceptor(); - - @Test - public void should_find_issues() { - HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url()); - httpServer.doReturnBody("{\"issues\": [{\"key\": \"ABCDE\"}]}"); - - IssueClient client = new DefaultIssueClient(requestFactory); - IssueQuery query = IssueQuery.create().issues("ABCDE"); - Issues issues = client.find(query); - - assertThat(httpServer.requestedPath()).isEqualTo("/api/issues/search?issues=ABCDE"); - assertThat(issues.list()).hasSize(1); - assertThat(issues.list().get(0).key()).isEqualTo("ABCDE"); - } - - @Test - public void should_fail_to_find_issues() { - HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url()); - httpServer.doReturnStatus(500); - - IssueClient client = new DefaultIssueClient(requestFactory); - try { - client.find(IssueQuery.create()); - fail(); - } catch (IllegalStateException e) { - assertThat(e).hasMessage("Fail to search for issues. Bad HTTP response status: 500"); - } - } - - @Test - public void should_set_severity() { - HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url()); - httpServer.doReturnBody("{\"issue\": {\"key\": \"ABCDE\"}}"); - - IssueClient client = new DefaultIssueClient(requestFactory); - Issue result = client.setSeverity("ABCDE", "BLOCKER"); - - assertThat(httpServer.requestedPath()).isEqualTo("/api/issues/set_severity?issue=ABCDE&severity=BLOCKER"); - assertThat(result).isNotNull(); - } - - @Test - public void should_assign() { - HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url()); - httpServer.doReturnBody("{\"issue\": {\"key\": \"ABCDE\"}}"); - - IssueClient client = new DefaultIssueClient(requestFactory); - Issue result = client.assign("ABCDE", "emmerik"); - - assertThat(httpServer.requestedPath()).isEqualTo("/api/issues/assign?issue=ABCDE&assignee=emmerik"); - assertThat(result).isNotNull(); - } - - @Test - public void should_unassign() { - HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url()); - httpServer.doReturnBody("{\"issue\": {\"key\": \"ABCDE\"}}"); - - IssueClient client = new DefaultIssueClient(requestFactory); - Issue result = client.assign("ABCDE", null); - - assertThat(httpServer.requestedPath()).isEqualTo("/api/issues/assign?issue=ABCDE"); - assertThat(result).isNotNull(); - } - - @Test - public void should_plan() { - HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url()); - httpServer.doReturnBody("{\"issue\": {\"key\": \"ABCDE\"}}"); - - IssueClient client = new DefaultIssueClient(requestFactory); - Issue result = client.plan("ABCDE", "DEFGH"); - - assertThat(httpServer.requestedPath()).isEqualTo("/api/issues/plan?issue=ABCDE&plan=DEFGH"); - assertThat(result).isNotNull(); - } - - @Test - public void should_unplan() { - HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url()); - httpServer.doReturnBody("{\"issue\": {\"key\": \"ABCDE\"}}"); - - IssueClient client = new DefaultIssueClient(requestFactory); - Issue result = client.plan("ABCDE", null); - - assertThat(httpServer.requestedPath()).isEqualTo("/api/issues/plan?issue=ABCDE"); - assertThat(result).isNotNull(); - } - - @Test - public void should_create_issue() { - HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url()); - httpServer.doReturnBody("{\"issue\": {\"key\": \"ABCDE\"}}"); - - IssueClient client = new DefaultIssueClient(requestFactory); - Issue result = client.create(NewIssue.create().component("Action.java").rule("squid:AvoidCycle")); - - assertThat(httpServer.requestedPath()).isEqualTo("/api/issues/create?component=Action.java&rule=squid:AvoidCycle"); - assertThat(result).isNotNull(); - } - - @Test - public void should_get_transitions() { - HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url()); - httpServer.doReturnBody("{\n" + - " \"transitions\": [\n" + - " \"resolve\",\n" + - " \"falsepositive\"\n" + - " ]\n" + - "}"); - - IssueClient client = new DefaultIssueClient(requestFactory); - List transitions = client.transitions("ABCDE"); - - assertThat(httpServer.requestedPath()).isEqualTo("/api/issues/transitions?issue=ABCDE"); - assertThat(transitions).hasSize(2); - assertThat(transitions).containsOnly("resolve", "falsepositive"); - } - - @Test - public void should_apply_transition() { - HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url()); - httpServer.doReturnBody("{\"issue\": {\"key\": \"ABCDE\"}}"); - - IssueClient client = new DefaultIssueClient(requestFactory); - Issue result = client.doTransition("ABCDE", "resolve"); - - assertThat(httpServer.requestedPath()).isEqualTo("/api/issues/do_transition?issue=ABCDE&transition=resolve"); - assertThat(result).isNotNull(); - } - - @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"))); - - IssueClient client = new DefaultIssueClient(requestFactory); - IssueComment comment = client.addComment("ISSUE-1", "this is my comment"); - - assertThat(httpServer.requestedPath()).isEqualTo("/api/issues/add_comment?issue=ISSUE-1&text=this%20is%20my%20comment"); - assertThat(comment).isNotNull(); - assertThat(comment.key()).isEqualTo("COMMENT-123"); - assertThat(comment.htmlText()).isEqualTo("this is my comment"); - assertThat(comment.login()).isEqualTo("admin"); - assertThat(comment.createdAt().getDate()).isEqualTo(18); - } - - @Test - public void should_get_actions() { - HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url()); - httpServer.doReturnBody("{\n" + - " \"actions\": [\n" + - " \"link-to-jira\",\n" + - " \"tweet\"\n" + - " ]\n" + - "}"); - - IssueClient client = new DefaultIssueClient(requestFactory); - List actions = client.actions("ABCDE"); - - assertThat(httpServer.requestedPath()).isEqualTo("/api/issues/actions?issue=ABCDE"); - assertThat(actions).hasSize(2); - assertThat(actions).containsOnly("link-to-jira", "tweet"); - } - - @Test - public void should_apply_action() { - HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url()); - httpServer.doReturnBody("{\"issue\": {\"key\": \"ABCDE\"}}"); - - IssueClient client = new DefaultIssueClient(requestFactory); - Issue result = client.doAction("ABCDE", "tweet"); - - assertThat(httpServer.requestedPath()).isEqualTo("/api/issues/do_action?issue=ABCDE&actionKey=tweet"); - assertThat(result).isNotNull(); - } -} 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/IssueJsonParserTest.java deleted file mode 100644 index 09cb3941742..00000000000 --- a/sonar-ws-client/src/test/java/org/sonar/wsclient/issue/IssueJsonParserTest.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * 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; - -import org.apache.commons.io.IOUtils; -import org.junit.Test; -import org.sonar.wsclient.component.Component; -import org.sonar.wsclient.user.User; - -import java.util.List; - -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")); - Issues issues = new IssueJsonParser().parseIssues(json); - assertThat(issues).isNotNull(); - List list = issues.list(); - assertThat(list).hasSize(2); - Issue first = list.get(0); - assertThat(first.key()).isEqualTo("ABCDE"); - assertThat(first.componentKey()).isEqualTo("Action.java"); - assertThat(first.projectKey()).isEqualTo("struts"); - assertThat(first.ruleKey()).isEqualTo("squid:CycleBetweenPackages"); - assertThat(first.severity()).isEqualTo("CRITICAL"); - assertThat(first.line()).isEqualTo(10); - assertThat(first.resolution()).isEqualTo("FIXED"); - assertThat(first.status()).isEqualTo("OPEN"); - assertThat(first.assignee()).isEqualTo("karadoc"); - assertThat(first.message()).isEqualTo("the message"); - assertThat(first.effortToFix()).isEqualTo(4.2); - assertThat(first.reporter()).isEqualTo("perceval"); - assertThat(first.author()).isEqualTo("pirlouis"); - assertThat(first.actionPlan()).isEqualTo("9450b10c-e725-48b8-bf01-acdec751c491"); - assertThat(first.creationDate()).isNotNull(); - assertThat(first.updateDate()).isNotNull(); - assertThat(first.closeDate()).isNotNull(); - assertThat(first.attribute("JIRA")).isEqualTo("FOO-1234"); - assertThat(first.attribute("OTHER")).isNull(); - assertThat(first.attributes()).hasSize(1); - assertThat(first.comments()).isEmpty(); - - Issue second = list.get(1); - assertThat(second.key()).isEqualTo("FGHIJ"); - assertThat(second.line()).isNull(); - assertThat(second.effortToFix()).isNull(); - assertThat(second.reporter()).isNull(); - assertThat(second.author()).isNull(); - assertThat(second.attribute("JIRA")).isNull(); - assertThat(second.attributes()).isEmpty(); - assertThat(second.comments()).isEmpty(); - - assertThat(issues.rules()).hasSize(2); - assertThat(issues.rule(first).key()).isEqualTo("squid:CycleBetweenPackages"); - assertThat(issues.rule(first).name()).isEqualTo("Avoid cycle between java packages"); - assertThat(issues.rule(first).description()).contains("When several packages"); - - assertThat(issues.paging()).isNotNull(); - Paging paging = issues.paging(); - assertThat(paging.pageIndex()).isEqualTo(1); - assertThat(paging.pageSize()).isEqualTo(100); - assertThat(paging.pages()).isEqualTo(1); - assertThat(paging.total()).isEqualTo(2); - - assertThat(issues.maxResultsReached()).isTrue(); - } - - @Test - public void test_GET_empty_search() throws Exception { - String json = IOUtils.toString(getClass().getResourceAsStream("/org/sonar/wsclient/issue/IssueParserTest/empty.json")); - Issues issues = new IssueJsonParser().parseIssues(json); - assertThat(issues).isNotNull(); - assertThat(issues.list()).isEmpty(); - assertThat(issues.rules()).isEmpty(); - assertThat(issues.maxResultsReached()).isFalse(); - } - - @Test - public void test_GET_transitions() throws Exception { - String json = IOUtils.toString(getClass().getResourceAsStream("/org/sonar/wsclient/issue/IssueParserTest/getTransitions.json")); - List transitions = new IssueJsonParser().parseTransitions(json); - - assertThat(transitions).isNotNull(); - assertThat(transitions).hasSize(2); - assertThat(transitions).containsOnly("resolve", "falsepositive"); - } - - @Test - public void should_parse_comments() throws Exception { - String json = IOUtils.toString(getClass().getResourceAsStream("/org/sonar/wsclient/issue/IssueParserTest/issue-with-comments.json")); - Issues issues = new IssueJsonParser().parseIssues(json); - assertThat(issues.size()).isEqualTo(1); - - Issue issue = issues.list().get(0); - assertThat(issue.comments()).hasSize(2); - - IssueComment firstComment = issue.comments().get(0); - assertThat(firstComment.key()).isEqualTo("COMMENT-1"); - assertThat(firstComment.login()).isEqualTo("morgan"); - assertThat(firstComment.htmlText()).isEqualTo("the first comment"); - assertThat(firstComment.createdAt().getDate()).isEqualTo(18); - - IssueComment secondComment = issue.comments().get(1); - assertThat(secondComment.key()).isEqualTo("COMMENT-2"); - assertThat(secondComment.login()).isEqualTo("arthur"); - assertThat(secondComment.htmlText()).isEqualTo("the second comment"); - assertThat(secondComment.createdAt().getDate()).isEqualTo(19); - } - - @Test - public void should_parse_users() throws Exception { - String json = IOUtils.toString(getClass().getResourceAsStream("/org/sonar/wsclient/issue/IssueParserTest/issue-with-users.json")); - Issues issues = new IssueJsonParser().parseIssues(json); - - assertThat(issues.users()).hasSize(2); - - User morgan = issues.user("morgan"); - assertThat(morgan.login()).isEqualTo("morgan"); - assertThat(morgan.name()).isEqualTo("Morgan"); - assertThat(morgan.active()).isTrue(); - assertThat(morgan.email()).isEqualTo("mor@gan.bzh"); - - User arthur = issues.user("arthur"); - assertThat(arthur.login()).isEqualTo("arthur"); - assertThat(arthur.name()).isEqualTo("Arthur"); - assertThat(arthur.active()).isFalse(); - assertThat(arthur.email()).isEqualTo("ar@thur.bzh"); - } - - @Test - public void should_parse_components() throws Exception { - String json = IOUtils.toString(getClass().getResourceAsStream("/org/sonar/wsclient/issue/IssueParserTest/issue-with-components.json")); - Issues issues = new IssueJsonParser().parseIssues(json); - - assertThat(issues.components()).hasSize(1); - - Component component = issues.component(issues.list().get(0)); - assertThat(component.key()).isEqualTo("struts:Action.java"); - assertThat(component.qualifier()).isEqualTo("CLA"); - assertThat(component.name()).isEqualTo("Action"); - assertThat(component.longName()).isEqualTo("org.struts.Action"); - } - - @Test - public void should_parse_projects() throws Exception { - String json = IOUtils.toString(getClass().getResourceAsStream("/org/sonar/wsclient/issue/IssueParserTest/issue-with-projects.json")); - Issues issues = new IssueJsonParser().parseIssues(json); - - assertThat(issues.projects()).hasSize(1); - - Component component = issues.project(issues.list().get(0)); - assertThat(component.key()).isEqualTo("struts"); - assertThat(component.qualifier()).isEqualTo("TRK"); - assertThat(component.name()).isEqualTo("Struts"); - assertThat(component.longName()).isEqualTo("org.struts"); - } - - @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")); - Issues issues = new IssueJsonParser().parseIssues(json); - - assertThat(issues.actionPlans()).hasSize(1); - - ActionPlan actionPlan = issues.actionPlans(issues.list().get(0)); - assertThat(actionPlan.key()).isEqualTo("9450b10c-e725-48b8-bf01-acdec751c491"); - assertThat(actionPlan.name()).isEqualTo("3.6"); - assertThat(actionPlan.status()).isEqualTo("OPEN"); - assertThat(actionPlan.project()).isEqualTo("struts"); - assertThat(actionPlan.deadLine().getTime()).isEqualTo(1369951200000l); - assertThat(actionPlan.createdAt().getTime()).isEqualTo(1369828520000l); - assertThat(actionPlan.updatedAt().getTime()).isEqualTo(1369828520000l); - } -} 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/internal/DefaultActionPlanClientTest.java b/sonar-ws-client/src/test/java/org/sonar/wsclient/issue/internal/DefaultActionPlanClientTest.java new file mode 100644 index 00000000000..2e74730df14 --- /dev/null +++ b/sonar-ws-client/src/test/java/org/sonar/wsclient/issue/internal/DefaultActionPlanClientTest.java @@ -0,0 +1,163 @@ +/* + * 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.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; +import java.util.Date; +import java.util.List; + +import static org.fest.assertions.Assertions.assertThat; +import static org.fest.assertions.Fail.fail; + +public class DefaultActionPlanClientTest { + + @Rule + public MockHttpServerInterceptor httpServer = new MockHttpServerInterceptor(); + + @Test + public void should_find_action_plans() { + HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url()); + httpServer.doReturnBody("{\"actionPlans\": [{\"key\": \"382f6f2e-ad9d-424a-b973-9b065e04348a\",\n" + + "\"name\": \"Long term\",\n" + + "\"status\": \"CLOSED\",\n" + + "\"project\": \"com.sonarsource.it.samples:simple-sample\",\n" + + "\"userLogin\": \"admin\",\n" + + "\"deadLine\": \"2013-05-30T00:00:00+0200\",\n" + + "\"totalIssues\": 3,\n" + + "\"unresolvedIssues\": 2,\n" + + "\"createdAt\": \"2013-05-13T12:50:29+0200\",\n" + + "\"updatedAt\": \"2013-05-13T12:50:44+0200\"}]}"); + + ActionPlanClient client = new DefaultActionPlanClient(requestFactory); + List actionPlans = client.find("com.sonarsource.it.samples:simple-sample"); + + assertThat(httpServer.requestedPath()).isEqualTo("/api/action_plans/search?project=com.sonarsource.it.samples:simple-sample"); + assertThat(actionPlans).hasSize(1); + ActionPlan actionPlan = actionPlans.get(0); + assertThat(actionPlan.key()).isEqualTo("382f6f2e-ad9d-424a-b973-9b065e04348a"); + assertThat(actionPlan.name()).isEqualTo("Long term"); + assertThat(actionPlan.project()).isEqualTo("com.sonarsource.it.samples:simple-sample"); + assertThat(actionPlan.status()).isEqualTo("CLOSED"); + assertThat(actionPlan.userLogin()).isEqualTo("admin"); + assertThat(actionPlan.deadLine()).isNotNull(); + assertThat(actionPlan.totalIssues()).isEqualTo(3); + assertThat(actionPlan.unresolvedIssues()).isEqualTo(2); + assertThat(actionPlan.createdAt()).isNotNull(); + assertThat(actionPlan.updatedAt()).isNotNull(); + } + + @Test + public void should_create_action_plan() throws Exception { + HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url()); + httpServer.doReturnBody("{\"actionPlan\": {\"key\": \"382f6f2e-ad9d-424a-b973-9b065e04348a\"}}"); + + ActionPlanClient client = new DefaultActionPlanClient(requestFactory); + ActionPlan result = client.create( + NewActionPlan.create().name("Short term").project("org.sonar.Sample").description("Short term issues").deadLine(stringToDate("2014-01-01"))); + + assertThat(httpServer.requestedPath()).isEqualTo("/api/action_plans/create?project=org.sonar.Sample&description=Short%20term%20issues&name=Short%20term&deadLine=2014-01-01"); + assertThat(result).isNotNull(); + } + + @Test + public void should_update_action_plan() { + HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url()); + httpServer.doReturnBody("{\"actionPlan\": {\"key\": \"382f6f2e-ad9d-424a-b973-9b065e04348a\"}}"); + + ActionPlanClient client = new DefaultActionPlanClient(requestFactory); + ActionPlan result = client.update( + UpdateActionPlan.create().key("382f6f2e-ad9d-424a-b973-9b065e04348a").name("Short term").description("Short term issues").deadLine(stringToDate("2014-01-01"))); + + assertThat(httpServer.requestedPath()).isEqualTo("/api/action_plans/update?description=Short%20term%20issues&name=Short%20term&deadLine=2014-01-01&key=382f6f2e-ad9d-424a-b973-9b065e04348a"); + assertThat(result).isNotNull(); + } + + @Test + public void should_delete_action_plan() { + HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url()); + + ActionPlanClient client = new DefaultActionPlanClient(requestFactory); + client.delete("382f6f2e-ad9d-424a-b973-9b065e04348a"); + + assertThat(httpServer.requestedPath()).isEqualTo("/api/action_plans/delete?key=382f6f2e-ad9d-424a-b973-9b065e04348a"); + } + + @Test + public void should_fail_to_delete_action_plan() { + HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url()); + httpServer.doReturnStatus(500); + + ActionPlanClient client = new DefaultActionPlanClient(requestFactory); + try { + client.delete("382f6f2e-ad9d-424a-b973-9b065e04348a"); + fail(); + } 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"); + } + } + + @Test + public void should_open_action_plan() { + HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url()); + httpServer.doReturnBody("{\"actionPlan\": {\"key\": \"382f6f2e-ad9d-424a-b973-9b065e04348a\"}}"); + + ActionPlanClient client = new DefaultActionPlanClient(requestFactory); + ActionPlan result = client.open("382f6f2e-ad9d-424a-b973-9b065e04348a"); + + assertThat(httpServer.requestedPath()).isEqualTo("/api/action_plans/open?key=382f6f2e-ad9d-424a-b973-9b065e04348a"); + assertThat(result).isNotNull(); + } + + @Test + public void should_close_action_plan() { + HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url()); + httpServer.doReturnBody("{\"actionPlan\": {\"key\": \"382f6f2e-ad9d-424a-b973-9b065e04348a\"}}"); + + ActionPlanClient client = new DefaultActionPlanClient(requestFactory); + ActionPlan result = client.close("382f6f2e-ad9d-424a-b973-9b065e04348a"); + + assertThat(httpServer.requestedPath()).isEqualTo("/api/action_plans/close?key=382f6f2e-ad9d-424a-b973-9b065e04348a"); + assertThat(result).isNotNull(); + } + + private static Date stringToDate(String sDate) { + try { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-dd-MM"); + return sdf.parse(sDate); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/sonar-ws-client/src/test/java/org/sonar/wsclient/issue/internal/DefaultIssueClientTest.java b/sonar-ws-client/src/test/java/org/sonar/wsclient/issue/internal/DefaultIssueClientTest.java new file mode 100644 index 00000000000..d262073e26e --- /dev/null +++ b/sonar-ws-client/src/test/java/org/sonar/wsclient/issue/internal/DefaultIssueClientTest.java @@ -0,0 +1,217 @@ +/* + * 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.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; + +import static org.fest.assertions.Assertions.assertThat; +import static org.fest.assertions.Fail.fail; + +public class DefaultIssueClientTest { + @Rule + public MockHttpServerInterceptor httpServer = new MockHttpServerInterceptor(); + + @Test + public void should_find_issues() { + HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url()); + httpServer.doReturnBody("{\"issues\": [{\"key\": \"ABCDE\"}]}"); + + IssueClient client = new DefaultIssueClient(requestFactory); + IssueQuery query = IssueQuery.create().issues("ABCDE"); + Issues issues = client.find(query); + + assertThat(httpServer.requestedPath()).isEqualTo("/api/issues/search?issues=ABCDE"); + assertThat(issues.list()).hasSize(1); + assertThat(issues.list().get(0).key()).isEqualTo("ABCDE"); + } + + @Test + public void should_fail_to_find_issues() { + HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url()); + httpServer.doReturnStatus(500); + + IssueClient client = new DefaultIssueClient(requestFactory); + try { + client.find(IssueQuery.create()); + fail(); + } catch (HttpException e) { + assertThat(e.status()).isEqualTo(500); + assertThat(e.url()).startsWith("http://localhost"); + assertThat(e.url()).endsWith("/api/issues/search"); + } + } + + @Test + public void should_set_severity() { + HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url()); + httpServer.doReturnBody("{\"issue\": {\"key\": \"ABCDE\"}}"); + + IssueClient client = new DefaultIssueClient(requestFactory); + Issue result = client.setSeverity("ABCDE", "BLOCKER"); + + assertThat(httpServer.requestedPath()).isEqualTo("/api/issues/set_severity?issue=ABCDE&severity=BLOCKER"); + assertThat(result).isNotNull(); + } + + @Test + public void should_assign() { + HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url()); + httpServer.doReturnBody("{\"issue\": {\"key\": \"ABCDE\"}}"); + + IssueClient client = new DefaultIssueClient(requestFactory); + Issue result = client.assign("ABCDE", "emmerik"); + + assertThat(httpServer.requestedPath()).isEqualTo("/api/issues/assign?issue=ABCDE&assignee=emmerik"); + assertThat(result).isNotNull(); + } + + @Test + public void should_unassign() { + HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url()); + httpServer.doReturnBody("{\"issue\": {\"key\": \"ABCDE\"}}"); + + IssueClient client = new DefaultIssueClient(requestFactory); + Issue result = client.assign("ABCDE", null); + + assertThat(httpServer.requestedPath()).isEqualTo("/api/issues/assign?issue=ABCDE"); + assertThat(result).isNotNull(); + } + + @Test + public void should_plan() { + HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url()); + httpServer.doReturnBody("{\"issue\": {\"key\": \"ABCDE\"}}"); + + IssueClient client = new DefaultIssueClient(requestFactory); + Issue result = client.plan("ABCDE", "DEFGH"); + + assertThat(httpServer.requestedPath()).isEqualTo("/api/issues/plan?issue=ABCDE&plan=DEFGH"); + assertThat(result).isNotNull(); + } + + @Test + public void should_unplan() { + HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url()); + httpServer.doReturnBody("{\"issue\": {\"key\": \"ABCDE\"}}"); + + IssueClient client = new DefaultIssueClient(requestFactory); + Issue result = client.plan("ABCDE", null); + + assertThat(httpServer.requestedPath()).isEqualTo("/api/issues/plan?issue=ABCDE"); + assertThat(result).isNotNull(); + } + + @Test + public void should_create_issue() { + HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url()); + httpServer.doReturnBody("{\"issue\": {\"key\": \"ABCDE\"}}"); + + IssueClient client = new DefaultIssueClient(requestFactory); + Issue result = client.create(NewIssue.create().component("Action.java").rule("squid:AvoidCycle")); + + assertThat(httpServer.requestedPath()).isEqualTo("/api/issues/create?component=Action.java&rule=squid:AvoidCycle"); + assertThat(result).isNotNull(); + } + + @Test + public void should_get_transitions() { + HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url()); + httpServer.doReturnBody("{\n" + + " \"transitions\": [\n" + + " \"resolve\",\n" + + " \"falsepositive\"\n" + + " ]\n" + + "}"); + + IssueClient client = new DefaultIssueClient(requestFactory); + List transitions = client.transitions("ABCDE"); + + assertThat(httpServer.requestedPath()).isEqualTo("/api/issues/transitions?issue=ABCDE"); + assertThat(transitions).hasSize(2); + assertThat(transitions).containsOnly("resolve", "falsepositive"); + } + + @Test + public void should_apply_transition() { + HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url()); + httpServer.doReturnBody("{\"issue\": {\"key\": \"ABCDE\"}}"); + + IssueClient client = new DefaultIssueClient(requestFactory); + Issue result = client.doTransition("ABCDE", "resolve"); + + assertThat(httpServer.requestedPath()).isEqualTo("/api/issues/do_transition?issue=ABCDE&transition=resolve"); + assertThat(result).isNotNull(); + } + + @Test + public void should_add_comment() throws Exception { + HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url()); + 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"); + + assertThat(httpServer.requestedPath()).isEqualTo("/api/issues/add_comment?issue=ISSUE-1&text=this%20is%20my%20comment"); + assertThat(comment).isNotNull(); + assertThat(comment.key()).isEqualTo("COMMENT-123"); + assertThat(comment.htmlText()).isEqualTo("this is my comment"); + assertThat(comment.login()).isEqualTo("admin"); + assertThat(comment.createdAt().getDate()).isEqualTo(18); + } + + @Test + public void should_get_actions() { + HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url()); + httpServer.doReturnBody("{\n" + + " \"actions\": [\n" + + " \"link-to-jira\",\n" + + " \"tweet\"\n" + + " ]\n" + + "}"); + + IssueClient client = new DefaultIssueClient(requestFactory); + List actions = client.actions("ABCDE"); + + assertThat(httpServer.requestedPath()).isEqualTo("/api/issues/actions?issue=ABCDE"); + assertThat(actions).hasSize(2); + assertThat(actions).containsOnly("link-to-jira", "tweet"); + } + + @Test + public void should_apply_action() { + HttpRequestFactory requestFactory = new HttpRequestFactory(httpServer.url()); + httpServer.doReturnBody("{\"issue\": {\"key\": \"ABCDE\"}}"); + + IssueClient client = new DefaultIssueClient(requestFactory); + Issue result = client.doAction("ABCDE", "tweet"); + + assertThat(httpServer.requestedPath()).isEqualTo("/api/issues/do_action?issue=ABCDE&actionKey=tweet"); + assertThat(result).isNotNull(); + } +} diff --git a/sonar-ws-client/src/test/java/org/sonar/wsclient/issue/internal/IssueJsonParserTest.java b/sonar-ws-client/src/test/java/org/sonar/wsclient/issue/internal/IssueJsonParserTest.java new file mode 100644 index 00000000000..c84bfe8c001 --- /dev/null +++ b/sonar-ws-client/src/test/java/org/sonar/wsclient/issue/internal/IssueJsonParserTest.java @@ -0,0 +1,199 @@ +/* + * 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.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; + +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/internal/IssueJsonParserTest/search.json")); + Issues issues = new IssueJsonParser().parseIssues(json); + assertThat(issues).isNotNull(); + List list = issues.list(); + assertThat(list).hasSize(2); + Issue first = list.get(0); + assertThat(first.key()).isEqualTo("ABCDE"); + assertThat(first.componentKey()).isEqualTo("Action.java"); + assertThat(first.projectKey()).isEqualTo("struts"); + assertThat(first.ruleKey()).isEqualTo("squid:CycleBetweenPackages"); + assertThat(first.severity()).isEqualTo("CRITICAL"); + assertThat(first.line()).isEqualTo(10); + assertThat(first.resolution()).isEqualTo("FIXED"); + assertThat(first.status()).isEqualTo("OPEN"); + assertThat(first.assignee()).isEqualTo("karadoc"); + assertThat(first.message()).isEqualTo("the message"); + assertThat(first.effortToFix()).isEqualTo(4.2); + assertThat(first.reporter()).isEqualTo("perceval"); + assertThat(first.author()).isEqualTo("pirlouis"); + assertThat(first.actionPlan()).isEqualTo("9450b10c-e725-48b8-bf01-acdec751c491"); + assertThat(first.creationDate()).isNotNull(); + assertThat(first.updateDate()).isNotNull(); + assertThat(first.closeDate()).isNotNull(); + assertThat(first.attribute("JIRA")).isEqualTo("FOO-1234"); + assertThat(first.attribute("OTHER")).isNull(); + assertThat(first.attributes()).hasSize(1); + assertThat(first.comments()).isEmpty(); + + Issue second = list.get(1); + assertThat(second.key()).isEqualTo("FGHIJ"); + assertThat(second.line()).isNull(); + assertThat(second.effortToFix()).isNull(); + assertThat(second.reporter()).isNull(); + assertThat(second.author()).isNull(); + assertThat(second.attribute("JIRA")).isNull(); + assertThat(second.attributes()).isEmpty(); + assertThat(second.comments()).isEmpty(); + + assertThat(issues.rules()).hasSize(2); + assertThat(issues.rule(first).key()).isEqualTo("squid:CycleBetweenPackages"); + assertThat(issues.rule(first).name()).isEqualTo("Avoid cycle between java packages"); + assertThat(issues.rule(first).description()).contains("When several packages"); + + assertThat(issues.paging()).isNotNull(); + Paging paging = issues.paging(); + assertThat(paging.pageIndex()).isEqualTo(1); + assertThat(paging.pageSize()).isEqualTo(100); + assertThat(paging.pages()).isEqualTo(1); + assertThat(paging.total()).isEqualTo(2); + + assertThat(issues.maxResultsReached()).isTrue(); + } + + @Test + public void test_GET_empty_search() throws Exception { + 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(); + assertThat(issues.rules()).isEmpty(); + assertThat(issues.maxResultsReached()).isFalse(); + } + + @Test + public void test_GET_transitions() throws Exception { + String json = IOUtils.toString(getClass().getResourceAsStream("/org/sonar/wsclient/issue/internal/IssueJsonParserTest/getTransitions.json")); + List transitions = new IssueJsonParser().parseTransitions(json); + + assertThat(transitions).isNotNull(); + assertThat(transitions).hasSize(2); + assertThat(transitions).containsOnly("resolve", "falsepositive"); + } + + @Test + public void should_parse_comments() throws Exception { + 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); + + Issue issue = issues.list().get(0); + assertThat(issue.comments()).hasSize(2); + + IssueComment firstComment = issue.comments().get(0); + assertThat(firstComment.key()).isEqualTo("COMMENT-1"); + assertThat(firstComment.login()).isEqualTo("morgan"); + assertThat(firstComment.htmlText()).isEqualTo("the first comment"); + assertThat(firstComment.createdAt().getDate()).isEqualTo(18); + + IssueComment secondComment = issue.comments().get(1); + assertThat(secondComment.key()).isEqualTo("COMMENT-2"); + assertThat(secondComment.login()).isEqualTo("arthur"); + assertThat(secondComment.htmlText()).isEqualTo("the second comment"); + assertThat(secondComment.createdAt().getDate()).isEqualTo(19); + } + + @Test + public void should_parse_users() throws Exception { + 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); + + User morgan = issues.user("morgan"); + assertThat(morgan.login()).isEqualTo("morgan"); + assertThat(morgan.name()).isEqualTo("Morgan"); + assertThat(morgan.active()).isTrue(); + assertThat(morgan.email()).isEqualTo("mor@gan.bzh"); + + User arthur = issues.user("arthur"); + assertThat(arthur.login()).isEqualTo("arthur"); + assertThat(arthur.name()).isEqualTo("Arthur"); + assertThat(arthur.active()).isFalse(); + assertThat(arthur.email()).isEqualTo("ar@thur.bzh"); + } + + @Test + public void should_parse_components() throws Exception { + 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); + + Component component = issues.component(issues.list().get(0)); + assertThat(component.key()).isEqualTo("struts:Action.java"); + assertThat(component.qualifier()).isEqualTo("CLA"); + assertThat(component.name()).isEqualTo("Action"); + assertThat(component.longName()).isEqualTo("org.struts.Action"); + } + + @Test + public void should_parse_projects() throws Exception { + 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); + + Component component = issues.project(issues.list().get(0)); + assertThat(component.key()).isEqualTo("struts"); + assertThat(component.qualifier()).isEqualTo("TRK"); + assertThat(component.name()).isEqualTo("Struts"); + assertThat(component.longName()).isEqualTo("org.struts"); + } + + @Test + public void should_parse_action_plans() throws Exception { + 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); + + ActionPlan actionPlan = issues.actionPlans(issues.list().get(0)); + assertThat(actionPlan.key()).isEqualTo("9450b10c-e725-48b8-bf01-acdec751c491"); + assertThat(actionPlan.name()).isEqualTo("3.6"); + assertThat(actionPlan.status()).isEqualTo("OPEN"); + assertThat(actionPlan.project()).isEqualTo("struts"); + assertThat(actionPlan.deadLine().getTime()).isEqualTo(1369951200000l); + assertThat(actionPlan.createdAt().getTime()).isEqualTo(1369828520000l); + assertThat(actionPlan.updatedAt().getTime()).isEqualTo(1369828520000l); + } +} 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/DefaultIssueClientTest/add_comment_result.json deleted file mode 100644 index 7329cc86d24..00000000000 --- a/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/DefaultIssueClientTest/add_comment_result.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "comment": { - "key": "COMMENT-123", - "htmlText": "this is my comment", - "login": "admin", - "createdAt": "2013-05-18T13:45:34+0200" - } -} \ No newline at end of file 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/IssueParserTest/empty.json deleted file mode 100644 index b3712e0d503..00000000000 --- a/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/IssueParserTest/empty.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "paging": { - "pageIndex": 1, - "pageSize": 100, - "total": 0, - "pages": 0 - }, - "maxResultsReached": false -} \ No newline at end of file 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/IssueParserTest/getTransitions.json deleted file mode 100644 index 0451945c9d1..00000000000 --- a/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/IssueParserTest/getTransitions.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "transitions": [ - "resolve", - "falsepositive" - ] -} \ No newline at end of file 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/IssueParserTest/issue-with-action-plans.json deleted file mode 100644 index 46718d5b39f..00000000000 --- a/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/IssueParserTest/issue-with-action-plans.json +++ /dev/null @@ -1,71 +0,0 @@ -{ - "issues": [ - { - "key": "ABCDE", - "component": "struts:Action.java", - "project": "struts", - "rule": "squid:CycleBetweenPackages", - "severity": "CRITICAL", - "status": "OPEN", - "actionPlan": "9450b10c-e725-48b8-bf01-acdec751c491", - "comments": [ - { - "key": "COMMENT-1", - "login": "morgan", - "htmlText": "the first comment", - "createdAt": "2013-05-18T13:45:34+0200" - }, - { - "key": "COMMENT-2", - "login": "arthur", - "htmlText": "the second comment", - "createdAt": "2013-06-19T00:02:03+0100" - } - ] - } - ], - "rules": [ - { - - "key": "squid:CycleBetweenPackages", - "name": "Avoid cycle between java packages", - "desc": "

\nWhen several packages are involved in a cycle (package A > package B > package C > package A where \">\" means \"depends upon\"),\nthat means that those packages are highly coupled and that there is no way to reuse/extract one of those packages without importing all the other packages.\nSuch cycle could quickly increase the effort required to maintain an application and to embrace business change.\nSonar not only detect cycles between packages but also determines what is the minimum effort to break those cycles.\nThis rule log a violation on each source file having an outgoing dependency to be but in order to break a cycle.\n

\n" - - } - ], - "components": [ - { - "key": "struts:Action.java", - "name": "Action", - "qualifier": "CLA", - "longName": "org.struts.Action" - } - ], - "projects": [ - { - "key": "struts", - "name": "Struts", - "qualifier": "TRK", - "longName": "org.struts" - } - ], - "actionPlans": [ - { - "key": "9450b10c-e725-48b8-bf01-acdec751c491", - "name": "3.6", - "status": "OPEN", - "project": "struts", - "userLogin": "arthur", - "deadLine": "2013-05-31T00:00:00+0200", - "createdAt": "2013-05-29T13:55:20+0200", - "updatedAt": "2013-05-29T13:55:20+0200" - } - ], - "paging": { - "pageIndex": 1, - "pageSize": 100, - "total": 2, - "pages": 1 - }, - "maxResultsReached": false -} \ No newline at end of file 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/IssueParserTest/issue-with-comments.json deleted file mode 100644 index 5118aaee009..00000000000 --- a/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/IssueParserTest/issue-with-comments.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "issues": [ - { - "key": "ABCDE", - "component": "Action.java", - "project": "struts", - "rule": "squid:CycleBetweenPackages", - "severity": "CRITICAL", - "status": "OPEN", - "comments": [ - { - "key": "COMMENT-1", - "login": "morgan", - "htmlText": "the first comment", - "createdAt": "2013-05-18T13:45:34+0200" - }, - { - "key": "COMMENT-2", - "login": "arthur", - "htmlText": "the second comment", - "createdAt": "2013-06-19T00:02:03+0100" - } - ] - } - ], - "rules": [ - { - - "key": "squid:CycleBetweenPackages", - "name": "Avoid cycle between java packages", - "desc": "

\nWhen several packages are involved in a cycle (package A > package B > package C > package A where \">\" means \"depends upon\"),\nthat means that those packages are highly coupled and that there is no way to reuse/extract one of those packages without importing all the other packages.\nSuch cycle could quickly increase the effort required to maintain an application and to embrace business change.\nSonar not only detect cycles between packages but also determines what is the minimum effort to break those cycles.\nThis rule log a violation on each source file having an outgoing dependency to be but in order to break a cycle.\n

\n" - - } - ], - "paging": { - "pageIndex": 1, - "pageSize": 100, - "total": 2, - "pages": 1 - }, - "maxResultsReached": false -} \ No newline at end of file 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/IssueParserTest/issue-with-components.json deleted file mode 100644 index 2f331712d3c..00000000000 --- a/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/IssueParserTest/issue-with-components.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "issues": [ - { - "key": "ABCDE", - "component": "struts:Action.java", - "project": "struts", - "rule": "squid:CycleBetweenPackages", - "severity": "CRITICAL", - "status": "OPEN", - "comments": [ - { - "key": "COMMENT-1", - "login": "morgan", - "htmlText": "the first comment", - "createdAt": "2013-05-18T13:45:34+0200" - }, - { - "key": "COMMENT-2", - "login": "arthur", - "htmlText": "the second comment", - "createdAt": "2013-06-19T00:02:03+0100" - } - ] - } - ], - "rules": [ - { - - "key": "squid:CycleBetweenPackages", - "name": "Avoid cycle between java packages", - "desc": "

\nWhen several packages are involved in a cycle (package A > package B > package C > package A where \">\" means \"depends upon\"),\nthat means that those packages are highly coupled and that there is no way to reuse/extract one of those packages without importing all the other packages.\nSuch cycle could quickly increase the effort required to maintain an application and to embrace business change.\nSonar not only detect cycles between packages but also determines what is the minimum effort to break those cycles.\nThis rule log a violation on each source file having an outgoing dependency to be but in order to break a cycle.\n

\n" - - } - ], - "components": [ - { - "key": "struts:Action.java", - "name": "Action", - "qualifier": "CLA", - "longName": "org.struts.Action" - } - ], - "paging": { - "pageIndex": 1, - "pageSize": 100, - "total": 2, - "pages": 1 - }, - "maxResultsReached": false -} \ No newline at end of file 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/IssueParserTest/issue-with-projects.json deleted file mode 100644 index a5e4ea7cd9d..00000000000 --- a/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/IssueParserTest/issue-with-projects.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "issues": [ - { - "key": "ABCDE", - "component": "struts:Action.java", - "project": "struts", - "rule": "squid:CycleBetweenPackages", - "severity": "CRITICAL", - "status": "OPEN", - "comments": [ - { - "key": "COMMENT-1", - "login": "morgan", - "htmlText": "the first comment", - "createdAt": "2013-05-18T13:45:34+0200" - }, - { - "key": "COMMENT-2", - "login": "arthur", - "htmlText": "the second comment", - "createdAt": "2013-06-19T00:02:03+0100" - } - ] - } - ], - "rules": [ - { - - "key": "squid:CycleBetweenPackages", - "name": "Avoid cycle between java packages", - "desc": "

\nWhen several packages are involved in a cycle (package A > package B > package C > package A where \">\" means \"depends upon\"),\nthat means that those packages are highly coupled and that there is no way to reuse/extract one of those packages without importing all the other packages.\nSuch cycle could quickly increase the effort required to maintain an application and to embrace business change.\nSonar not only detect cycles between packages but also determines what is the minimum effort to break those cycles.\nThis rule log a violation on each source file having an outgoing dependency to be but in order to break a cycle.\n

\n" - - } - ], - "components": [ - { - "key": "struts:Action.java", - "name": "Action", - "qualifier": "CLA", - "longName": "org.struts.Action" - } - ], - "projects": [ - { - "key": "struts", - "name": "Struts", - "qualifier": "TRK", - "longName": "org.struts" - } - ], - "paging": { - "pageIndex": 1, - "pageSize": 100, - "total": 2, - "pages": 1 - }, - "maxResultsReached": false -} \ No newline at end of file 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/IssueParserTest/issue-with-users.json deleted file mode 100644 index 7d8bc6586a4..00000000000 --- a/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/IssueParserTest/issue-with-users.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "issues": [ - { - "key": "ABCDE", - "component": "Action.java", - "project": "struts", - "rule": "squid:CycleBetweenPackages", - "severity": "CRITICAL", - "status": "OPEN", - "comments": [ - { - "key": "COMMENT-1", - "login": "morgan", - "htmlText": "the first comment", - "createdAt": "2013-05-18T13:45:34+0200" - }, - { - "key": "COMMENT-2", - "login": "arthur", - "htmlText": "the second comment", - "createdAt": "2013-06-19T00:02:03+0100" - } - ] - } - ], - "rules": [ - { - - "key": "squid:CycleBetweenPackages", - "name": "Avoid cycle between java packages", - "desc": "

\nWhen several packages are involved in a cycle (package A > package B > package C > package A where \">\" means \"depends upon\"),\nthat means that those packages are highly coupled and that there is no way to reuse/extract one of those packages without importing all the other packages.\nSuch cycle could quickly increase the effort required to maintain an application and to embrace business change.\nSonar not only detect cycles between packages but also determines what is the minimum effort to break those cycles.\nThis rule log a violation on each source file having an outgoing dependency to be but in order to break a cycle.\n

\n" - - } - ], - "users": [ - { - "login": "morgan", - "name": "Morgan", - "active": true, - "email": "mor@gan.bzh" - }, - { - "login": "arthur", - "name": "Arthur", - "active": false, - "email": "ar@thur.bzh" - } - ], - "paging": { - "pageIndex": 1, - "pageSize": 100, - "total": 2, - "pages": 1 - }, - "maxResultsReached": false -} \ No newline at end of file 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/IssueParserTest/search.json deleted file mode 100644 index 8c8505f5d73..00000000000 --- a/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/IssueParserTest/search.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "issues": [ - { - "key": "ABCDE", - "component": "Action.java", - "project": "struts", - "rule": "squid:CycleBetweenPackages", - "severity": "CRITICAL", - "line": 10, - "resolution": "FIXED", - "status": "OPEN", - "assignee": "karadoc", - "effortToFix": 4.2, - "message": "the message", - "title": "the title", - "reporter": "perceval", - "author": "pirlouis", - "actionPlan": "9450b10c-e725-48b8-bf01-acdec751c491", - "creationDate": "2013-05-18T12:45:34+0200", - "updateDate": "2013-05-18T13:45:34+0200", - "closeDate": "2013-05-18T14:45:34+0200", - "attr": { - "JIRA": "FOO-1234" - } - }, - { - "key": "FGHIJ", - "component": "Filter.java", - "project": "struts", - "rule": "checkstyle:com.puppycrawl.tools.checkstyle.checks.imports.UnusedImportsCheck", - "severity": "BLOCKER", - "resolution": "FIXED", - "status": "OPEN" - } - ], - "rules": [ - { - - "key": "squid:CycleBetweenPackages", - "name": "Avoid cycle between java packages", - "desc": "

\nWhen several packages are involved in a cycle (package A > package B > package C > package A where \">\" means \"depends upon\"),\nthat means that those packages are highly coupled and that there is no way to reuse/extract one of those packages without importing all the other packages.\nSuch cycle could quickly increase the effort required to maintain an application and to embrace business change.\nSonar not only detect cycles between packages but also determines what is the minimum effort to break those cycles.\nThis rule log a violation on each source file having an outgoing dependency to be but in order to break a cycle.\n

\n" - - }, - { - "key": "checkstyle:com.puppycrawl.tools.checkstyle.checks.imports.UnusedImportsCheck", - "name": "Unused Imports", - "desc": "Checks for unused import statements." - } - ], - "paging": { - "pageIndex": 1, - "pageSize": 100, - "total": 2, - "pages": 1 - }, - "maxResultsReached": true -} \ No newline at end of file diff --git a/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/DefaultIssueClientTest/add_comment_result.json b/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/DefaultIssueClientTest/add_comment_result.json new file mode 100644 index 00000000000..7329cc86d24 --- /dev/null +++ b/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/DefaultIssueClientTest/add_comment_result.json @@ -0,0 +1,8 @@ +{ + "comment": { + "key": "COMMENT-123", + "htmlText": "this is my comment", + "login": "admin", + "createdAt": "2013-05-18T13:45:34+0200" + } +} \ No newline at end of file diff --git a/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/empty.json b/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/empty.json new file mode 100644 index 00000000000..b3712e0d503 --- /dev/null +++ b/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/empty.json @@ -0,0 +1,9 @@ +{ + "paging": { + "pageIndex": 1, + "pageSize": 100, + "total": 0, + "pages": 0 + }, + "maxResultsReached": false +} \ No newline at end of file diff --git a/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/getTransitions.json b/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/getTransitions.json new file mode 100644 index 00000000000..0451945c9d1 --- /dev/null +++ b/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/getTransitions.json @@ -0,0 +1,6 @@ +{ + "transitions": [ + "resolve", + "falsepositive" + ] +} \ No newline at end of file diff --git a/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/issue-with-action-plans.json b/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/issue-with-action-plans.json new file mode 100644 index 00000000000..46718d5b39f --- /dev/null +++ b/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/issue-with-action-plans.json @@ -0,0 +1,71 @@ +{ + "issues": [ + { + "key": "ABCDE", + "component": "struts:Action.java", + "project": "struts", + "rule": "squid:CycleBetweenPackages", + "severity": "CRITICAL", + "status": "OPEN", + "actionPlan": "9450b10c-e725-48b8-bf01-acdec751c491", + "comments": [ + { + "key": "COMMENT-1", + "login": "morgan", + "htmlText": "the first comment", + "createdAt": "2013-05-18T13:45:34+0200" + }, + { + "key": "COMMENT-2", + "login": "arthur", + "htmlText": "the second comment", + "createdAt": "2013-06-19T00:02:03+0100" + } + ] + } + ], + "rules": [ + { + + "key": "squid:CycleBetweenPackages", + "name": "Avoid cycle between java packages", + "desc": "

\nWhen several packages are involved in a cycle (package A > package B > package C > package A where \">\" means \"depends upon\"),\nthat means that those packages are highly coupled and that there is no way to reuse/extract one of those packages without importing all the other packages.\nSuch cycle could quickly increase the effort required to maintain an application and to embrace business change.\nSonar not only detect cycles between packages but also determines what is the minimum effort to break those cycles.\nThis rule log a violation on each source file having an outgoing dependency to be but in order to break a cycle.\n

\n" + + } + ], + "components": [ + { + "key": "struts:Action.java", + "name": "Action", + "qualifier": "CLA", + "longName": "org.struts.Action" + } + ], + "projects": [ + { + "key": "struts", + "name": "Struts", + "qualifier": "TRK", + "longName": "org.struts" + } + ], + "actionPlans": [ + { + "key": "9450b10c-e725-48b8-bf01-acdec751c491", + "name": "3.6", + "status": "OPEN", + "project": "struts", + "userLogin": "arthur", + "deadLine": "2013-05-31T00:00:00+0200", + "createdAt": "2013-05-29T13:55:20+0200", + "updatedAt": "2013-05-29T13:55:20+0200" + } + ], + "paging": { + "pageIndex": 1, + "pageSize": 100, + "total": 2, + "pages": 1 + }, + "maxResultsReached": false +} \ No newline at end of file diff --git a/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/issue-with-comments.json b/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/issue-with-comments.json new file mode 100644 index 00000000000..5118aaee009 --- /dev/null +++ b/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/issue-with-comments.json @@ -0,0 +1,42 @@ +{ + "issues": [ + { + "key": "ABCDE", + "component": "Action.java", + "project": "struts", + "rule": "squid:CycleBetweenPackages", + "severity": "CRITICAL", + "status": "OPEN", + "comments": [ + { + "key": "COMMENT-1", + "login": "morgan", + "htmlText": "the first comment", + "createdAt": "2013-05-18T13:45:34+0200" + }, + { + "key": "COMMENT-2", + "login": "arthur", + "htmlText": "the second comment", + "createdAt": "2013-06-19T00:02:03+0100" + } + ] + } + ], + "rules": [ + { + + "key": "squid:CycleBetweenPackages", + "name": "Avoid cycle between java packages", + "desc": "

\nWhen several packages are involved in a cycle (package A > package B > package C > package A where \">\" means \"depends upon\"),\nthat means that those packages are highly coupled and that there is no way to reuse/extract one of those packages without importing all the other packages.\nSuch cycle could quickly increase the effort required to maintain an application and to embrace business change.\nSonar not only detect cycles between packages but also determines what is the minimum effort to break those cycles.\nThis rule log a violation on each source file having an outgoing dependency to be but in order to break a cycle.\n

\n" + + } + ], + "paging": { + "pageIndex": 1, + "pageSize": 100, + "total": 2, + "pages": 1 + }, + "maxResultsReached": false +} \ No newline at end of file diff --git a/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/issue-with-components.json b/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/issue-with-components.json new file mode 100644 index 00000000000..2f331712d3c --- /dev/null +++ b/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/issue-with-components.json @@ -0,0 +1,50 @@ +{ + "issues": [ + { + "key": "ABCDE", + "component": "struts:Action.java", + "project": "struts", + "rule": "squid:CycleBetweenPackages", + "severity": "CRITICAL", + "status": "OPEN", + "comments": [ + { + "key": "COMMENT-1", + "login": "morgan", + "htmlText": "the first comment", + "createdAt": "2013-05-18T13:45:34+0200" + }, + { + "key": "COMMENT-2", + "login": "arthur", + "htmlText": "the second comment", + "createdAt": "2013-06-19T00:02:03+0100" + } + ] + } + ], + "rules": [ + { + + "key": "squid:CycleBetweenPackages", + "name": "Avoid cycle between java packages", + "desc": "

\nWhen several packages are involved in a cycle (package A > package B > package C > package A where \">\" means \"depends upon\"),\nthat means that those packages are highly coupled and that there is no way to reuse/extract one of those packages without importing all the other packages.\nSuch cycle could quickly increase the effort required to maintain an application and to embrace business change.\nSonar not only detect cycles between packages but also determines what is the minimum effort to break those cycles.\nThis rule log a violation on each source file having an outgoing dependency to be but in order to break a cycle.\n

\n" + + } + ], + "components": [ + { + "key": "struts:Action.java", + "name": "Action", + "qualifier": "CLA", + "longName": "org.struts.Action" + } + ], + "paging": { + "pageIndex": 1, + "pageSize": 100, + "total": 2, + "pages": 1 + }, + "maxResultsReached": false +} \ No newline at end of file diff --git a/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/issue-with-projects.json b/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/issue-with-projects.json new file mode 100644 index 00000000000..a5e4ea7cd9d --- /dev/null +++ b/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/issue-with-projects.json @@ -0,0 +1,58 @@ +{ + "issues": [ + { + "key": "ABCDE", + "component": "struts:Action.java", + "project": "struts", + "rule": "squid:CycleBetweenPackages", + "severity": "CRITICAL", + "status": "OPEN", + "comments": [ + { + "key": "COMMENT-1", + "login": "morgan", + "htmlText": "the first comment", + "createdAt": "2013-05-18T13:45:34+0200" + }, + { + "key": "COMMENT-2", + "login": "arthur", + "htmlText": "the second comment", + "createdAt": "2013-06-19T00:02:03+0100" + } + ] + } + ], + "rules": [ + { + + "key": "squid:CycleBetweenPackages", + "name": "Avoid cycle between java packages", + "desc": "

\nWhen several packages are involved in a cycle (package A > package B > package C > package A where \">\" means \"depends upon\"),\nthat means that those packages are highly coupled and that there is no way to reuse/extract one of those packages without importing all the other packages.\nSuch cycle could quickly increase the effort required to maintain an application and to embrace business change.\nSonar not only detect cycles between packages but also determines what is the minimum effort to break those cycles.\nThis rule log a violation on each source file having an outgoing dependency to be but in order to break a cycle.\n

\n" + + } + ], + "components": [ + { + "key": "struts:Action.java", + "name": "Action", + "qualifier": "CLA", + "longName": "org.struts.Action" + } + ], + "projects": [ + { + "key": "struts", + "name": "Struts", + "qualifier": "TRK", + "longName": "org.struts" + } + ], + "paging": { + "pageIndex": 1, + "pageSize": 100, + "total": 2, + "pages": 1 + }, + "maxResultsReached": false +} \ No newline at end of file diff --git a/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/issue-with-users.json b/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/issue-with-users.json new file mode 100644 index 00000000000..7d8bc6586a4 --- /dev/null +++ b/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/issue-with-users.json @@ -0,0 +1,56 @@ +{ + "issues": [ + { + "key": "ABCDE", + "component": "Action.java", + "project": "struts", + "rule": "squid:CycleBetweenPackages", + "severity": "CRITICAL", + "status": "OPEN", + "comments": [ + { + "key": "COMMENT-1", + "login": "morgan", + "htmlText": "the first comment", + "createdAt": "2013-05-18T13:45:34+0200" + }, + { + "key": "COMMENT-2", + "login": "arthur", + "htmlText": "the second comment", + "createdAt": "2013-06-19T00:02:03+0100" + } + ] + } + ], + "rules": [ + { + + "key": "squid:CycleBetweenPackages", + "name": "Avoid cycle between java packages", + "desc": "

\nWhen several packages are involved in a cycle (package A > package B > package C > package A where \">\" means \"depends upon\"),\nthat means that those packages are highly coupled and that there is no way to reuse/extract one of those packages without importing all the other packages.\nSuch cycle could quickly increase the effort required to maintain an application and to embrace business change.\nSonar not only detect cycles between packages but also determines what is the minimum effort to break those cycles.\nThis rule log a violation on each source file having an outgoing dependency to be but in order to break a cycle.\n

\n" + + } + ], + "users": [ + { + "login": "morgan", + "name": "Morgan", + "active": true, + "email": "mor@gan.bzh" + }, + { + "login": "arthur", + "name": "Arthur", + "active": false, + "email": "ar@thur.bzh" + } + ], + "paging": { + "pageIndex": 1, + "pageSize": 100, + "total": 2, + "pages": 1 + }, + "maxResultsReached": false +} \ No newline at end of file diff --git a/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/search.json b/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/search.json new file mode 100644 index 00000000000..8c8505f5d73 --- /dev/null +++ b/sonar-ws-client/src/test/resources/org/sonar/wsclient/issue/internal/IssueJsonParserTest/search.json @@ -0,0 +1,57 @@ +{ + "issues": [ + { + "key": "ABCDE", + "component": "Action.java", + "project": "struts", + "rule": "squid:CycleBetweenPackages", + "severity": "CRITICAL", + "line": 10, + "resolution": "FIXED", + "status": "OPEN", + "assignee": "karadoc", + "effortToFix": 4.2, + "message": "the message", + "title": "the title", + "reporter": "perceval", + "author": "pirlouis", + "actionPlan": "9450b10c-e725-48b8-bf01-acdec751c491", + "creationDate": "2013-05-18T12:45:34+0200", + "updateDate": "2013-05-18T13:45:34+0200", + "closeDate": "2013-05-18T14:45:34+0200", + "attr": { + "JIRA": "FOO-1234" + } + }, + { + "key": "FGHIJ", + "component": "Filter.java", + "project": "struts", + "rule": "checkstyle:com.puppycrawl.tools.checkstyle.checks.imports.UnusedImportsCheck", + "severity": "BLOCKER", + "resolution": "FIXED", + "status": "OPEN" + } + ], + "rules": [ + { + + "key": "squid:CycleBetweenPackages", + "name": "Avoid cycle between java packages", + "desc": "

\nWhen several packages are involved in a cycle (package A > package B > package C > package A where \">\" means \"depends upon\"),\nthat means that those packages are highly coupled and that there is no way to reuse/extract one of those packages without importing all the other packages.\nSuch cycle could quickly increase the effort required to maintain an application and to embrace business change.\nSonar not only detect cycles between packages but also determines what is the minimum effort to break those cycles.\nThis rule log a violation on each source file having an outgoing dependency to be but in order to break a cycle.\n

\n" + + }, + { + "key": "checkstyle:com.puppycrawl.tools.checkstyle.checks.imports.UnusedImportsCheck", + "name": "Unused Imports", + "desc": "Checks for unused import statements." + } + ], + "paging": { + "pageIndex": 1, + "pageSize": 100, + "total": 2, + "pages": 1 + }, + "maxResultsReached": true +} \ No newline at end of file