You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

AddCommentActionTest.java 9.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2020 SonarSource SA
  4. * mailto:info AT sonarsource DOT com
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program; if not, write to the Free Software Foundation,
  18. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. package org.sonar.server.issue.ws;
  21. import javax.annotation.Nullable;
  22. import org.junit.Before;
  23. import org.junit.Rule;
  24. import org.junit.Test;
  25. import org.junit.rules.ExpectedException;
  26. import org.mockito.ArgumentCaptor;
  27. import org.sonar.api.server.ws.Request;
  28. import org.sonar.api.server.ws.Response;
  29. import org.sonar.api.server.ws.WebService;
  30. import org.sonar.api.utils.System2;
  31. import org.sonar.db.DbClient;
  32. import org.sonar.db.DbTester;
  33. import org.sonar.db.component.ComponentDto;
  34. import org.sonar.db.issue.IssueChangeDto;
  35. import org.sonar.db.issue.IssueDbTester;
  36. import org.sonar.db.issue.IssueDto;
  37. import org.sonar.db.rule.RuleDefinitionDto;
  38. import org.sonar.db.user.UserDto;
  39. import org.sonar.server.es.EsTester;
  40. import org.sonar.server.exceptions.ForbiddenException;
  41. import org.sonar.server.exceptions.NotFoundException;
  42. import org.sonar.server.exceptions.UnauthorizedException;
  43. import org.sonar.server.issue.IssueFieldsSetter;
  44. import org.sonar.server.issue.IssueFinder;
  45. import org.sonar.server.issue.TestIssueChangePostProcessor;
  46. import org.sonar.server.issue.WebIssueStorage;
  47. import org.sonar.server.issue.index.IssueIndexer;
  48. import org.sonar.server.issue.index.IssueIteratorFactory;
  49. import org.sonar.server.issue.notification.IssuesChangesNotificationSerializer;
  50. import org.sonar.server.notification.NotificationManager;
  51. import org.sonar.server.organization.DefaultOrganizationProvider;
  52. import org.sonar.server.organization.TestDefaultOrganizationProvider;
  53. import org.sonar.server.rule.DefaultRuleFinder;
  54. import org.sonar.server.tester.UserSessionRule;
  55. import org.sonar.server.ws.TestRequest;
  56. import org.sonar.server.ws.TestResponse;
  57. import org.sonar.server.ws.WsActionTester;
  58. import static java.util.Collections.singletonList;
  59. import static java.util.Optional.ofNullable;
  60. import static org.assertj.core.api.Assertions.assertThat;
  61. import static org.assertj.core.api.Assertions.assertThatThrownBy;
  62. import static org.mockito.ArgumentMatchers.any;
  63. import static org.mockito.ArgumentMatchers.eq;
  64. import static org.mockito.Mockito.mock;
  65. import static org.mockito.Mockito.verify;
  66. import static org.mockito.Mockito.when;
  67. import static org.sonar.api.web.UserRole.CODEVIEWER;
  68. import static org.sonar.api.web.UserRole.USER;
  69. import static org.sonar.db.issue.IssueChangeDto.TYPE_COMMENT;
  70. public class AddCommentActionTest {
  71. private static final long NOW = 10_000_000_000L;
  72. @Rule
  73. public ExpectedException expectedException = ExpectedException.none();
  74. @Rule
  75. public DbTester dbTester = DbTester.create(System2.INSTANCE);
  76. @Rule
  77. public EsTester es = EsTester.create();
  78. @Rule
  79. public UserSessionRule userSession = UserSessionRule.standalone();
  80. private System2 system2 = mock(System2.class);
  81. private DbClient dbClient = dbTester.getDbClient();
  82. private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(dbTester);
  83. private IssueDbTester issueDbTester = new IssueDbTester(dbTester);
  84. private IssueIndexer issueIndexer = new IssueIndexer(es.client(), dbClient, new IssueIteratorFactory(dbClient));
  85. private WebIssueStorage serverIssueStorage = new WebIssueStorage(system2, dbClient, new DefaultRuleFinder(dbClient, defaultOrganizationProvider), issueIndexer);
  86. private TestIssueChangePostProcessor issueChangePostProcessor = new TestIssueChangePostProcessor();
  87. private IssueUpdater issueUpdater = new IssueUpdater(dbClient, serverIssueStorage, mock(NotificationManager.class), issueChangePostProcessor, new IssuesChangesNotificationSerializer());
  88. private OperationResponseWriter responseWriter = mock(OperationResponseWriter.class);
  89. private ArgumentCaptor<SearchResponseData> preloadedSearchResponseDataCaptor = ArgumentCaptor.forClass(SearchResponseData.class);
  90. private WsActionTester tester = new WsActionTester(
  91. new AddCommentAction(system2, userSession, dbClient, new IssueFinder(dbClient, userSession), issueUpdater, new IssueFieldsSetter(), responseWriter));
  92. @Before
  93. public void setUp() {
  94. when(system2.now()).thenReturn(NOW);
  95. }
  96. @Test
  97. public void add_comment() {
  98. IssueDto issueDto = issueDbTester.insertIssue();
  99. loginWithBrowsePermission(issueDto, USER);
  100. call(issueDto.getKey(), "please fix it");
  101. verify(responseWriter).write(eq(issueDto.getKey()), preloadedSearchResponseDataCaptor.capture(), any(Request.class), any(Response.class));
  102. verifyContentOfPreloadedSearchResponseData(issueDto);
  103. IssueChangeDto issueComment = dbClient.issueChangeDao().selectByTypeAndIssueKeys(dbTester.getSession(), singletonList(issueDto.getKey()), TYPE_COMMENT).get(0);
  104. assertThat(issueComment.getKey()).isNotNull();
  105. assertThat(issueComment.getUserUuid()).isEqualTo(userSession.getUuid());
  106. assertThat(issueComment.getChangeType()).isEqualTo(TYPE_COMMENT);
  107. assertThat(issueComment.getChangeData()).isEqualTo("please fix it");
  108. assertThat(issueComment.getCreatedAt()).isNotNull();
  109. assertThat(issueComment.getUpdatedAt()).isNotNull();
  110. assertThat(issueComment.getIssueKey()).isEqualTo(issueDto.getKey());
  111. assertThat(issueComment.getIssueChangeCreationDate()).isNotNull();
  112. IssueDto issueReloaded = dbClient.issueDao().selectByKey(dbTester.getSession(), issueDto.getKey()).get();
  113. assertThat(issueReloaded.getIssueUpdateTime()).isEqualTo(NOW);
  114. assertThat(issueChangePostProcessor.wasCalled()).isFalse();
  115. }
  116. @Test
  117. public void fail_if_add_comment_to_hotspot() {
  118. IssueDto issueDto = issueDbTester.insertHotspot();
  119. loginWithBrowsePermission(issueDto, USER);
  120. assertThatThrownBy(() -> call(issueDto.getKey(), "please fix it"))
  121. .isInstanceOf(NotFoundException.class)
  122. .hasMessage("Issue with key '%s' does not exist", issueDto.getKey());
  123. }
  124. @Test
  125. public void fail_when_missing_issue_key() {
  126. userSession.logIn("john");
  127. expectedException.expect(IllegalArgumentException.class);
  128. call(null, "please fix it");
  129. }
  130. @Test
  131. public void fail_when_issue_does_not_exist() {
  132. userSession.logIn("john");
  133. expectedException.expect(NotFoundException.class);
  134. call("ABCD", "please fix it");
  135. }
  136. @Test
  137. public void fail_when_missing_comment_text() {
  138. userSession.logIn("john");
  139. expectedException.expect(IllegalArgumentException.class);
  140. call("ABCD", null);
  141. }
  142. @Test
  143. public void fail_when_empty_comment_text() {
  144. IssueDto issueDto = issueDbTester.insertIssue();
  145. loginWithBrowsePermission(issueDto, USER);
  146. expectedException.expect(IllegalArgumentException.class);
  147. call(issueDto.getKey(), "");
  148. }
  149. @Test
  150. public void fail_when_not_authenticated() {
  151. expectedException.expect(UnauthorizedException.class);
  152. call("ABCD", "please fix it");
  153. }
  154. @Test
  155. public void fail_when_not_enough_permission() {
  156. IssueDto issueDto = issueDbTester.insertIssue();
  157. loginWithBrowsePermission(issueDto, CODEVIEWER);
  158. expectedException.expect(ForbiddenException.class);
  159. call(issueDto.getKey(), "please fix it");
  160. }
  161. @Test
  162. public void test_definition() {
  163. WebService.Action action = tester.getDef();
  164. assertThat(action.key()).isEqualTo("add_comment");
  165. assertThat(action.isPost()).isTrue();
  166. assertThat(action.isInternal()).isFalse();
  167. assertThat(action.params()).hasSize(2);
  168. assertThat(action.responseExampleAsString()).isNotEmpty();
  169. }
  170. private void verifyContentOfPreloadedSearchResponseData(IssueDto issue) {
  171. SearchResponseData preloadedSearchResponseData = preloadedSearchResponseDataCaptor.getValue();
  172. assertThat(preloadedSearchResponseData.getIssues())
  173. .extracting(IssueDto::getKey)
  174. .containsOnly(issue.getKey());
  175. assertThat(preloadedSearchResponseData.getRules())
  176. .extracting(RuleDefinitionDto::getKey)
  177. .containsOnly(issue.getRuleKey());
  178. assertThat(preloadedSearchResponseData.getComponents())
  179. .extracting(ComponentDto::uuid)
  180. .containsOnly(issue.getComponentUuid(), issue.getProjectUuid());
  181. }
  182. private TestResponse call(@Nullable String issueKey, @Nullable String commentText) {
  183. TestRequest request = tester.newRequest();
  184. ofNullable(issueKey).ifPresent(issue -> request.setParam("issue", issue));
  185. ofNullable(commentText).ifPresent(text -> request.setParam("text", text));
  186. return request.execute();
  187. }
  188. private void loginWithBrowsePermission(IssueDto issueDto, String permission) {
  189. UserDto user = dbTester.users().insertUser("john");
  190. userSession.logIn(user)
  191. .addProjectPermission(permission,
  192. dbClient.componentDao().selectByUuid(dbTester.getSession(), issueDto.getProjectUuid()).get(),
  193. dbClient.componentDao().selectByUuid(dbTester.getSession(), issueDto.getComponentUuid()).get());
  194. }
  195. }