]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-7290 Add changelog action in IssueClient from ws-client 1452/head
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Mon, 12 Dec 2016 16:52:19 +0000 (17:52 +0100)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Tue, 13 Dec 2016 15:15:07 +0000 (16:15 +0100)
it/it-tests/src/test/java/it/authorisation/IssuePermissionTest.java
it/it-tests/src/test/java/it/issue/IssueChangelogTest.java
it/it-tests/src/test/java/it/qualityModel/TechnicalDebtInIssueChangelogTest.java
server/sonar-server/src/main/java/org/sonar/server/issue/ws/ChangelogAction.java
server/sonar-server/src/main/java/org/sonar/server/issue/ws/IssuesWs.java
server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionComponentsMediumTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionMediumTest.java
sonar-ws/src/main/java/org/sonarqube/ws/client/issue/IssuesService.java
sonar-ws/src/main/java/org/sonarqube/ws/client/issue/IssuesWsParameters.java
sonar-ws/src/test/java/org/sonarqube/ws/client/issue/IssuesServiceTest.java [new file with mode: 0644]

index 0ae2fa15ce06e7a59dbaa69a8c47b840c46b222e..93a7e4189396c9acc6447bd9396deef0e60b8b4a 100644 (file)
@@ -33,6 +33,7 @@ import org.sonar.wsclient.issue.BulkChangeQuery;
 import org.sonar.wsclient.issue.Issue;
 import org.sonar.wsclient.issue.IssueQuery;
 import org.sonar.wsclient.user.UserParameters;
+import org.sonarqube.ws.Issues;
 import org.sonarqube.ws.client.WsClient;
 import org.sonarqube.ws.client.permission.AddUserWsRequest;
 import org.sonarqube.ws.client.permission.RemoveGroupWsRequest;
@@ -40,6 +41,7 @@ import org.sonarqube.ws.client.permission.RemoveGroupWsRequest;
 import static junit.framework.TestCase.fail;
 import static org.assertj.core.api.Assertions.assertThat;
 import static util.ItUtils.newAdminWsClient;
+import static util.ItUtils.newUserWsClient;
 import static util.ItUtils.projectDir;
 
 public class IssuePermissionTest {
@@ -122,14 +124,14 @@ public class IssuePermissionTest {
 
       // Without user permission, a user cannot see issue changelog on the project
       try {
-        orchestrator.getServer().wsClient(withoutBrowsePermission, "password").issueClient().changes(issue.key());
+        changelog(issue.key(), withoutBrowsePermission, "password");
         fail();
       } catch (Exception e) {
-        assertThat(e).isInstanceOf(HttpException.class).describedAs("404");
+        assertThat(e).isInstanceOf(org.sonarqube.ws.client.HttpException.class).describedAs("403");
       }
 
       // Without user permission, a user cannot see issues on the project
-      assertThat(orchestrator.getServer().wsClient(withBrowsePermission, "password").issueClient().changes(issue.key())).isNotEmpty();
+      assertThat(changelog(issue.key(), withBrowsePermission, "password").getChangelogList()).isNotEmpty();
 
     } finally {
       client.userClient().deactivate(withBrowsePermission);
@@ -242,4 +244,8 @@ public class IssuePermissionTest {
       .setProjectKey(projectKey)
       .setPermission(permission));
   }
+
+  private static Issues.ChangelogWsResponse changelog(String issueKey, String login, String password) {
+    return newUserWsClient(orchestrator, login, password).issues().changelog(issueKey);
+  }
 }
index f4a1d58b038c5e1503cf4152d4c6811cf1174611..75a0c78d6be18382d17888f39d10ebfdd77bdd6f 100644 (file)
@@ -24,12 +24,14 @@ import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.sonar.wsclient.issue.Issue;
-import org.sonar.wsclient.issue.IssueChange;
-import org.sonar.wsclient.issue.IssueChangeDiff;
+import org.sonarqube.ws.Issues;
+import org.sonarqube.ws.Issues.ChangelogWsResponse.Changelog;
 import util.ProjectAnalysis;
 import util.ProjectAnalysisRule;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.tuple;
