您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

IssueDaoTest.java 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2019 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.db.issue;
  21. import java.util.Arrays;
  22. import java.util.Collection;
  23. import java.util.Collections;
  24. import java.util.List;
  25. import java.util.stream.Stream;
  26. import org.junit.Rule;
  27. import org.junit.Test;
  28. import org.junit.rules.ExpectedException;
  29. import org.sonar.api.issue.Issue;
  30. import org.sonar.api.rule.RuleKey;
  31. import org.sonar.api.rules.RuleType;
  32. import org.sonar.api.utils.System2;
  33. import org.sonar.db.DbTester;
  34. import org.sonar.db.RowNotFoundException;
  35. import org.sonar.db.component.BranchType;
  36. import org.sonar.db.component.ComponentDto;
  37. import org.sonar.db.component.ComponentTesting;
  38. import org.sonar.db.component.KeyType;
  39. import org.sonar.db.organization.OrganizationDto;
  40. import org.sonar.db.rule.RuleDefinitionDto;
  41. import org.sonar.db.rule.RuleDto;
  42. import org.sonar.db.rule.RuleTesting;
  43. import static java.util.Arrays.asList;
  44. import static org.apache.commons.lang.math.RandomUtils.nextInt;
  45. import static org.assertj.core.api.Assertions.assertThat;
  46. import static org.junit.rules.ExpectedException.none;
  47. import static org.sonar.db.component.ComponentTesting.newFileDto;
  48. import static org.sonar.db.component.ComponentTesting.newModuleDto;
  49. public class IssueDaoTest {
  50. private static final String PROJECT_UUID = "prj_uuid";
  51. private static final String PROJECT_KEY = "prj_key";
  52. private static final String FILE_UUID = "file_uuid";
  53. private static final String FILE_KEY = "file_key";
  54. private static final RuleDto RULE = RuleTesting.newXooX1();
  55. private static final String ISSUE_KEY1 = "I1";
  56. private static final String ISSUE_KEY2 = "I2";
  57. private static final RuleType[] RULE_TYPES_EXCEPT_HOTSPOT = Stream.of(RuleType.values())
  58. .filter(r -> r != RuleType.SECURITY_HOTSPOT)
  59. .toArray(RuleType[]::new);
  60. @Rule
  61. public ExpectedException expectedException = none();
  62. @Rule
  63. public DbTester db = DbTester.create(System2.INSTANCE);
  64. private IssueDao underTest = db.getDbClient().issueDao();
  65. @Test
  66. public void selectByKeyOrFail() {
  67. prepareTables();
  68. IssueDto issue = underTest.selectOrFailByKey(db.getSession(), ISSUE_KEY1);
  69. assertThat(issue.getKee()).isEqualTo(ISSUE_KEY1);
  70. assertThat(issue.getId()).isGreaterThan(0L);
  71. assertThat(issue.getComponentUuid()).isEqualTo(FILE_UUID);
  72. assertThat(issue.getProjectUuid()).isEqualTo(PROJECT_UUID);
  73. assertThat(issue.getRuleId()).isEqualTo(RULE.getId());
  74. assertThat(issue.getLanguage()).isEqualTo(RULE.getLanguage());
  75. assertThat(issue.getSeverity()).isEqualTo("BLOCKER");
  76. assertThat(issue.getType()).isEqualTo(2);
  77. assertThat(issue.isManualSeverity()).isFalse();
  78. assertThat(issue.getMessage()).isEqualTo("the message");
  79. assertThat(issue.getLine()).isEqualTo(500);
  80. assertThat(issue.getEffort()).isEqualTo(10L);
  81. assertThat(issue.getGap()).isEqualTo(3.14);
  82. assertThat(issue.getStatus()).isEqualTo("RESOLVED");
  83. assertThat(issue.getResolution()).isEqualTo("FIXED");
  84. assertThat(issue.getChecksum()).isEqualTo("123456789");
  85. assertThat(issue.getAuthorLogin()).isEqualTo("morgan");
  86. assertThat(issue.getAssigneeUuid()).isEqualTo("karadoc");
  87. assertThat(issue.getIssueAttributes()).isEqualTo("JIRA=FOO-1234");
  88. assertThat(issue.getIssueCreationDate()).isNotNull();
  89. assertThat(issue.getIssueUpdateDate()).isNotNull();
  90. assertThat(issue.getIssueCloseDate()).isNotNull();
  91. assertThat(issue.getCreatedAt()).isEqualTo(1_440_000_000_000L);
  92. assertThat(issue.getUpdatedAt()).isEqualTo(1_440_000_000_000L);
  93. assertThat(issue.getRuleRepo()).isEqualTo(RULE.getRepositoryKey());
  94. assertThat(issue.getRule()).isEqualTo(RULE.getRuleKey());
  95. assertThat(issue.getComponentKey()).isEqualTo(FILE_KEY);
  96. assertThat(issue.getProjectKey()).isEqualTo(PROJECT_KEY);
  97. assertThat(issue.getLocations()).isNull();
  98. assertThat(issue.parseLocations()).isNull();
  99. assertThat(issue.isExternal()).isTrue();
  100. }
  101. @Test
  102. public void selectByKeyOrFail_fails_if_key_not_found() {
  103. expectedException.expect(RowNotFoundException.class);
  104. expectedException.expectMessage("Issue with key 'DOES_NOT_EXIST' does not exist");
  105. prepareTables();
  106. underTest.selectOrFailByKey(db.getSession(), "DOES_NOT_EXIST");
  107. }
  108. @Test
  109. public void selectByKeys() {
  110. // contains I1 and I2
  111. prepareTables();
  112. List<IssueDto> issues = underTest.selectByKeys(db.getSession(), asList("I1", "I2", "I3"));
  113. // results are not ordered, so do not use "containsExactly"
  114. assertThat(issues).extracting("key").containsOnly("I1", "I2");
  115. }
  116. @Test
  117. public void scrollNonClosedByComponentUuid() {
  118. RuleDefinitionDto rule = db.rules().insert();
  119. ComponentDto project = db.components().insertPrivateProject();
  120. ComponentDto file = db.components().insertComponent(newFileDto(project));
  121. IssueDto openIssue1OnFile = db.issues().insert(rule, project, file, i -> i.setStatus("OPEN").setResolution(null).setType(randomRuleTypeExceptHotspot()));
  122. IssueDto openIssue2OnFile = db.issues().insert(rule, project, file, i -> i.setStatus("OPEN").setResolution(null).setType(randomRuleTypeExceptHotspot()));
  123. IssueDto closedIssueOnFile = db.issues().insert(rule, project, file, i -> i.setStatus("CLOSED").setResolution("FIXED").setType(randomRuleTypeExceptHotspot()));
  124. IssueDto openIssueOnProject = db.issues().insert(rule, project, project, i -> i.setStatus("OPEN").setResolution(null).setType(randomRuleTypeExceptHotspot()));
  125. IssueDto securityHotspot = db.issues().insert(rule, project, file, i -> i.setType(RuleType.SECURITY_HOTSPOT));
  126. IssueDto manualVulnerability = db.issues().insert(rule, project, file, i -> i.setType(RuleType.VULNERABILITY).setIsFromHotspot(true));
  127. RuleDefinitionDto external = db.rules().insert(ruleDefinitionDto -> ruleDefinitionDto.setIsExternal(true));
  128. IssueDto issueFromExteralruleOnFile = db.issues().insert(external, project, file, i -> i.setKee("ON_FILE_FROM_EXTERNAL").setType(randomRuleTypeExceptHotspot()));
  129. assertThat(underTest.selectNonClosedByComponentUuidExcludingExternalsAndSecurityHotspots(db.getSession(), file.uuid()))
  130. .extracting(IssueDto::getKey)
  131. .containsExactlyInAnyOrder(Arrays.stream(new IssueDto[] {openIssue1OnFile, openIssue2OnFile}).map(IssueDto::getKey).toArray(String[]::new));
  132. assertThat(underTest.selectNonClosedByComponentUuidExcludingExternalsAndSecurityHotspots(db.getSession(), project.uuid()))
  133. .extracting(IssueDto::getKey)
  134. .containsExactlyInAnyOrder(Arrays.stream(new IssueDto[] {openIssueOnProject}).map(IssueDto::getKey).toArray(String[]::new));
  135. assertThat(underTest.selectNonClosedByComponentUuidExcludingExternalsAndSecurityHotspots(db.getSession(), "does_not_exist")).isEmpty();
  136. }
  137. @Test
  138. public void scrollNonClosedByModuleOrProject() {
  139. RuleDefinitionDto rule = db.rules().insert();
  140. ComponentDto project = db.components().insertPrivateProject();
  141. ComponentDto anotherProject = db.components().insertPrivateProject();
  142. ComponentDto module = db.components().insertComponent(newModuleDto(project));
  143. ComponentDto file = db.components().insertComponent(newFileDto(module));
  144. IssueDto openIssue1OnFile = db.issues().insert(rule, project, file, i -> i.setStatus("OPEN").setResolution(null).setType(randomRuleTypeExceptHotspot()));
  145. IssueDto openIssue2OnFile = db.issues().insert(rule, project, file, i -> i.setStatus("OPEN").setResolution(null).setType(randomRuleTypeExceptHotspot()));
  146. IssueDto closedIssueOnFile = db.issues().insert(rule, project, file, i -> i.setStatus("CLOSED").setResolution("FIXED").setType(randomRuleTypeExceptHotspot()));
  147. IssueDto openIssueOnModule = db.issues().insert(rule, project, module, i -> i.setStatus("OPEN").setResolution(null).setType(randomRuleTypeExceptHotspot()));
  148. IssueDto openIssueOnProject = db.issues().insert(rule, project, project, i -> i.setStatus("OPEN").setResolution(null).setType(randomRuleTypeExceptHotspot()));
  149. IssueDto openIssueOnAnotherProject = db.issues().insert(rule, anotherProject, anotherProject, i -> i.setStatus("OPEN").setResolution(null).setType(randomRuleTypeExceptHotspot()));
  150. IssueDto securityHotspot = db.issues().insert(rule, project, file, i -> i.setType(RuleType.SECURITY_HOTSPOT));
  151. IssueDto manualVulnerability = db.issues().insert(rule, project, file, i -> i.setType(RuleType.VULNERABILITY).setIsFromHotspot(true));
  152. RuleDefinitionDto external = db.rules().insert(ruleDefinitionDto -> ruleDefinitionDto.setIsExternal(true));
  153. IssueDto issueFromExteralruleOnFile = db.issues().insert(external, project, file, i -> i.setKee("ON_FILE_FROM_EXTERNAL").setType(randomRuleTypeExceptHotspot()));
  154. assertThat(underTest.selectNonClosedByModuleOrProjectExcludingExternalsAndSecurityHotspots(db.getSession(), project))
  155. .extracting(IssueDto::getKey)
  156. .containsExactlyInAnyOrder(Arrays.stream(new IssueDto[] {openIssue1OnFile, openIssue2OnFile, openIssueOnModule, openIssueOnProject}).map(IssueDto::getKey).toArray(String[]::new));
  157. assertThat(underTest.selectNonClosedByModuleOrProjectExcludingExternalsAndSecurityHotspots(db.getSession(), module))
  158. .extracting(IssueDto::getKey)
  159. .containsExactlyInAnyOrder(Arrays.stream(new IssueDto[] {openIssue1OnFile, openIssue2OnFile, openIssueOnModule}).map(IssueDto::getKey).toArray(String[]::new));
  160. ComponentDto notPersisted = ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization());
  161. assertThat(underTest.selectNonClosedByModuleOrProjectExcludingExternalsAndSecurityHotspots(db.getSession(), notPersisted)).isEmpty();
  162. }
  163. @Test
  164. public void selectOpenByComponentUuid() {
  165. RuleDefinitionDto rule = db.rules().insert();
  166. ComponentDto project = db.components().insertMainBranch();
  167. ComponentDto projectBranch = db.components().insertProjectBranch(project,
  168. b -> b.setKey("feature/foo")
  169. .setBranchType(BranchType.SHORT));
  170. ComponentDto file = db.components().insertComponent(newFileDto(projectBranch));
  171. IssueDto openIssue = db.issues().insert(rule, projectBranch, file, i -> i.setStatus(Issue.STATUS_OPEN).setResolution(null));
  172. IssueDto closedIssue = db.issues().insert(rule, projectBranch, file, i -> i.setStatus(Issue.STATUS_CLOSED).setResolution(Issue.RESOLUTION_FIXED));
  173. IssueDto reopenedIssue = db.issues().insert(rule, projectBranch, file, i -> i.setStatus(Issue.STATUS_REOPENED).setResolution(null));
  174. IssueDto confirmedIssue = db.issues().insert(rule, projectBranch, file, i -> i.setStatus(Issue.STATUS_CONFIRMED).setResolution(null));
  175. IssueDto wontfixIssue = db.issues().insert(rule, projectBranch, file, i -> i.setStatus(Issue.STATUS_RESOLVED).setResolution(Issue.RESOLUTION_WONT_FIX));
  176. IssueDto fpIssue = db.issues().insert(rule, projectBranch, file, i -> i.setStatus(Issue.STATUS_RESOLVED).setResolution(Issue.RESOLUTION_FALSE_POSITIVE));
  177. assertThat(underTest.selectOpenByComponentUuids(db.getSession(), Collections.singletonList(file.uuid())))
  178. .extracting("kee")
  179. .containsOnly(openIssue.getKey(), reopenedIssue.getKey(), confirmedIssue.getKey(), wontfixIssue.getKey(), fpIssue.getKey());
  180. }
  181. @Test
  182. public void selectOpenByComponentUuid_should_correctly_map_required_fields() {
  183. RuleDefinitionDto rule = db.rules().insert();
  184. ComponentDto project = db.components().insertMainBranch();
  185. ComponentDto projectBranch = db.components().insertProjectBranch(project,
  186. b -> b.setKey("feature/foo")
  187. .setBranchType(BranchType.SHORT));
  188. ComponentDto file = db.components().insertComponent(newFileDto(projectBranch));
  189. IssueDto fpIssue = db.issues().insert(rule, projectBranch, file, i -> i.setStatus("RESOLVED").setResolution("FALSE-POSITIVE"));
  190. ShortBranchIssueDto fp = underTest.selectOpenByComponentUuids(db.getSession(), Collections.singletonList(file.uuid())).get(0);
  191. assertThat(fp.getLine()).isEqualTo(fpIssue.getLine());
  192. assertThat(fp.getMessage()).isEqualTo(fpIssue.getMessage());
  193. assertThat(fp.getChecksum()).isEqualTo(fpIssue.getChecksum());
  194. assertThat(fp.getRuleKey()).isEqualTo(fpIssue.getRuleKey());
  195. assertThat(fp.getStatus()).isEqualTo(fpIssue.getStatus());
  196. assertThat(fp.getLine()).isNotNull();
  197. assertThat(fp.getLine()).isNotZero();
  198. assertThat(fp.getMessage()).isNotNull();
  199. assertThat(fp.getChecksum()).isNotNull();
  200. assertThat(fp.getChecksum()).isNotEmpty();
  201. assertThat(fp.getRuleKey()).isNotNull();
  202. assertThat(fp.getStatus()).isNotNull();
  203. assertThat(fp.getBranchKey()).isEqualTo("feature/foo");
  204. assertThat(fp.getKeyType()).isEqualTo(KeyType.BRANCH);
  205. assertThat(fp.getIssueUpdateDate()).isNotNull();
  206. }
  207. @Test
  208. public void test_selectGroupsOfComponentTreeOnLeak_on_component_without_issues() {
  209. ComponentDto project = db.components().insertPublicProject();
  210. ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(project));
  211. Collection<IssueGroupDto> groups = underTest.selectIssueGroupsByBaseComponent(db.getSession(), file, 1_000L);
  212. assertThat(groups).isEmpty();
  213. }
  214. @Test
  215. public void selectGroupsOfComponentTreeOnLeak_on_file() {
  216. ComponentDto project = db.components().insertPublicProject();
  217. ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(project));
  218. RuleDefinitionDto rule = db.rules().insert();
  219. IssueDto fpBug = db.issues().insert(rule, project, file,
  220. i -> i.setStatus("RESOLVED").setResolution("FALSE-POSITIVE").setSeverity("MAJOR").setType(RuleType.BUG).setIssueCreationTime(1_500L));
  221. IssueDto criticalBug1 = db.issues().insert(rule, project, file,
  222. i -> i.setStatus("OPEN").setResolution(null).setSeverity("CRITICAL").setType(RuleType.BUG).setIssueCreationTime(1_600L));
  223. IssueDto criticalBug2 = db.issues().insert(rule, project, file,
  224. i -> i.setStatus("OPEN").setResolution(null).setSeverity("CRITICAL").setType(RuleType.BUG).setIssueCreationTime(1_700L));
  225. // closed issues are ignored
  226. IssueDto closed = db.issues().insert(rule, project, file,
  227. i -> i.setStatus("CLOSED").setResolution("REMOVED").setSeverity("CRITICAL").setType(RuleType.BUG).setIssueCreationTime(1_700L));
  228. Collection<IssueGroupDto> result = underTest.selectIssueGroupsByBaseComponent(db.getSession(), file, 1_000L);
  229. assertThat(result.stream().mapToLong(IssueGroupDto::getCount).sum()).isEqualTo(3);
  230. assertThat(result.stream().filter(g -> g.getRuleType()==RuleType.BUG.getDbConstant()).mapToLong(IssueGroupDto::getCount).sum()).isEqualTo(3);
  231. assertThat(result.stream().filter(g -> g.getRuleType()==RuleType.CODE_SMELL.getDbConstant()).mapToLong(IssueGroupDto::getCount).sum()).isEqualTo(0);
  232. assertThat(result.stream().filter(g -> g.getRuleType()==RuleType.VULNERABILITY.getDbConstant()).mapToLong(IssueGroupDto::getCount).sum()).isEqualTo(0);
  233. assertThat(result.stream().filter(g -> g.getSeverity().equals("CRITICAL")).mapToLong(IssueGroupDto::getCount).sum()).isEqualTo(2);
  234. assertThat(result.stream().filter(g -> g.getSeverity().equals("MAJOR")).mapToLong(IssueGroupDto::getCount).sum()).isEqualTo(1);
  235. assertThat(result.stream().filter(g -> g.getSeverity().equals("MINOR")).mapToLong(IssueGroupDto::getCount).sum()).isEqualTo(0);
  236. assertThat(result.stream().filter(g -> g.getStatus().equals("OPEN")).mapToLong(IssueGroupDto::getCount).sum()).isEqualTo(2);
  237. assertThat(result.stream().filter(g -> g.getStatus().equals("RESOLVED")).mapToLong(IssueGroupDto::getCount).sum()).isEqualTo(1);
  238. assertThat(result.stream().filter(g -> g.getStatus().equals("CLOSED")).mapToLong(IssueGroupDto::getCount).sum()).isEqualTo(0);
  239. assertThat(result.stream().filter(g -> "FALSE-POSITIVE" .equals(g.getResolution())).mapToLong(IssueGroupDto::getCount).sum()).isEqualTo(1);
  240. assertThat(result.stream().filter(g -> g.getResolution()== null).mapToLong(IssueGroupDto::getCount).sum()).isEqualTo(2);
  241. assertThat(result.stream().filter(g -> g.isInLeak()).mapToLong(IssueGroupDto::getCount).sum()).isEqualTo(3);
  242. assertThat(result.stream().filter(g -> !g.isInLeak()).mapToLong(IssueGroupDto::getCount).sum()).isEqualTo(0);
  243. // test leak
  244. result = underTest.selectIssueGroupsByBaseComponent(db.getSession(), file, 999_999_999L);
  245. assertThat(result.stream().filter(g -> g.isInLeak()).mapToLong(IssueGroupDto::getCount).sum()).isEqualTo(0);
  246. assertThat(result.stream().filter(g -> !g.isInLeak()).mapToLong(IssueGroupDto::getCount).sum()).isEqualTo(3);
  247. }
  248. private static IssueDto newIssueDto(String key) {
  249. IssueDto dto = new IssueDto();
  250. dto.setComponent(new ComponentDto().setDbKey("struts:Action").setId(123L).setUuid("component-uuid"));
  251. dto.setProject(new ComponentDto().setDbKey("struts").setId(100L).setUuid("project-uuid"));
  252. dto.setRule(RuleTesting.newRule(RuleKey.of("squid", "S001")).setId(200));
  253. dto.setKee(key);
  254. dto.setType(2);
  255. dto.setLine(500);
  256. dto.setGap(3.14);
  257. dto.setEffort(10L);
  258. dto.setResolution("FIXED");
  259. dto.setStatus("RESOLVED");
  260. dto.setSeverity("BLOCKER");
  261. dto.setAuthorLogin("morgan");
  262. dto.setAssigneeUuid("karadoc");
  263. dto.setIssueAttributes("JIRA=FOO-1234");
  264. dto.setChecksum("123456789");
  265. dto.setMessage("the message");
  266. dto.setCreatedAt(1_440_000_000_000L);
  267. dto.setUpdatedAt(1_440_000_000_000L);
  268. dto.setIssueCreationTime(1_450_000_000_000L);
  269. dto.setIssueUpdateTime(1_450_000_000_000L);
  270. dto.setIssueCloseTime(1_450_000_000_000L);
  271. return dto;
  272. }
  273. private void prepareTables() {
  274. db.rules().insertRule(RULE.setIsExternal(true));
  275. OrganizationDto organizationDto = db.organizations().insert();
  276. ComponentDto projectDto = db.components().insertPrivateProject(organizationDto, (t) -> t.setUuid(PROJECT_UUID).setDbKey(PROJECT_KEY));
  277. db.components().insertComponent(newFileDto(projectDto).setUuid(FILE_UUID).setDbKey(FILE_KEY));
  278. underTest.insert(db.getSession(), newIssueDto(ISSUE_KEY1)
  279. .setMessage("the message")
  280. .setRuleId(RULE.getId())
  281. .setComponentUuid(FILE_UUID)
  282. .setProjectUuid(PROJECT_UUID));
  283. underTest.insert(db.getSession(), newIssueDto(ISSUE_KEY2)
  284. .setRuleId(RULE.getId())
  285. .setComponentUuid(FILE_UUID)
  286. .setProjectUuid(PROJECT_UUID));
  287. db.getSession().commit();
  288. }
  289. private static RuleType randomRuleTypeExceptHotspot() {
  290. return RULE_TYPES_EXCEPT_HOTSPOT[nextInt(RULE_TYPES_EXCEPT_HOTSPOT.length)];
  291. }
  292. }