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.

SearchResponseFormatFormatOperationTest.java 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2023 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 java.util.ArrayList;
  22. import java.util.Collection;
  23. import java.util.Date;
  24. import java.util.List;
  25. import java.util.Set;
  26. import org.junit.Before;
  27. import org.junit.Rule;
  28. import org.junit.Test;
  29. import org.junit.runner.RunWith;
  30. import org.mockito.junit.MockitoJUnitRunner;
  31. import org.sonar.api.resources.Languages;
  32. import org.sonar.api.rules.CleanCodeAttribute;
  33. import org.sonar.api.utils.Duration;
  34. import org.sonar.api.utils.Durations;
  35. import org.sonar.core.issue.status.IssueStatus;
  36. import org.sonar.db.DbTester;
  37. import org.sonar.db.component.BranchDto;
  38. import org.sonar.db.component.BranchType;
  39. import org.sonar.db.component.ComponentDto;
  40. import org.sonar.db.issue.IssueChangeDto;
  41. import org.sonar.db.issue.IssueDto;
  42. import org.sonar.db.project.ProjectDto;
  43. import org.sonar.db.rule.RuleDto;
  44. import org.sonar.db.user.UserDto;
  45. import org.sonar.server.issue.TextRangeResponseFormatter;
  46. import org.sonar.server.issue.workflow.Transition;
  47. import org.sonarqube.ws.Common;
  48. import org.sonarqube.ws.Issues.Issue;
  49. import org.sonarqube.ws.Issues.Operation;
  50. import static java.lang.System.currentTimeMillis;
  51. import static java.util.stream.Collectors.toList;
  52. import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
  53. import static org.assertj.core.api.Assertions.assertThat;
  54. import static org.assertj.core.groups.Tuple.tuple;
  55. import static org.mockito.ArgumentMatchers.any;
  56. import static org.mockito.ArgumentMatchers.eq;
  57. import static org.mockito.Mockito.mock;
  58. import static org.mockito.Mockito.when;
  59. import static org.sonar.api.resources.Qualifiers.UNIT_TEST_FILE;
  60. import static org.sonar.api.rule.RuleKey.EXTERNAL_RULE_REPO_PREFIX;
  61. import static org.sonar.api.rules.RuleType.CODE_SMELL;
  62. import static org.sonar.api.rules.RuleType.SECURITY_HOTSPOT;
  63. import static org.sonar.api.utils.DateUtils.formatDateTime;
  64. import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto;
  65. import static org.sonar.db.issue.IssueTesting.newIssue;
  66. import static org.sonar.db.issue.IssueTesting.newIssueChangeDto;
  67. import static org.sonar.db.rule.RuleTesting.newRule;
  68. import static org.sonar.db.user.UserTesting.newUserDto;
  69. import static org.sonar.server.issue.index.IssueScope.MAIN;
  70. import static org.sonar.server.issue.index.IssueScope.TEST;
  71. @RunWith(MockitoJUnitRunner.class)
  72. public class SearchResponseFormatFormatOperationTest {
  73. @Rule
  74. public DbTester db = DbTester.create();
  75. private final Durations durations = new Durations();
  76. private final Languages languages = mock(Languages.class);
  77. private final TextRangeResponseFormatter textRangeResponseFormatter = mock(TextRangeResponseFormatter.class);
  78. private final UserResponseFormatter userResponseFormatter = mock(UserResponseFormatter.class);
  79. private final Common.User user = mock(Common.User.class);
  80. private final SearchResponseFormat searchResponseFormat = new SearchResponseFormat(durations, languages, textRangeResponseFormatter, userResponseFormatter);
  81. private SearchResponseData searchResponseData;
  82. private IssueDto issueDto;
  83. private ComponentDto componentDto;
  84. private UserDto userDto;
  85. @Before
  86. public void setUp() {
  87. searchResponseData = newSearchResponseDataMainBranch();
  88. }
  89. @Test
  90. public void formatOperation_should_add_components_to_response() {
  91. Operation result = searchResponseFormat.formatOperation(searchResponseData);
  92. assertThat(result.getComponentsList()).hasSize(1);
  93. assertThat(result.getComponentsList().get(0).getKey()).isEqualTo(issueDto.getComponentKey());
  94. }
  95. @Test
  96. public void formatOperation_should_add_rules_to_response() {
  97. Operation result = searchResponseFormat.formatOperation(searchResponseData);
  98. assertThat(result.getRulesList()).hasSize(1);
  99. assertThat(result.getRulesList().get(0).getKey()).isEqualTo(issueDto.getRuleKey().toString());
  100. }
  101. @Test
  102. public void formatOperation_should_add_users_to_response() {
  103. Operation result = searchResponseFormat.formatOperation(searchResponseData);
  104. assertThat(result.getUsersList()).hasSize(1);
  105. assertThat(result.getUsers(0)).isSameAs(user);
  106. }
  107. @Test
  108. public void formatOperation_should_add_issue_to_response() {
  109. Operation result = searchResponseFormat.formatOperation(searchResponseData);
  110. assertIssueEqualsIssueDto(result.getIssue(), issueDto);
  111. }
  112. private void assertIssueEqualsIssueDto(Issue issue, IssueDto issueDto) {
  113. assertThat(issue.getKey()).isEqualTo(issueDto.getKey());
  114. assertThat(issue.getCleanCodeAttribute()).isEqualTo(Common.CleanCodeAttribute.valueOf(issueDto.getEffectiveCleanCodeAttribute().name()));
  115. assertThat(issue.getCleanCodeAttributeCategory()).isEqualTo(Common.CleanCodeAttributeCategory.valueOf(issueDto.getEffectiveCleanCodeAttribute().getAttributeCategory().name()));
  116. assertThat(issue.getType().getNumber()).isEqualTo(issueDto.getType());
  117. assertThat(issue.getComponent()).isEqualTo(issueDto.getComponentKey());
  118. assertThat(issue.getRule()).isEqualTo(issueDto.getRuleKey().toString());
  119. assertThat(issue.getSeverity()).hasToString(issueDto.getSeverity());
  120. assertThat(issue.getAssignee()).isEqualTo(userDto.getLogin());
  121. assertThat(issue.getResolution()).isEqualTo(issueDto.getResolution());
  122. assertThat(issue.getStatus()).isEqualTo(issueDto.getStatus());
  123. assertThat(issue.getMessage()).isEqualTo(issueDto.getMessage());
  124. assertThat(new ArrayList<>(issue.getTagsList())).containsExactlyInAnyOrderElementsOf(issueDto.getTags());
  125. assertThat(issue.getLine()).isEqualTo(issueDto.getLine());
  126. assertThat(issue.getHash()).isEqualTo(issueDto.getChecksum());
  127. assertThat(issue.getAuthor()).isEqualTo(issueDto.getAuthorLogin());
  128. assertThat(issue.getCreationDate()).isEqualTo(formatDateTime(issueDto.getIssueCreationDate()));
  129. assertThat(issue.getUpdateDate()).isEqualTo(formatDateTime(issueDto.getIssueUpdateDate()));
  130. assertThat(issue.getCloseDate()).isEqualTo(formatDateTime(issueDto.getIssueCloseDate()));
  131. assertThat(issue.getQuickFixAvailable()).isEqualTo(issueDto.isQuickFixAvailable());
  132. assertThat(issue.getRuleDescriptionContextKey()).isEqualTo(issueDto.getOptionalRuleDescriptionContextKey().orElse(null));
  133. assertThat(new ArrayList<>(issue.getCodeVariantsList())).containsExactlyInAnyOrderElementsOf(issueDto.getCodeVariants());
  134. assertThat(issue.getImpactsList())
  135. .extracting(Common.Impact::getSoftwareQuality, Common.Impact::getSeverity)
  136. .containsExactlyInAnyOrderElementsOf(issueDto.getEffectiveImpacts()
  137. .entrySet()
  138. .stream()
  139. .map(entry -> tuple(Common.SoftwareQuality.valueOf(entry.getKey().name()), Common.ImpactSeverity.valueOf(entry.getValue().name())))
  140. .collect(toList()));
  141. }
  142. @Test
  143. public void formatOperation_should_not_add_issue_when_several_issue() {
  144. searchResponseData = new SearchResponseData(List.of(createIssue(), createIssue()));
  145. Operation result = searchResponseFormat.formatOperation(searchResponseData);
  146. assertThat(result.getIssue()).isEqualTo(Issue.getDefaultInstance());
  147. }
  148. private static IssueDto createIssue() {
  149. RuleDto ruleDto = newRule();
  150. String projectUuid = "project_uuid_" + randomAlphanumeric(5);
  151. ComponentDto projectDto = newPrivateProjectDto();
  152. projectDto.setBranchUuid(projectUuid);
  153. return newIssue(ruleDto, projectUuid, "project_key_" + randomAlphanumeric(5), projectDto);
  154. }
  155. @Test
  156. public void formatOperation_should_add_branch_on_issue() {
  157. String branchName = randomAlphanumeric(5);
  158. searchResponseData = newSearchResponseDataBranch(branchName);
  159. Operation result = searchResponseFormat.formatOperation(searchResponseData);
  160. assertThat(result.getIssue().getBranch()).isEqualTo(branchName);
  161. }
  162. @Test
  163. public void formatOperation_should_add_pullrequest_on_issue() {
  164. searchResponseData = newSearchResponseDataPr("pr1");
  165. Operation result = searchResponseFormat.formatOperation(searchResponseData);
  166. assertThat(result.getIssue().getPullRequest()).isEqualTo("pr1");
  167. }
  168. @Test
  169. public void formatOperation_should_add_project_on_issue() {
  170. issueDto.setProjectUuid(componentDto.uuid());
  171. Operation result = searchResponseFormat.formatOperation(searchResponseData);
  172. assertThat(result.getIssue().getProject()).isEqualTo(componentDto.getKey());
  173. }
  174. @Test
  175. public void formatOperation_should_add_external_rule_engine_on_issue() {
  176. issueDto.setExternal(true);
  177. String expected = randomAlphanumeric(5);
  178. issueDto.setRuleKey(EXTERNAL_RULE_REPO_PREFIX + expected, randomAlphanumeric(5));
  179. Operation result = searchResponseFormat.formatOperation(searchResponseData);
  180. assertThat(result.getIssue().getExternalRuleEngine()).isEqualTo(expected);
  181. }
  182. @Test
  183. public void formatOperation_should_add_effort_and_debt_on_issue() {
  184. long effort = 60L;
  185. issueDto.setEffort(effort);
  186. String expected = durations.encode(Duration.create(effort));
  187. Operation result = searchResponseFormat.formatOperation(searchResponseData);
  188. assertThat(result.getIssue().getEffort()).isEqualTo(expected);
  189. assertThat(result.getIssue().getDebt()).isEqualTo(expected);
  190. }
  191. @Test
  192. public void formatOperation_should_add_scope_test_on_issue_when_unit_test_file() {
  193. componentDto.setQualifier(UNIT_TEST_FILE);
  194. Operation result = searchResponseFormat.formatOperation(searchResponseData);
  195. assertThat(result.getIssue().getScope()).isEqualTo(TEST.name());
  196. }
  197. @Test
  198. public void formatOperation_should_add_scope_main_on_issue_when_not_unit_test_file() {
  199. componentDto.setQualifier(randomAlphanumeric(5));
  200. Operation result = searchResponseFormat.formatOperation(searchResponseData);
  201. assertThat(result.getIssue().getScope()).isEqualTo(MAIN.name());
  202. }
  203. @Test
  204. public void formatOperation_should_add_actions_on_issues() {
  205. Set<String> expectedActions = Set.of("actionA", "actionB");
  206. searchResponseData.addActions(issueDto.getKey(), expectedActions);
  207. Operation result = searchResponseFormat.formatOperation(searchResponseData);
  208. assertThat(result.getIssue().getActions().getActionsList()).containsExactlyInAnyOrderElementsOf(expectedActions);
  209. }
  210. @Test
  211. public void formatOperation_should_add_transitions_on_issues() {
  212. Set<String> expectedTransitions = Set.of("transitionone", "transitiontwo");
  213. searchResponseData.addTransitions(issueDto.getKey(), createFakeTransitions(expectedTransitions));
  214. Operation result = searchResponseFormat.formatOperation(searchResponseData);
  215. assertThat(result.getIssue().getTransitions().getTransitionsList()).containsExactlyInAnyOrderElementsOf(expectedTransitions);
  216. }
  217. private static List<Transition> createFakeTransitions(Collection<String> transitions) {
  218. return transitions.stream()
  219. .map(transition -> Transition.builder(transition).from("OPEN").to("RESOLVED").build())
  220. .collect(toList());
  221. }
  222. @Test
  223. public void formatOperation_should_add_comments_on_issues() {
  224. IssueChangeDto issueChangeDto = newIssueChangeDto(issueDto);
  225. searchResponseData.setComments(List.of(issueChangeDto));
  226. Operation result = searchResponseFormat.formatOperation(searchResponseData);
  227. assertThat(result.getIssue().getComments().getCommentsList()).hasSize(1).extracting(Common.Comment::getKey).containsExactly(issueChangeDto.getKey());
  228. }
  229. @Test
  230. public void formatOperation_should_not_set_severity_for_security_hotspot_issue() {
  231. issueDto.setType(SECURITY_HOTSPOT);
  232. Operation result = searchResponseFormat.formatOperation(searchResponseData);
  233. assertThat(result.getIssue().hasSeverity()).isFalse();
  234. }
  235. @Test
  236. public void formatOperation_shouldReturnExpectedIssueStatus() {
  237. issueDto.setStatus(org.sonar.api.issue.Issue.STATUS_RESOLVED);
  238. issueDto.setResolution(org.sonar.api.issue.Issue.RESOLUTION_WONT_FIX);
  239. Operation result = searchResponseFormat.formatOperation(searchResponseData);
  240. assertThat(result.getIssue().getIssueStatus()).isEqualTo(IssueStatus.ACCEPTED.name());
  241. }
  242. private SearchResponseData newSearchResponseDataMainBranch() {
  243. ComponentDto projectDto = db.components().insertPublicProject().getMainBranchComponent();
  244. BranchDto branchDto = db.getDbClient().branchDao().selectByUuid(db.getSession(), projectDto.uuid()).get();
  245. return newSearchResponseData(projectDto, branchDto);
  246. }
  247. private SearchResponseData newSearchResponseDataBranch(String name) {
  248. ProjectDto projectDto = db.components().insertPublicProject().getProjectDto();
  249. BranchDto branch = db.components().insertProjectBranch(projectDto, b -> b.setKey(name));
  250. ComponentDto branchComponent = db.components().getComponentDto(branch);
  251. return newSearchResponseData(branchComponent, branch);
  252. }
  253. private SearchResponseData newSearchResponseDataPr(String name) {
  254. ProjectDto projectDto = db.components().insertPublicProject().getProjectDto();
  255. BranchDto branch = db.components().insertProjectBranch(projectDto, b -> b.setKey(name).setBranchType(BranchType.PULL_REQUEST));
  256. ComponentDto branchComponent = db.components().getComponentDto(branch);
  257. return newSearchResponseData(branchComponent, branch);
  258. }
  259. private SearchResponseData newSearchResponseData(ComponentDto component, BranchDto branch) {
  260. RuleDto ruleDto = newRule();
  261. userDto = newUserDto();
  262. componentDto = component;
  263. issueDto = newIssue(ruleDto, component.branchUuid(), component.getKey(), component)
  264. .setType(CODE_SMELL)
  265. .setCleanCodeAttribute(CleanCodeAttribute.CLEAR)
  266. .setRuleDescriptionContextKey("context_key_" + randomAlphanumeric(5))
  267. .setAssigneeUuid(userDto.getUuid())
  268. .setResolution("resolution_" + randomAlphanumeric(5))
  269. .setIssueCreationDate(new Date(currentTimeMillis() - 2_000))
  270. .setIssueUpdateDate(new Date(currentTimeMillis() - 1_000))
  271. .setIssueCloseDate(new Date(currentTimeMillis()));
  272. SearchResponseData searchResponseData = new SearchResponseData(issueDto);
  273. searchResponseData.addComponents(List.of(component));
  274. searchResponseData.addRules(List.of(ruleDto));
  275. searchResponseData.addUsers(List.of(userDto));
  276. searchResponseData.addBranches(List.of(branch));
  277. when(userResponseFormatter.formatUser(any(Common.User.Builder.class), eq(userDto))).thenReturn(user);
  278. return searchResponseData;
  279. }
  280. }