+import static util.ItUtils.newAdminWsClient;
 
 public class IssueChangelogTest extends AbstractIssueTest {
 
@@ -54,16 +56,14 @@ public class IssueChangelogTest extends AbstractIssueTest {
 
     adminIssueClient().assign(issue.key(), "admin");
 
-    List<IssueChange> changes = retrieveChangeForIssue(issue.key());
+    List<Changelog> changes = changelog(issue.key()).getChangelogList();
     assertThat(changes).hasSize(1);
-    IssueChange change = changes.get(0);
-    assertThat(change.user()).isEqualTo("admin");
-    assertThat(change.creationDate()).isNotNull();
-    assertThat(change.diffs()).hasSize(1);
-    IssueChangeDiff changeDiff = change.diffs().get(0);
-    assertThat(changeDiff.key()).isEqualTo("assignee");
-    assertThat(changeDiff.oldValue()).isNull();
-    assertThat(changeDiff.newValue()).isEqualTo("Administrator");
+    Changelog change = changes.get(0);
+    assertThat(change.getUser()).isEqualTo("admin");
+    assertThat(change.getCreationDate()).isNotNull();
+    assertThat(change.getDiffsList())
+      .extracting(Changelog.Diff::getKey, Changelog.Diff::hasOldValue, Changelog.Diff::getNewValue)
+      .containsOnly(tuple("assignee", false, "Administrator"));
   }
 
   @Test
@@ -74,48 +74,32 @@ public class IssueChangelogTest extends AbstractIssueTest {
     adminIssueClient().doTransition(issue.key(), "resolve");
     xooSampleAnalysis.run();
 
-    List<IssueChange> changes = retrieveChangeForIssue(issue.key());
+    List<Changelog> changes = changelog(issue.key()).getChangelogList();
     assertThat(changes).hasSize(2);
 
     // Change done by the user (first change is be the oldest one)
-    IssueChange change1 = changes.get(0);
-    assertThat(change1.user()).isEqualTo("admin");
-    assertThat(change1.creationDate()).isNotNull();
-    assertThat(change1.diffs()).hasSize(2);
-
-    IssueChangeDiff change1Diff1 = change1.diffs().get(0);
-    assertThat(change1Diff1.key()).isEqualTo("resolution");
-    assertThat(change1Diff1.oldValue()).isNull();
-    assertThat(change1Diff1.newValue()).isEqualTo("FIXED");
-
-    IssueChangeDiff change1Diff2 = change1.diffs().get(1);
-    assertThat(change1Diff2.key()).isEqualTo("status");
-    assertThat(change1Diff2.oldValue()).isEqualTo("OPEN");
-    assertThat(change1Diff2.newValue()).isEqualTo("RESOLVED");
+    Changelog change1 = changes.get(0);
+    assertThat(change1.getUser()).isEqualTo("admin");
+    assertThat(change1.getCreationDate()).isNotNull();
+    assertThat(change1.getDiffsList())
+      .extracting(Changelog.Diff::getKey, Changelog.Diff::getOldValue, Changelog.Diff::getNewValue)
+      .containsOnly(tuple("resolution", "", "FIXED"), tuple("status", "OPEN", "RESOLVED"));
 
     // Change done by scan
-    IssueChange change2 = changes.get(1);
-    assertThat(change2.user()).isNull();
-    assertThat(change2.creationDate()).isNotNull();
-    assertThat(change2.diffs()).hasSize(2);
-
-    IssueChangeDiff changeDiff1 = change2.diffs().get(0);
-    assertThat(changeDiff1.key()).isEqualTo("resolution");
-    assertThat(changeDiff1.oldValue()).isNull();
-    assertThat(changeDiff1.newValue()).isNull();
-
-    IssueChangeDiff changeDiff2 = change2.diffs().get(1);
-    assertThat(changeDiff2.key()).isEqualTo("status");
-    assertThat(changeDiff2.oldValue()).isEqualTo("RESOLVED");
-    assertThat(changeDiff2.newValue()).isEqualTo("REOPENED");
+    Changelog change2 = changes.get(1);
+    assertThat(change2.hasUser()).isFalse();
+    assertThat(change2.getCreationDate()).isNotNull();
+    assertThat(change2.getDiffsList())
+      .extracting(Changelog.Diff::getKey, Changelog.Diff::getOldValue, Changelog.Diff::getNewValue)
+      .containsOnly(tuple("resolution", "", ""), tuple("status", "RESOLVED", "REOPENED"));
   }
 
   private void assertIssueHasNoChange(String issueKey) {
-    assertThat(retrieveChangeForIssue(issueKey)).isEmpty();
+    assertThat(changelog(issueKey).getChangelogList()).isEmpty();
   }
 
-  private List<IssueChange> retrieveChangeForIssue(String issueKey) {
-    return issueClient().changes(issueKey);
+  private static Issues.ChangelogWsResponse changelog(String issueKey) {
+    return newAdminWsClient(ORCHESTRATOR).issues().changelog(issueKey);
   }
 
 }
index f64abe6a5cebd9752e9247c218f21e699c2f61f4..ab44372993fa5ada353525c4b295dc50302df7a7 100644 (file)
@@ -29,12 +29,13 @@ import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.sonar.wsclient.issue.Issue;
-import org.sonar.wsclient.issue.IssueChange;
-import org.sonar.wsclient.issue.IssueChangeDiff;
 import org.sonar.wsclient.issue.IssueClient;
 import org.sonar.wsclient.issue.IssueQuery;
+import org.sonarqube.ws.Issues;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.tuple;
+import static util.ItUtils.newAdminWsClient;
 import static util.ItUtils.projectDir;
 
 /**
@@ -71,16 +72,16 @@ public class TechnicalDebtInIssueChangelogTest {
 
     IssueClient issueClient = orchestrator.getServer().wsClient().issueClient();
     Issue issue = issueClient.find(IssueQuery.create()).list().get(0);
-    List<IssueChange> changes = issueClient.changes(issue.key());
 
+    List<Issues.ChangelogWsResponse.Changelog> changes = changelog(issue.key()).getChangelogList();
     assertThat(changes).hasSize(1);
-    IssueChange change = changes.get(0);
+    assertThat(changes.get(0).getDiffsList())
+      .extracting(Issues.ChangelogWsResponse.Changelog.Diff::getKey, Issues.ChangelogWsResponse.Changelog.Diff::getOldValue, Issues.ChangelogWsResponse.Changelog.Diff::getNewValue)
+      .containsOnly(tuple("effort", "10", "100"));
+  }
 
-    assertThat(change.diffs()).hasSize(1);
-    IssueChangeDiff changeDiff = change.diffs().get(0);
-    assertThat(changeDiff.key()).isEqualTo("effort");
-    assertThat(changeDiff.oldValue()).isEqualTo("10");
-    assertThat(changeDiff.newValue()).isEqualTo("100");
+  private static Issues.ChangelogWsResponse changelog(String issueKey) {
+    return newAdminWsClient(orchestrator).issues().changelog(issueKey);
   }
 
 }
index 8181e95a370a4bb3585131495bb88d928fef72b8..545ae54458d809d0ffb57ba39955eab0ca9e4b2f 100644 (file)
@@ -45,11 +45,11 @@ import static org.sonar.core.util.Protobuf.setNullable;
 import static org.sonar.core.util.Uuids.UUID_EXAMPLE_01;
 import static org.sonar.server.issue.IssueFieldsSetter.TECHNICAL_DEBT;
 import static org.sonar.server.ws.WsUtils.writeProtobuf;
+import static org.sonarqube.ws.client.issue.IssuesWsParameters.ACTION_CHANGELOG;
 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_ISSUE;
 
 public class ChangelogAction implements IssuesWsAction {
 
-  private static final String ACTION_CHANGELOG = "changelog";
   private static final String EFFORT_CHANGELOG_KEY = "effort";
 
   private final DbClient dbClient;
index 77ffb6925296083f1ff281bd656e20b17cb4f166..2df191f77eb23af90764d5a5ceec6fdb1931507a 100644 (file)
@@ -25,9 +25,9 @@ import org.sonar.api.rules.RuleType;
 import org.sonar.api.server.ws.RailsHandler;
 import org.sonar.api.server.ws.WebService;
 
-public class IssuesWs implements WebService {
+import static org.sonarqube.ws.client.issue.IssuesWsParameters.CONTROLLER_ISSUES;
 
-  public static final String API_ENDPOINT = "api/issues";
+public class IssuesWs implements WebService {
 
   public static final String ADD_COMMENT_ACTION = "add_comment";
   public static final String DELETE_COMMENT_ACTION = "delete_comment";
@@ -42,7 +42,7 @@ public class IssuesWs implements WebService {
 
   @Override
   public void define(Context context) {
-    NewController controller = context.createController(API_ENDPOINT);
+    NewController controller = context.createController(CONTROLLER_ISSUES);
     controller.setDescription("Read and update issues.");
     controller.setSince("3.6");
     for (IssuesWsAction action : actions) {
index 36001cd409178290a6b98e6841f7fc366314fc8d..140fa9bb62035311bd538a48bec9cde7061708ba 100644 (file)
@@ -69,6 +69,7 @@ import static org.sonar.core.util.Uuids.UUID_EXAMPLE_02;
 import static org.sonar.db.component.ComponentTesting.newFileDto;
 import static org.sonar.db.component.ComponentTesting.newModuleDto;
 import static org.sonar.db.component.SnapshotTesting.newAnalysis;
+import static org.sonarqube.ws.client.issue.IssuesWsParameters.CONTROLLER_ISSUES;
 
 public class SearchActionComponentsMediumTest {
 
@@ -122,7 +123,7 @@ public class SearchActionComponentsMediumTest {
     session.commit();
     tester.get(IssueIndexer.class).indexAll();
 
-    WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION).execute();
+    WsTester.Result result = wsTester.newGetRequest(CONTROLLER_ISSUES, SearchAction.SEARCH_ACTION).execute();
     result.assertJson(this.getClass(), "issues_on_different_projects.json");
   }
 
@@ -166,22 +167,22 @@ public class SearchActionComponentsMediumTest {
     session.commit();
     tester.get(IssueIndexer.class).indexAll();
 
-    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+    wsTester.newGetRequest(CONTROLLER_ISSUES, SearchAction.SEARCH_ACTION)
       .setParam(IssuesWsParameters.PROJECT_UUIDS, project.uuid())
       .execute()
       .assertJson(this.getClass(), "search_by_project_uuid.json");
 
-    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+    wsTester.newGetRequest(CONTROLLER_ISSUES, SearchAction.SEARCH_ACTION)
       .setParam(IssuesWsParameters.PROJECT_UUIDS, "unknown")
       .execute()
       .assertJson(this.getClass(), "no_issue.json");
 
-    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+    wsTester.newGetRequest(CONTROLLER_ISSUES, SearchAction.SEARCH_ACTION)
       .setParam(IssuesWsParameters.COMPONENT_UUIDS, project.uuid())
       .execute()
       .assertJson(this.getClass(), "search_by_project_uuid.json");
 
-    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+    wsTester.newGetRequest(CONTROLLER_ISSUES, SearchAction.SEARCH_ACTION)
       .setParam(IssuesWsParameters.COMPONENT_UUIDS, "unknown")
       .execute()
       .assertJson(this.getClass(), "no_issue.json");
@@ -208,7 +209,7 @@ public class SearchActionComponentsMediumTest {
     session.commit();
     tester.get(IssueIndexer.class).indexAll();
 
-    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+    wsTester.newGetRequest(CONTROLLER_ISSUES, SearchAction.SEARCH_ACTION)
       .setParam(IssuesWsParameters.COMPONENT_UUIDS, project.uuid())
       .setParam(IssuesWsParameters.SINCE_LEAK_PERIOD, "true")
       .execute()
@@ -236,7 +237,7 @@ public class SearchActionComponentsMediumTest {
     session.commit();
     tester.get(IssueIndexer.class).indexAll();
 
-    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+    wsTester.newGetRequest(CONTROLLER_ISSUES, SearchAction.SEARCH_ACTION)
       .setParam(IssuesWsParameters.COMPONENT_UUIDS, project.uuid())
       .setParam(IssuesWsParameters.FILE_UUIDS, file.uuid())
       .setParam(IssuesWsParameters.SINCE_LEAK_PERIOD, "true")
@@ -263,7 +264,7 @@ public class SearchActionComponentsMediumTest {
     session.commit();
     tester.get(IssueIndexer.class).indexAll();
 
-    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+    wsTester.newGetRequest(CONTROLLER_ISSUES, SearchAction.SEARCH_ACTION)
       .setParam(IssuesWsParameters.PROJECT_UUIDS, project1.uuid())
       .setParam(WebService.Param.FACETS, "projectUuids")
       .execute()
@@ -280,22 +281,22 @@ public class SearchActionComponentsMediumTest {
     session.commit();
     tester.get(IssueIndexer.class).indexAll();
 
-    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+    wsTester.newGetRequest(CONTROLLER_ISSUES, SearchAction.SEARCH_ACTION)
       .setParam(IssuesWsParameters.FILE_UUIDS, file.uuid())
       .execute()
       .assertJson(this.getClass(), "search_by_file_uuid.json");
 
-    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+    wsTester.newGetRequest(CONTROLLER_ISSUES, SearchAction.SEARCH_ACTION)
       .setParam(IssuesWsParameters.FILE_UUIDS, "unknown")
       .execute()
       .assertJson(this.getClass(), "no_issue.json");
 
-    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+    wsTester.newGetRequest(CONTROLLER_ISSUES, SearchAction.SEARCH_ACTION)
       .setParam(IssuesWsParameters.COMPONENT_UUIDS, file.uuid())
       .execute()
       .assertJson(this.getClass(), "search_by_file_uuid.json");
 
-    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+    wsTester.newGetRequest(CONTROLLER_ISSUES, SearchAction.SEARCH_ACTION)
       .setParam(IssuesWsParameters.COMPONENT_UUIDS, "unknown")
       .execute()
       .assertJson(this.getClass(), "no_issue.json");
@@ -314,12 +315,12 @@ public class SearchActionComponentsMediumTest {
     session.commit();
     tester.get(IssueIndexer.class).indexAll();
 
-    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+    wsTester.newGetRequest(CONTROLLER_ISSUES, SearchAction.SEARCH_ACTION)
       .setParam(IssuesWsParameters.COMPONENTS, file.key())
       .execute()
       .assertJson(this.getClass(), "search_by_file_key.json");
 
-    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+    wsTester.newGetRequest(CONTROLLER_ISSUES, SearchAction.SEARCH_ACTION)
       .setParam(IssuesWsParameters.COMPONENTS, unitTest.key())
       .execute()
       .assertJson(this.getClass(), "search_by_test_key.json");
@@ -339,7 +340,7 @@ public class SearchActionComponentsMediumTest {
     session.commit();
     tester.get(IssueIndexer.class).indexAll();
 
-    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+    wsTester.newGetRequest(CONTROLLER_ISSUES, SearchAction.SEARCH_ACTION)
       .setParam(IssuesWsParameters.COMPONENT_UUIDS, project.uuid())
       .setParam(IssuesWsParameters.FILE_UUIDS, file1.uuid() + "," + file3.uuid())
       .setParam(WebService.Param.FACETS, "fileUuids")
@@ -358,22 +359,22 @@ public class SearchActionComponentsMediumTest {
     session.commit();
     tester.get(IssueIndexer.class).indexAll();
 
-    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+    wsTester.newGetRequest(CONTROLLER_ISSUES, SearchAction.SEARCH_ACTION)
       .setParam(IssuesWsParameters.COMPONENT_UUIDS, directory.uuid())
       .execute()
       .assertJson(this.getClass(), "search_by_file_uuid.json");
 
-    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+    wsTester.newGetRequest(CONTROLLER_ISSUES, SearchAction.SEARCH_ACTION)
       .setParam(IssuesWsParameters.COMPONENT_UUIDS, "unknown")
       .execute()
       .assertJson(this.getClass(), "no_issue.json");
 
-    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+    wsTester.newGetRequest(CONTROLLER_ISSUES, SearchAction.SEARCH_ACTION)
       .setParam(IssuesWsParameters.DIRECTORIES, "src/main/java/dir")
       .execute()
       .assertJson(this.getClass(), "search_by_file_uuid.json");
 
-    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+    wsTester.newGetRequest(CONTROLLER_ISSUES, SearchAction.SEARCH_ACTION)
       .setParam(IssuesWsParameters.DIRECTORIES, "src/main/java")
       .execute()
       .assertJson(this.getClass(), "no_issue.json");
@@ -396,34 +397,34 @@ public class SearchActionComponentsMediumTest {
 
     tester.get(IssueIndexer.class).indexAll();
 
-    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+    wsTester.newGetRequest(CONTROLLER_ISSUES, SearchAction.SEARCH_ACTION)
       .setParam(IssuesWsParameters.COMPONENT_UUIDS, directory1.uuid())
       .execute()
       .assertJson(this.getClass(), "search_by_directory_uuid.json");
 
-    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+    wsTester.newGetRequest(CONTROLLER_ISSUES, SearchAction.SEARCH_ACTION)
       .setParam(IssuesWsParameters.COMPONENT_UUIDS, directory2.uuid())
       .execute()
       .assertJson(this.getClass(), "no_issue.json");
 
-    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+    wsTester.newGetRequest(CONTROLLER_ISSUES, SearchAction.SEARCH_ACTION)
       .setParam(IssuesWsParameters.MODULE_UUIDS, module1.uuid())
       .setParam(IssuesWsParameters.DIRECTORIES, "src/main/java/dir")
       .execute()
       .assertJson(this.getClass(), "search_by_directory_uuid.json");
 
-    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+    wsTester.newGetRequest(CONTROLLER_ISSUES, SearchAction.SEARCH_ACTION)
       .setParam(IssuesWsParameters.MODULE_UUIDS, module2.uuid())
       .setParam(IssuesWsParameters.DIRECTORIES, "src/main/java/dir")
       .execute()
       .assertJson(this.getClass(), "no_issue.json");
 
-    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+    wsTester.newGetRequest(CONTROLLER_ISSUES, SearchAction.SEARCH_ACTION)
       .setParam(IssuesWsParameters.DIRECTORIES, "src/main/java/dir")
       .execute()
       .assertJson(this.getClass(), "search_by_directory_uuid.json");
 
-    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+    wsTester.newGetRequest(CONTROLLER_ISSUES, SearchAction.SEARCH_ACTION)
       .setParam(IssuesWsParameters.DIRECTORIES, "src/main/java")
       .execute()
       .assertJson(this.getClass(), "no_issue.json");
@@ -446,7 +447,7 @@ public class SearchActionComponentsMediumTest {
     session.commit();
     tester.get(IssueIndexer.class).indexAll();
 
-    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+    wsTester.newGetRequest(CONTROLLER_ISSUES, SearchAction.SEARCH_ACTION)
       .setParam(IssuesWsParameters.COMPONENT_UUIDS, module.uuid())
       .setParam(IssuesWsParameters.MODULE_UUIDS, subModule1.uuid() + "," + subModule3.uuid())
       .setParam(WebService.Param.FACETS, "moduleUuids")
@@ -466,7 +467,7 @@ public class SearchActionComponentsMediumTest {
     tester.get(IssueIndexer.class).indexAll();
 
     userSessionRule.login("john");
-    WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+    WsTester.Result result = wsTester.newGetRequest(CONTROLLER_ISSUES, SearchAction.SEARCH_ACTION)
       .setParam("resolved", "false")
       .setParam(WebService.Param.FACETS, "directories")
       .execute();
@@ -486,7 +487,7 @@ public class SearchActionComponentsMediumTest {
     setAnyoneProjectPermission(view, UserRole.USER);
     userSessionRule.login("john").addProjectUuidPermissions(UserRole.USER, view.uuid());
 
-    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+    wsTester.newGetRequest(CONTROLLER_ISSUES, SearchAction.SEARCH_ACTION)
       .setParam(IssuesWsParameters.COMPONENT_UUIDS, view.uuid())
       .execute()
       .assertJson(this.getClass(), "search_by_view_uuid.json");
@@ -506,7 +507,7 @@ public class SearchActionComponentsMediumTest {
     // User has wrong permission on the view, no issue will be returned
     userSessionRule.login("john").addProjectUuidPermissions(UserRole.CODEVIEWER, view.uuid());
 
-    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+    wsTester.newGetRequest(CONTROLLER_ISSUES, SearchAction.SEARCH_ACTION)
       .setParam(IssuesWsParameters.COMPONENT_UUIDS, view.uuid())
       .execute()
       .assertJson(this.getClass(), "no_issue.json");
@@ -527,7 +528,7 @@ public class SearchActionComponentsMediumTest {
     setAnyoneProjectPermission(view, UserRole.USER);
     userSessionRule.login("john").addComponentUuidPermission(UserRole.USER, view.uuid(), subView.uuid());
 
-    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+    wsTester.newGetRequest(CONTROLLER_ISSUES, SearchAction.SEARCH_ACTION)
       .setParam(IssuesWsParameters.COMPONENT_UUIDS, subView.uuid())
       .execute()
       .assertJson(this.getClass(), "search_by_view_uuid.json");
@@ -549,7 +550,7 @@ public class SearchActionComponentsMediumTest {
     // User has wrong permission on the view, no issue will be returned
     userSessionRule.login("john").addComponentUuidPermission(UserRole.CODEVIEWER, view.uuid(), subView.uuid());
 
-    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+    wsTester.newGetRequest(CONTROLLER_ISSUES, SearchAction.SEARCH_ACTION)
       .setParam(IssuesWsParameters.COMPONENT_UUIDS, subView.uuid())
       .execute()
       .assertJson(this.getClass(), "no_issue.json");
@@ -568,13 +569,13 @@ public class SearchActionComponentsMediumTest {
     session.commit();
     tester.get(IssueIndexer.class).indexAll();
 
-    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+    wsTester.newGetRequest(CONTROLLER_ISSUES, SearchAction.SEARCH_ACTION)
       .setParam(IssuesWsParameters.AUTHORS, "leia")
       .setParam(WebService.Param.FACETS, "authors")
       .execute()
       .assertJson(this.getClass(), "search_by_authors.json");
 
-    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+    wsTester.newGetRequest(CONTROLLER_ISSUES, SearchAction.SEARCH_ACTION)
       .setParam(IssuesWsParameters.AUTHORS, "unknown")
       .execute()
       .assertJson(this.getClass(), "no_issue.json");
@@ -597,7 +598,7 @@ public class SearchActionComponentsMediumTest {
     session.commit();
     tester.get(IssueIndexer.class).indexAll();
 
-    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+    wsTester.newGetRequest(CONTROLLER_ISSUES, SearchAction.SEARCH_ACTION)
       .setParam(IssuesWsParameters.COMPONENT_UUIDS, developer.uuid())
       .execute()
       .assertJson(this.getClass(), "search_by_developer.json");
@@ -629,7 +630,7 @@ public class SearchActionComponentsMediumTest {
     session.commit();
     tester.get(IssueIndexer.class).indexAll();
 
-    Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+    Result result = wsTester.newGetRequest(CONTROLLER_ISSUES, SearchAction.SEARCH_ACTION)
       .setParam(IssuesWsParameters.COMPONENT_UUIDS, technicalProject.uuid())
       .execute();
     result
index 8cf65711c2fa80cc57aabb9a2f078a8cff8645e2..40f326619a30d1e0baf0ab9548596b2e07831116 100644 (file)
@@ -58,10 +58,10 @@ import org.sonar.server.ws.WsTester;
 
 import static java.util.Arrays.asList;
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.server.issue.ws.IssuesWs.API_ENDPOINT;
 import static org.sonar.server.issue.ws.SearchAction.SEARCH_ACTION;
 import static org.sonarqube.ws.client.issue.IssuesWsParameters.ADDITIONAL_FIELDS;
 import static org.sonarqube.ws.client.issue.IssuesWsParameters.COMPONENTS;
+import static org.sonarqube.ws.client.issue.IssuesWsParameters.CONTROLLER_ISSUES;
 import static org.sonarqube.ws.client.issue.IssuesWsParameters.CREATED_AFTER;
 import static org.sonarqube.ws.client.issue.IssuesWsParameters.DEPRECATED_FACET_MODE_DEBT;
 import static org.sonarqube.ws.client.issue.IssuesWsParameters.FACET_MODE_EFFORT;
@@ -112,7 +112,7 @@ public class SearchActionMediumTest {
 
   @Test
   public void empty_search() throws Exception {
-    WsTester.TestRequest request = wsTester.newGetRequest(API_ENDPOINT, SEARCH_ACTION);
+    WsTester.TestRequest request = wsTester.newGetRequest(CONTROLLER_ISSUES, SEARCH_ACTION);
     WsTester.Result result = request.execute();
 
     assertThat(result).isNotNull();
@@ -143,7 +143,7 @@ public class SearchActionMediumTest {
     session.commit();
     tester.get(IssueIndexer.class).indexAll();
 
-    WsTester.Result result = wsTester.newGetRequest(API_ENDPOINT, SEARCH_ACTION).execute();
+    WsTester.Result result = wsTester.newGetRequest(CONTROLLER_ISSUES, SEARCH_ACTION).execute();
     result.assertJson(this.getClass(), "response_contains_all_fields_except_additional_fields.json");
   }
 
@@ -177,7 +177,7 @@ public class SearchActionMediumTest {
     tester.get(IssueIndexer.class).indexAll();
 
     userSessionRule.login("john");
-    WsTester.Result result = wsTester.newGetRequest(API_ENDPOINT, SEARCH_ACTION)
+    WsTester.Result result = wsTester.newGetRequest(CONTROLLER_ISSUES, SEARCH_ACTION)
       .setParam("additionalFields", "comments,users")
       .execute();
     result.assertJson(this.getClass(), "issue_with_comments.json");
@@ -213,7 +213,7 @@ public class SearchActionMediumTest {
     tester.get(IssueIndexer.class).indexAll();
 
     userSessionRule.login("john");
-    WsTester.Result result = wsTester.newGetRequest(API_ENDPOINT, SEARCH_ACTION).setParam(HIDE_COMMENTS, "true").execute();
+    WsTester.Result result = wsTester.newGetRequest(CONTROLLER_ISSUES, SEARCH_ACTION).setParam(HIDE_COMMENTS, "true").execute();
     result.assertJson(this.getClass(), "issue_with_comment_hidden.json");
     assertThat(result.outputAsString()).doesNotContain("fabrice");
   }
@@ -235,7 +235,7 @@ public class SearchActionMediumTest {
     tester.get(IssueIndexer.class).indexAll();
 
     userSessionRule.login("john");
-    WsTester.Result result = wsTester.newGetRequest(API_ENDPOINT, SEARCH_ACTION)
+    WsTester.Result result = wsTester.newGetRequest(CONTROLLER_ISSUES, SEARCH_ACTION)
       .setParam("additionalFields", "_all").execute();
     result.assertJson(this.getClass(), "load_additional_fields.json");
   }
@@ -260,7 +260,7 @@ public class SearchActionMediumTest {
     session.commit();
     tester.get(IssueIndexer.class).indexAll();
 
-    WsTester.Result result = wsTester.newGetRequest(API_ENDPOINT, SEARCH_ACTION)
+    WsTester.Result result = wsTester.newGetRequest(CONTROLLER_ISSUES, SEARCH_ACTION)
       .execute();
     result.assertJson(this.getClass(), "issue_on_removed_file.json");
   }
@@ -275,7 +275,7 @@ public class SearchActionMediumTest {
     session.commit();
     tester.get(IssueIndexer.class).indexAll();
 
-    WsTester.Result result = wsTester.newGetRequest(API_ENDPOINT, SEARCH_ACTION).execute();
+    WsTester.Result result = wsTester.newGetRequest(CONTROLLER_ISSUES, SEARCH_ACTION).execute();
     assertThat(result.outputAsString()).contains("\"componentId\":" + file.getId() + ",");
   }
 
@@ -292,7 +292,7 @@ public class SearchActionMediumTest {
     session.commit();
     tester.get(IssueIndexer.class).indexAll();
 
-    WsTester.Result result = wsTester.newGetRequest(API_ENDPOINT, SEARCH_ACTION).setParam(COMPONENTS, file.getKey()).execute();
+    WsTester.Result result = wsTester.newGetRequest(CONTROLLER_ISSUES, SEARCH_ACTION).setParam(COMPONENTS, file.getKey()).execute();
     result.assertJson(this.getClass(), "apply_paging_with_one_component.json");
   }
 
@@ -307,7 +307,7 @@ public class SearchActionMediumTest {
     session.commit();
     tester.get(IssueIndexer.class).indexAll();
 
-    WsTester.Result result = wsTester.newGetRequest(API_ENDPOINT, SEARCH_ACTION).setParam(ADDITIONAL_FIELDS, "_all").execute();
+    WsTester.Result result = wsTester.newGetRequest(CONTROLLER_ISSUES, SEARCH_ACTION).setParam(ADDITIONAL_FIELDS, "_all").execute();
     result.assertJson(this.getClass(), "components_contains_sub_projects.json");
   }
 
@@ -328,7 +328,7 @@ public class SearchActionMediumTest {
     tester.get(IssueIndexer.class).indexAll();
 
     userSessionRule.login("john");
-    WsTester.Result result = wsTester.newGetRequest(API_ENDPOINT, SEARCH_ACTION)
+    WsTester.Result result = wsTester.newGetRequest(CONTROLLER_ISSUES, SEARCH_ACTION)
       .setParam("resolved", "false")
       .setParam(WebService.Param.FACETS, "statuses,severities,resolutions,projectUuids,rules,fileUuids,assignees,languages,actionPlans,types")
       .execute();
@@ -352,7 +352,7 @@ public class SearchActionMediumTest {
     tester.get(IssueIndexer.class).indexAll();
 
     userSessionRule.login("john");
-    WsTester.Result result = wsTester.newGetRequest(API_ENDPOINT, SEARCH_ACTION)
+    WsTester.Result result = wsTester.newGetRequest(CONTROLLER_ISSUES, SEARCH_ACTION)
       .setParam("resolved", "false")
       .setParam(WebService.Param.FACETS, "statuses,severities,resolutions,projectUuids,rules,fileUuids,assignees,languages,actionPlans")
       .setParam("facetMode", FACET_MODE_EFFORT)
@@ -377,7 +377,7 @@ public class SearchActionMediumTest {
     tester.get(IssueIndexer.class).indexAll();
 
     userSessionRule.login("john");
-    WsTester.Result result = wsTester.newGetRequest(API_ENDPOINT, SEARCH_ACTION)
+    WsTester.Result result = wsTester.newGetRequest(CONTROLLER_ISSUES, SEARCH_ACTION)
       .setParam("resolved", "false")
       .setParam("severities", "MAJOR,MINOR")
       .setParam("languages", "xoo,polop,palap")
@@ -392,7 +392,7 @@ public class SearchActionMediumTest {
     userSessionRule.login("foo[");
 
     // should not fail
-    wsTester.newGetRequest(API_ENDPOINT, SEARCH_ACTION)
+    wsTester.newGetRequest(CONTROLLER_ISSUES, SEARCH_ACTION)
       .setParam(WebService.Param.FACETS, "assigned_to_me")
       .execute()
       .assertJson(this.getClass(), "assignedToMe_facet_must_escape_login_of_authenticated_user.json");
@@ -435,7 +435,7 @@ public class SearchActionMediumTest {
     tester.get(IssueIndexer.class).indexAll();
 
     userSessionRule.login("john");
-    wsTester.newGetRequest(API_ENDPOINT, SEARCH_ACTION)
+    wsTester.newGetRequest(CONTROLLER_ISSUES, SEARCH_ACTION)
       .setParam("resolved", "false")
       .setParam("assignees", "__me__")
       .setParam(WebService.Param.FACETS, "assignees,assigned_to_me")
@@ -466,7 +466,7 @@ public class SearchActionMediumTest {
     session.commit();
     tester.get(IssueIndexer.class).indexAll();
 
-    wsTester.newGetRequest(API_ENDPOINT, SEARCH_ACTION)
+    wsTester.newGetRequest(CONTROLLER_ISSUES, SEARCH_ACTION)
       .setParam("resolved", "false")
       .setParam("assignees", "__me__")
       .execute()
@@ -509,7 +509,7 @@ public class SearchActionMediumTest {
     tester.get(IssueIndexer.class).indexAll();
 
     userSessionRule.login("john-bob.polop");
-    wsTester.newGetRequest(API_ENDPOINT, SEARCH_ACTION)
+    wsTester.newGetRequest(CONTROLLER_ISSUES, SEARCH_ACTION)
       .setParam("resolved", "false")
       .setParam("assignees", "alice")
       .setParam(WebService.Param.FACETS, "assignees,assigned_to_me")
@@ -535,7 +535,7 @@ public class SearchActionMediumTest {
     session.commit();
     tester.get(IssueIndexer.class).indexAll();
 
-    WsTester.Result result = wsTester.newGetRequest(API_ENDPOINT, SEARCH_ACTION)
+    WsTester.Result result = wsTester.newGetRequest(CONTROLLER_ISSUES, SEARCH_ACTION)
       .setParam("sort", IssueQuery.SORT_BY_UPDATE_DATE)
       .setParam("asc", "false")
       .execute();
@@ -555,7 +555,7 @@ public class SearchActionMediumTest {
     session.commit();
     tester.get(IssueIndexer.class).indexAll();
 
-    WsTester.TestRequest request = wsTester.newGetRequest(API_ENDPOINT, SEARCH_ACTION);
+    WsTester.TestRequest request = wsTester.newGetRequest(CONTROLLER_ISSUES, SEARCH_ACTION);
     request.setParam(WebService.Param.PAGE, "2");
     request.setParam(WebService.Param.PAGE_SIZE, "9");
 
@@ -576,7 +576,7 @@ public class SearchActionMediumTest {
     session.commit();
     tester.get(IssueIndexer.class).indexAll();
 
-    WsTester.TestRequest request = wsTester.newGetRequest(API_ENDPOINT, SEARCH_ACTION);
+    WsTester.TestRequest request = wsTester.newGetRequest(CONTROLLER_ISSUES, SEARCH_ACTION);
     request.setParam(WebService.Param.PAGE, "1");
     request.setParam(WebService.Param.PAGE_SIZE, "-1");
 
@@ -597,7 +597,7 @@ public class SearchActionMediumTest {
     session.commit();
     tester.get(IssueIndexer.class).indexAll();
 
-    WsTester.TestRequest request = wsTester.newGetRequest(API_ENDPOINT, SEARCH_ACTION);
+    WsTester.TestRequest request = wsTester.newGetRequest(CONTROLLER_ISSUES, SEARCH_ACTION);
     request.setParam(PAGE_INDEX, "2");
     request.setParam(PAGE_SIZE, "9");
 
@@ -607,7 +607,7 @@ public class SearchActionMediumTest {
 
   @Test
   public void default_page_size_is_100() throws Exception {
-    WsTester.TestRequest request = wsTester.newGetRequest(API_ENDPOINT, SEARCH_ACTION);
+    WsTester.TestRequest request = wsTester.newGetRequest(CONTROLLER_ISSUES, SEARCH_ACTION);
 
     WsTester.Result result = request.execute();
     result.assertJson(this.getClass(), "default_page_size_is_100.json");
@@ -630,7 +630,7 @@ public class SearchActionMediumTest {
     tester.get(IssueIndexer.class).indexAll();
 
     userSessionRule.login("john");
-    WsTester.Result result = wsTester.newGetRequest(API_ENDPOINT, SEARCH_ACTION)
+    WsTester.Result result = wsTester.newGetRequest(CONTROLLER_ISSUES, SEARCH_ACTION)
       .setParam("resolved", "false")
       .setParam(WebService.Param.FACETS, "severities")
       .setParam("facetMode", DEPRECATED_FACET_MODE_DEBT)
@@ -643,7 +643,7 @@ public class SearchActionMediumTest {
     expectedException.expect(IllegalArgumentException.class);
     expectedException.expectMessage("Date 'wrong-date-input' cannot be parsed as either a date or date+time");
 
-    wsTester.newGetRequest(API_ENDPOINT, SEARCH_ACTION)
+    wsTester.newGetRequest(CONTROLLER_ISSUES, SEARCH_ACTION)
       .setParam(CREATED_AFTER, "wrong-date-input")
       .execute();
   }
index 976c112a69b6654a5ba13337fc1bbf8ca98b946e..88aebe35474bed7ad11ec4ed0b28ad53449725e3 100644 (file)
@@ -19,6 +19,7 @@
  */
 package org.sonarqube.ws.client.issue;
 
+import org.sonarqube.ws.Issues.ChangelogWsResponse;
 import org.sonarqube.ws.Issues.SearchWsResponse;
 import org.sonarqube.ws.client.BaseService;
 import org.sonarqube.ws.client.GetRequest;
@@ -34,6 +35,7 @@ import static org.sonarqube.ws.client.issue.IssuesWsParameters.COMPONENT_KEYS;
 import static org.sonarqube.ws.client.issue.IssuesWsParameters.COMPONENT_ROOTS;
 import static org.sonarqube.ws.client.issue.IssuesWsParameters.COMPONENT_ROOT_UUIDS;
 import static org.sonarqube.ws.client.issue.IssuesWsParameters.COMPONENT_UUIDS;
+import static org.sonarqube.ws.client.issue.IssuesWsParameters.CONTROLLER_ISSUES;
 import static org.sonarqube.ws.client.issue.IssuesWsParameters.CREATED_AFTER;
 import static org.sonarqube.ws.client.issue.IssuesWsParameters.CREATED_AT;
 import static org.sonarqube.ws.client.issue.IssuesWsParameters.CREATED_BEFORE;
@@ -61,7 +63,7 @@ import static org.sonarqube.ws.client.issue.IssuesWsParameters.TYPES;
 public class IssuesService extends BaseService {
 
   public IssuesService(WsConnector wsConnector) {
-    super(wsConnector, "api/issues");
+    super(wsConnector, CONTROLLER_ISSUES);
   }
 
   public SearchWsResponse search(SearchWsRequest request) {
@@ -106,4 +108,8 @@ public class IssuesService extends BaseService {
         .setParam(TYPES, inlineMultipleParamValue(request.getTypes())),
       SearchWsResponse.parser());
   }
+
+  public ChangelogWsResponse changelog(String issueKey) {
+    return call(new GetRequest(path("changelog")).setParam(IssuesWsParameters.PARAM_ISSUE, issueKey), ChangelogWsResponse.parser());
+  }
 }
index 5fb8575c93169a3f5668e8fc4959bb396d89f10e..6a27ae483d4a5db844615ae6184c4e0ad58b3c0a 100644 (file)
@@ -29,6 +29,10 @@ import java.util.List;
  */
 public class IssuesWsParameters {
 
+  public static final String CONTROLLER_ISSUES = "api/issues";
+
+  public static final String ACTION_CHANGELOG = "changelog";
+
   public static final String PARAM_ISSUE = "issue";
 
   public static final String ISSUES = "issues";
diff --git a/sonar-ws/src/test/java/org/sonarqube/ws/client/issue/IssuesServiceTest.java b/sonar-ws/src/test/java/org/sonarqube/ws/client/issue/IssuesServiceTest.java
new file mode 100644 (file)
index 0000000..37a7db6
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program 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.sonarqube.ws.client.issue;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonarqube.ws.Issues;
+import org.sonarqube.ws.client.GetRequest;
+import org.sonarqube.ws.client.ServiceTester;
+import org.sonarqube.ws.client.WsConnector;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_ISSUE;
+
+public class IssuesServiceTest {
+
+  @Rule
+  public ServiceTester<IssuesService> serviceTester = new ServiceTester<>(new IssuesService(mock(WsConnector.class)));
+
+  private IssuesService underTest = serviceTester.getInstanceUnderTest();
+
+  @Test
+  public void changelog() {
+    underTest.changelog("ABCD");
+
+    GetRequest getRequest = serviceTester.getGetRequest();
+
+    assertThat(serviceTester.getGetParser()).isSameAs(Issues.ChangelogWsResponse.parser());
+    serviceTester.assertThat(getRequest)
+      .hasParam(PARAM_ISSUE, "ABCD")
+      .andNoOtherParam();
+  }
+
+}