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.

IssueMapperTest.java 24KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575
  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.db.issue;
  21. import com.tngtech.java.junit.dataprovider.DataProvider;
  22. import com.tngtech.java.junit.dataprovider.DataProviderRunner;
  23. import com.tngtech.java.junit.dataprovider.UseDataProvider;
  24. import java.util.ArrayList;
  25. import java.util.Arrays;
  26. import java.util.Date;
  27. import java.util.List;
  28. import java.util.Random;
  29. import java.util.function.Consumer;
  30. import java.util.stream.IntStream;
  31. import org.apache.ibatis.session.ResultContext;
  32. import org.apache.ibatis.session.ResultHandler;
  33. import org.junit.Before;
  34. import org.junit.Rule;
  35. import org.junit.Test;
  36. import org.junit.runner.RunWith;
  37. import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
  38. import org.sonar.api.issue.Issue;
  39. import org.sonar.api.rules.RuleType;
  40. import org.sonar.api.utils.DateUtils;
  41. import org.sonar.api.utils.System2;
  42. import org.sonar.core.issue.FieldDiffs;
  43. import org.sonar.core.util.UuidFactoryFast;
  44. import org.sonar.core.util.Uuids;
  45. import org.sonar.db.DbSession;
  46. import org.sonar.db.DbTester;
  47. import org.sonar.db.component.ComponentDto;
  48. import org.sonar.db.component.ComponentTesting;
  49. import org.sonar.db.organization.OrganizationDto;
  50. import org.sonar.db.rule.RuleDefinitionDto;
  51. import org.sonar.db.rule.RuleDto;
  52. import org.sonar.db.rule.RuleTesting;
  53. import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
  54. import static org.assertj.core.api.Assertions.assertThat;
  55. import static org.assertj.core.api.Assertions.tuple;
  56. @RunWith(DataProviderRunner.class)
  57. public class IssueMapperTest {
  58. private static final long NO_FILTERING_ON_CLOSE_DATE = 1L;
  59. @Rule
  60. public DbTester dbTester = DbTester.create(System2.INSTANCE);
  61. private DbSession dbSession = dbTester.getSession();
  62. private IssueMapper underTest = dbSession.getMapper(IssueMapper.class);
  63. private ComponentDto project, file, file2;
  64. private RuleDto rule;
  65. private Random random = new Random();
  66. private System2 system2 = new AlwaysIncreasingSystem2();
  67. @Before
  68. public void setUp() {
  69. OrganizationDto organizationDto = dbTester.organizations().insert();
  70. project = ComponentTesting.newPrivateProjectDto(organizationDto);
  71. dbTester.getDbClient().componentDao().insert(dbSession, project);
  72. file = ComponentTesting.newFileDto(project, null);
  73. dbTester.getDbClient().componentDao().insert(dbSession, file);
  74. file2 = ComponentTesting.newFileDto(project, null).setUuid("file2 uuid");
  75. dbTester.getDbClient().componentDao().insert(dbSession, file2);
  76. rule = RuleTesting.newXooX1();
  77. dbTester.rules().insertRule(rule);
  78. dbSession.commit();
  79. }
  80. @Test
  81. public void insert() {
  82. underTest.insert(newIssue());
  83. dbTester.getSession().commit();
  84. IssueDto result = underTest.selectByKey("ABCDE");
  85. assertThat(result).isNotNull();
  86. assertThat(result.getKey()).isEqualTo("ABCDE");
  87. assertThat(result.getComponentUuid()).isEqualTo(file.uuid());
  88. assertThat(result.getProjectUuid()).isEqualTo(project.uuid());
  89. assertThat(result.getRuleUuid()).isEqualTo(rule.getUuid());
  90. assertThat(result.getType()).isEqualTo(2);
  91. assertThat(result.getLine()).isEqualTo(500);
  92. assertThat(result.getGap()).isEqualTo(3.14d);
  93. assertThat(result.getEffort()).isEqualTo(10L);
  94. assertThat(result.getResolution()).isEqualTo("FIXED");
  95. assertThat(result.getStatus()).isEqualTo("RESOLVED");
  96. assertThat(result.getSeverity()).isEqualTo("BLOCKER");
  97. assertThat(result.getAuthorLogin()).isEqualTo("morgan");
  98. assertThat(result.getAssigneeUuid()).isEqualTo("karadoc");
  99. assertThat(result.getIssueAttributes()).isEqualTo("JIRA=FOO-1234");
  100. assertThat(result.getChecksum()).isEqualTo("123456789");
  101. assertThat(result.getMessage()).isEqualTo("the message");
  102. assertThat(result.getIssueCreationTime()).isEqualTo(1_401_000_000_000L);
  103. assertThat(result.getIssueUpdateTime()).isEqualTo(1_402_000_000_000L);
  104. assertThat(result.getIssueCloseTime()).isEqualTo(1_403_000_000_000L);
  105. assertThat(result.getCreatedAt()).isEqualTo(1_400_000_000_000L);
  106. assertThat(result.getUpdatedAt()).isEqualTo(1_500_000_000_000L);
  107. }
  108. @Test
  109. public void update() {
  110. underTest.insert(newIssue());
  111. dbTester.getSession().commit();
  112. IssueDto update = new IssueDto();
  113. update.setKee("ABCDE");
  114. update.setComponentUuid("other component uuid");
  115. update.setProjectUuid(project.uuid());
  116. update.setRuleUuid(rule.getUuid());
  117. update.setType(3);
  118. update.setLine(500);
  119. update.setGap(3.14);
  120. update.setEffort(10L);
  121. update.setResolution("FIXED");
  122. update.setStatus("RESOLVED");
  123. update.setSeverity("BLOCKER");
  124. update.setAuthorLogin("morgan");
  125. update.setAssigneeUuid("karadoc");
  126. update.setIssueAttributes("JIRA=FOO-1234");
  127. update.setChecksum("123456789");
  128. update.setMessage("the message");
  129. update.setIssueCreationTime(1_550_000_000_000L);
  130. update.setIssueUpdateTime(1_550_000_000_000L);
  131. update.setIssueCloseTime(1_550_000_000_000L);
  132. // Should not change
  133. update.setCreatedAt(1_400_123_456_789L);
  134. update.setUpdatedAt(1_550_000_000_000L);
  135. underTest.update(update);
  136. dbTester.getSession().commit();
  137. IssueDto result = underTest.selectByKey("ABCDE");
  138. assertThat(result).isNotNull();
  139. assertThat(result.getKey()).isEqualTo("ABCDE");
  140. assertThat(result.getComponentUuid()).isEqualTo(file.uuid());
  141. assertThat(result.getProjectUuid()).isEqualTo(project.uuid());
  142. assertThat(result.getRuleUuid()).isEqualTo(rule.getUuid());
  143. assertThat(result.getType()).isEqualTo(3);
  144. assertThat(result.getLine()).isEqualTo(500);
  145. assertThat(result.getGap()).isEqualTo(3.14d);
  146. assertThat(result.getEffort()).isEqualTo(10L);
  147. assertThat(result.getResolution()).isEqualTo("FIXED");
  148. assertThat(result.getStatus()).isEqualTo("RESOLVED");
  149. assertThat(result.getSeverity()).isEqualTo("BLOCKER");
  150. assertThat(result.getAuthorLogin()).isEqualTo("morgan");
  151. assertThat(result.getAssigneeUuid()).isEqualTo("karadoc");
  152. assertThat(result.getIssueAttributes()).isEqualTo("JIRA=FOO-1234");
  153. assertThat(result.getChecksum()).isEqualTo("123456789");
  154. assertThat(result.getMessage()).isEqualTo("the message");
  155. assertThat(result.getIssueCreationTime()).isEqualTo(1_550_000_000_000L);
  156. assertThat(result.getIssueUpdateTime()).isEqualTo(1_550_000_000_000L);
  157. assertThat(result.getIssueCloseTime()).isEqualTo(1_550_000_000_000L);
  158. assertThat(result.getCreatedAt()).isEqualTo(1_400_000_000_000L);
  159. assertThat(result.getUpdatedAt()).isEqualTo(1_550_000_000_000L);
  160. }
  161. @Test
  162. public void updateBeforeSelectedDate_without_conflict() {
  163. underTest.insert(newIssue());
  164. IssueDto dto = newIssue()
  165. .setComponentUuid(file2.uuid())
  166. .setType(3)
  167. .setLine(600)
  168. .setGap(1.12d)
  169. .setEffort(50L)
  170. .setIssueUpdateTime(1_600_000_000_000L)
  171. .setUpdatedAt(1_600_000_000_000L);
  172. // selected after last update -> ok
  173. dto.setSelectedAt(1500000000000L);
  174. int count = underTest.updateIfBeforeSelectedDate(dto);
  175. assertThat(count).isEqualTo(1);
  176. dbTester.getSession().commit();
  177. IssueDto result = underTest.selectByKey("ABCDE");
  178. assertThat(result).isNotNull();
  179. assertThat(result.getComponentUuid()).isEqualTo(file2.uuid());
  180. assertThat(result.getType()).isEqualTo(3);
  181. assertThat(result.getLine()).isEqualTo(600);
  182. assertThat(result.getGap()).isEqualTo(1.12d);
  183. assertThat(result.getEffort()).isEqualTo(50L);
  184. assertThat(result.getIssueUpdateTime()).isEqualTo(1_600_000_000_000L);
  185. assertThat(result.getUpdatedAt()).isEqualTo(1_600_000_000_000L);
  186. }
  187. @Test
  188. public void updateBeforeSelectedDate_with_conflict() {
  189. underTest.insert(newIssue());
  190. IssueDto dto = newIssue()
  191. .setComponentUuid(file2.uuid())
  192. .setType(3)
  193. .setLine(600)
  194. .setGap(1.12d)
  195. .setEffort(50L)
  196. .setIssueUpdateTime(1_600_000_000_000L)
  197. .setUpdatedAt(1_600_000_000_000L);
  198. // selected before last update -> ko
  199. dto.setSelectedAt(1400000000000L);
  200. int count = underTest.updateIfBeforeSelectedDate(dto);
  201. assertThat(count).isEqualTo(0);
  202. dbTester.getSession().commit();
  203. // No change
  204. IssueDto result = underTest.selectByKey("ABCDE");
  205. assertThat(result).isNotNull();
  206. assertThat(result.getComponentUuid()).isEqualTo(file.uuid());
  207. assertThat(result.getType()).isEqualTo(2);
  208. assertThat(result.getLine()).isEqualTo(500);
  209. assertThat(result.getGap()).isEqualTo(3.14d);
  210. assertThat(result.getEffort()).isEqualTo(10L);
  211. assertThat(result.getIssueUpdateTime()).isEqualTo(1_402_000_000_000L);
  212. assertThat(result.getUpdatedAt()).isEqualTo(1_500_000_000_000L);
  213. }
  214. @Test
  215. public void scrollClosedByComponentUuid_returns_empty_when_no_issue_for_component() {
  216. String componentUuid = randomAlphabetic(10);
  217. RecorderResultHandler resultHandler = new RecorderResultHandler();
  218. underTest.scrollClosedByComponentUuid(componentUuid, new Date().getTime(), resultHandler);
  219. assertThat(resultHandler.issues).isEmpty();
  220. }
  221. @Test
  222. @UseDataProvider("closedIssuesSupportedRuleTypes")
  223. public void scrollClosedByComponentUuid_returns_closed_issues_with_at_least_one_diff_to_CLOSED(RuleType ruleType) {
  224. OrganizationDto organization = dbTester.organizations().insert();
  225. ComponentDto component = randomComponent(organization);
  226. IssueDto expected = insertNewClosedIssue(component, ruleType);
  227. IssueChangeDto changeDto = insertToClosedDiff(expected);
  228. RecorderResultHandler resultHandler = new RecorderResultHandler();
  229. underTest.scrollClosedByComponentUuid(component.uuid(), NO_FILTERING_ON_CLOSE_DATE, resultHandler);
  230. assertThat(resultHandler.issues).hasSize(1);
  231. IssueDto issue = resultHandler.issues.iterator().next();
  232. assertThat(issue.getKey()).isEqualTo(issue.getKey());
  233. assertThat(issue.getClosedChangeData()).contains(changeDto.getChangeData());
  234. }
  235. @Test
  236. @UseDataProvider("closedIssuesSupportedRuleTypes")
  237. public void scrollClosedByComponentUuid_does_not_return_closed_issues_of_non_existing_rule(RuleType ruleType) {
  238. OrganizationDto organization = dbTester.organizations().insert();
  239. ComponentDto component = randomComponent(organization);
  240. IssueDto issueWithRule = insertNewClosedIssue(component, ruleType);
  241. IssueChangeDto issueChange = insertToClosedDiff(issueWithRule);
  242. IssueDto issueWithoutRule = insertNewClosedIssue(component, new RuleDefinitionDto().setType(ruleType).setUuid("uuid-50"));
  243. insertToClosedDiff(issueWithoutRule);
  244. RecorderResultHandler resultHandler = new RecorderResultHandler();
  245. underTest.scrollClosedByComponentUuid(component.uuid(), NO_FILTERING_ON_CLOSE_DATE, resultHandler);
  246. assertThat(resultHandler.issues)
  247. .extracting(IssueDto::getKey, t -> t.getClosedChangeData().get())
  248. .containsOnly(tuple(issueWithRule.getKey(), issueChange.getChangeData()));
  249. }
  250. @Test
  251. @UseDataProvider("closedIssuesSupportedRuleTypes")
  252. public void scrollClosedByComponentUuid_does_not_return_closed_issues_of_orphan_component(RuleType ruleType) {
  253. OrganizationDto organization = dbTester.organizations().insert();
  254. ComponentDto component = randomComponent(organization);
  255. IssueDto issue = insertNewClosedIssue(component, ruleType);
  256. IssueChangeDto issueChange = insertToClosedDiff(issue);
  257. IssueDto issueMissingComponent = insertNewClosedIssue(component, ruleType, t -> t.setComponentUuid("does_not_exist"));
  258. insertToClosedDiff(issueMissingComponent);
  259. IssueDto issueMissingProject = insertNewClosedIssue(component, ruleType, t -> t.setProjectUuid("does_not_exist"));
  260. insertToClosedDiff(issueMissingProject);
  261. RecorderResultHandler resultHandler = new RecorderResultHandler();
  262. underTest.scrollClosedByComponentUuid(component.uuid(), NO_FILTERING_ON_CLOSE_DATE, resultHandler);
  263. assertThat(resultHandler.issues)
  264. .extracting(IssueDto::getKey, t -> t.getClosedChangeData().get())
  265. .containsOnly(tuple(issue.getKey(), issueChange.getChangeData()));
  266. }
  267. @Test
  268. @UseDataProvider("closedIssuesSupportedRuleTypes")
  269. public void scrollClosedByComponentUuid_does_not_return_closed_issues_without_any_status_diff_to_CLOSED(RuleType ruleType) {
  270. OrganizationDto organization = dbTester.organizations().insert();
  271. ComponentDto component = randomComponent(organization);
  272. IssueDto issueWithLineDiff = insertNewClosedIssue(component, ruleType);
  273. IssueChangeDto issueChange = insertToClosedDiff(issueWithLineDiff);
  274. insertNewClosedIssue(component, ruleType);
  275. RecorderResultHandler resultHandler = new RecorderResultHandler();
  276. underTest.scrollClosedByComponentUuid(component.uuid(), NO_FILTERING_ON_CLOSE_DATE, resultHandler);
  277. assertThat(resultHandler.issues)
  278. .extracting(IssueDto::getKey, t -> t.getClosedChangeData().get())
  279. .containsOnly(tuple(issueWithLineDiff.getKey(), issueChange.getChangeData()));
  280. }
  281. @Test
  282. public void scrollClosedByComponentUuid_does_not_return_closed_issues_of_type_SECURITY_HOTSPOT() {
  283. RuleType ruleType = randomSupportedRuleType();
  284. OrganizationDto organization = dbTester.organizations().insert();
  285. ComponentDto component = randomComponent(organization);
  286. IssueDto securityHotspotIssue = insertNewClosedIssue(component, RuleType.SECURITY_HOTSPOT);
  287. insertToClosedDiff(securityHotspotIssue);
  288. IssueDto issue = insertNewClosedIssue(component, ruleType);
  289. IssueChangeDto issueChange = insertToClosedDiff(issue);
  290. RecorderResultHandler resultHandler = new RecorderResultHandler();
  291. underTest.scrollClosedByComponentUuid(component.uuid(), NO_FILTERING_ON_CLOSE_DATE, resultHandler);
  292. assertThat(resultHandler.issues)
  293. .extracting(IssueDto::getKey, t -> t.getClosedChangeData().get())
  294. .containsOnly(tuple(issue.getKey(), issueChange.getChangeData()));
  295. }
  296. @Test
  297. public void scrollClosedByComponentUuid_does_not_return_closed_issues_without_close_date() {
  298. RuleType ruleType = randomSupportedRuleType();
  299. OrganizationDto organization = dbTester.organizations().insert();
  300. ComponentDto component = randomComponent(organization);
  301. IssueDto issueWithoutCloseDate = insertNewClosedIssue(component, ruleType, t -> t.setIssueCloseDate(null));
  302. insertToClosedDiff(issueWithoutCloseDate);
  303. IssueDto issueCloseDate = insertNewClosedIssue(component, ruleType);
  304. IssueChangeDto changeDto = insertToClosedDiff(issueCloseDate);
  305. RecorderResultHandler resultHandler = new RecorderResultHandler();
  306. underTest.scrollClosedByComponentUuid(component.uuid(), NO_FILTERING_ON_CLOSE_DATE, resultHandler);
  307. assertThat(resultHandler.issues).hasSize(1);
  308. IssueDto issue = resultHandler.issues.iterator().next();
  309. assertThat(issue.getKey()).isEqualTo(issue.getKey());
  310. assertThat(issue.getClosedChangeData()).contains(changeDto.getChangeData());
  311. }
  312. @Test
  313. public void scrollClosedByComponentUuid_returns_closed_issues_which_close_date_is_greater_or_equal_to_requested() {
  314. RuleType ruleType = randomSupportedRuleType();
  315. OrganizationDto organization = dbTester.organizations().insert();
  316. ComponentDto component = randomComponent(organization);
  317. RuleDefinitionDto rule1 = dbTester.rules().insert(t -> t.setType(ruleType));
  318. IssueDto[] issues = new IssueDto[] {
  319. insertNewClosedIssue(component, rule1, 1_999_999L),
  320. insertNewClosedIssue(component, rule1, 3_999_999L),
  321. insertNewClosedIssue(component, rule1, 2_999_999L),
  322. insertNewClosedIssue(component, rule1, 10_999_999L)
  323. };
  324. Arrays.stream(issues).forEach(this::insertToClosedDiff);
  325. RecorderResultHandler resultHandler = new RecorderResultHandler();
  326. underTest.scrollClosedByComponentUuid(component.uuid(), 4_000_000L, resultHandler);
  327. assertThat(resultHandler.issues)
  328. .extracting(IssueDto::getKey)
  329. .containsOnly(issues[3].getKey());
  330. resultHandler = new RecorderResultHandler();
  331. underTest.scrollClosedByComponentUuid(component.uuid(), 11_999_999L, resultHandler);
  332. assertThat(resultHandler.issues).isEmpty();
  333. resultHandler = new RecorderResultHandler();
  334. underTest.scrollClosedByComponentUuid(component.uuid(), 3_999_999L, resultHandler);
  335. assertThat(resultHandler.issues)
  336. .extracting(IssueDto::getKey)
  337. .containsOnly(issues[3].getKey(), issues[1].getKey());
  338. resultHandler = new RecorderResultHandler();
  339. underTest.scrollClosedByComponentUuid(component.uuid(), 2_999_999L, resultHandler);
  340. assertThat(resultHandler.issues)
  341. .extracting(IssueDto::getKey)
  342. .containsOnly(issues[3].getKey(), issues[1].getKey(), issues[2].getKey());
  343. resultHandler = new RecorderResultHandler();
  344. underTest.scrollClosedByComponentUuid(component.uuid(), 1L, resultHandler);
  345. assertThat(resultHandler.issues)
  346. .extracting(IssueDto::getKey)
  347. .containsOnly(issues[3].getKey(), issues[1].getKey(), issues[2].getKey(), issues[0].getKey());
  348. }
  349. @Test
  350. @UseDataProvider("closedIssuesSupportedRuleTypes")
  351. public void scrollClosedByComponentUuid_return_one_row_per_status_diff_to_CLOSED_sorted_by_most_recent_creation_date_first(RuleType ruleType) {
  352. OrganizationDto organization = dbTester.organizations().insert();
  353. ComponentDto component = randomComponent(organization);
  354. IssueDto issue = insertNewClosedIssue(component, ruleType);
  355. Date date = new Date();
  356. IssueChangeDto[] changes = new IssueChangeDto[] {
  357. insertToClosedDiff(issue, DateUtils.addDays(date, -10)),
  358. insertToClosedDiff(issue, DateUtils.addDays(date, -60)),
  359. insertToClosedDiff(issue, date),
  360. insertToClosedDiff(issue, DateUtils.addDays(date, -5))
  361. };
  362. RecorderResultHandler resultHandler = new RecorderResultHandler();
  363. underTest.scrollClosedByComponentUuid(component.uuid(), NO_FILTERING_ON_CLOSE_DATE, resultHandler);
  364. assertThat(resultHandler.issues)
  365. .hasSize(4)
  366. .extracting(IssueDto::getKey, t -> t.getClosedChangeData().get())
  367. .containsExactly(
  368. tuple(issue.getKey(), changes[2].getChangeData()),
  369. tuple(issue.getKey(), changes[3].getChangeData()),
  370. tuple(issue.getKey(), changes[0].getChangeData()),
  371. tuple(issue.getKey(), changes[1].getChangeData()));
  372. }
  373. @Test
  374. @UseDataProvider("closedIssuesSupportedRuleTypes")
  375. public void scrollClosedByComponentUuid_does_not_return_row_for_status_change_from_close(RuleType ruleType) {
  376. OrganizationDto organization = dbTester.organizations().insert();
  377. ComponentDto component = randomComponent(organization);
  378. IssueDto issue = insertNewClosedIssue(component, ruleType);
  379. Date date = new Date();
  380. IssueChangeDto[] changes = new IssueChangeDto[] {
  381. insertToClosedDiff(issue, DateUtils.addDays(date, -10), Issue.STATUS_CLOSED, Issue.STATUS_REOPENED),
  382. insertToClosedDiff(issue, DateUtils.addDays(date, -60)),
  383. insertToClosedDiff(issue, date),
  384. insertToClosedDiff(issue, DateUtils.addDays(date, -5))
  385. };
  386. RecorderResultHandler resultHandler = new RecorderResultHandler();
  387. underTest.scrollClosedByComponentUuid(component.uuid(), NO_FILTERING_ON_CLOSE_DATE, resultHandler);
  388. assertThat(resultHandler.issues)
  389. .hasSize(3)
  390. .extracting(IssueDto::getKey, t -> t.getClosedChangeData().get())
  391. .containsExactly(
  392. tuple(issue.getKey(), changes[2].getChangeData()),
  393. tuple(issue.getKey(), changes[3].getChangeData()),
  394. tuple(issue.getKey(), changes[1].getChangeData()));
  395. }
  396. private IssueChangeDto insertToClosedDiff(IssueDto issueDto) {
  397. return insertToClosedDiff(issueDto, new Date());
  398. }
  399. private IssueChangeDto insertToClosedDiff(IssueDto issueDto, Date date) {
  400. String[] statusesButClosed = Issue.STATUSES.stream()
  401. .filter(t -> !Issue.STATUS_CLOSED.equals(t))
  402. .toArray(String[]::new);
  403. String previousStatus = statusesButClosed[random.nextInt(statusesButClosed.length)];
  404. return insertToClosedDiff(issueDto, date, previousStatus, Issue.STATUS_CLOSED);
  405. }
  406. private IssueChangeDto insertToClosedDiff(IssueDto issue, Date creationDate, String previousStatus, String nextStatus) {
  407. FieldDiffs diffs = new FieldDiffs()
  408. .setCreationDate(creationDate);
  409. IntStream.range(0, random.nextInt(3)).forEach(i -> diffs.setDiff("key_b" + i, "old_" + i, "new_" + i));
  410. diffs.setDiff("status", previousStatus, nextStatus);
  411. IntStream.range(0, random.nextInt(3)).forEach(i -> diffs.setDiff("key_a" + i, "old_" + i, "new_" + i));
  412. IssueChangeDto changeDto = IssueChangeDto.of(issue.getKey(), diffs);
  413. changeDto.setUuid(Uuids.createFast());
  414. dbTester.getDbClient().issueChangeDao().insert(dbSession, changeDto);
  415. return changeDto;
  416. }
  417. @SafeVarargs
  418. private final IssueDto insertNewClosedIssue(ComponentDto component, RuleType ruleType, Consumer<IssueDto>... consumers) {
  419. RuleDefinitionDto rule = dbTester.rules().insert(t -> t.setType(ruleType));
  420. return insertNewClosedIssue(component, rule, system2.now(), consumers);
  421. }
  422. @SafeVarargs
  423. private final IssueDto insertNewClosedIssue(ComponentDto component, RuleDefinitionDto rule, Consumer<IssueDto>... consumers) {
  424. return insertNewClosedIssue(component, rule, system2.now(), consumers);
  425. }
  426. @SafeVarargs
  427. private final IssueDto insertNewClosedIssue(ComponentDto component, RuleDefinitionDto rule, long issueCloseTime, Consumer<IssueDto>... consumers) {
  428. IssueDto res = new IssueDto()
  429. .setKee(UuidFactoryFast.getInstance().create())
  430. .setRuleUuid(rule.getUuid())
  431. .setType(rule.getType())
  432. .setComponentUuid(component.uuid())
  433. .setProjectUuid(component.projectUuid())
  434. .setStatus(Issue.STATUS_CLOSED)
  435. .setIssueCloseTime(issueCloseTime);
  436. Arrays.asList(consumers).forEach(c -> c.accept(res));
  437. underTest.insert(res);
  438. dbSession.commit();
  439. return res;
  440. }
  441. private static final RuleType[] SUPPORTED_RULE_TYPES = Arrays.stream(RuleType.values())
  442. .filter(t -> t != RuleType.SECURITY_HOTSPOT)
  443. .toArray(RuleType[]::new);
  444. @DataProvider
  445. public static Object[][] closedIssuesSupportedRuleTypes() {
  446. return Arrays.stream(SUPPORTED_RULE_TYPES)
  447. .map(t -> new Object[] {t})
  448. .toArray(Object[][]::new);
  449. }
  450. private static RuleType randomSupportedRuleType() {
  451. return SUPPORTED_RULE_TYPES[new Random().nextInt(SUPPORTED_RULE_TYPES.length)];
  452. }
  453. private ComponentDto randomComponent(OrganizationDto organization) {
  454. ComponentDto project = dbTester.components().insertPublicProject(organization);
  455. ComponentDto module = dbTester.components().insertComponent(ComponentTesting.newModuleDto(project));
  456. ComponentDto dir = dbTester.components().insertComponent(ComponentTesting.newDirectory(project, "foo"));
  457. ComponentDto file = dbTester.components().insertComponent(ComponentTesting.newFileDto(project));
  458. ComponentDto[] components = new ComponentDto[] {project, module, dir, file};
  459. return components[random.nextInt(components.length)];
  460. }
  461. private IssueDto newIssue() {
  462. return new IssueDto()
  463. .setKee("ABCDE")
  464. .setComponentUuid(file.uuid())
  465. .setProjectUuid(project.uuid())
  466. .setRuleUuid(rule.getUuid())
  467. .setType(2)
  468. .setLine(500)
  469. .setGap(3.14)
  470. .setEffort(10L)
  471. .setResolution("FIXED")
  472. .setStatus("RESOLVED")
  473. .setSeverity("BLOCKER")
  474. .setAuthorLogin("morgan")
  475. .setAssigneeUuid("karadoc")
  476. .setIssueAttributes("JIRA=FOO-1234")
  477. .setChecksum("123456789")
  478. .setMessage("the message")
  479. .setIssueCreationTime(1_401_000_000_000L)
  480. .setIssueUpdateTime(1_402_000_000_000L)
  481. .setIssueCloseTime(1_403_000_000_000L)
  482. .setCreatedAt(1_400_000_000_000L)
  483. .setUpdatedAt(1_500_000_000_000L);
  484. }
  485. private static class RecorderResultHandler implements ResultHandler<IssueDto> {
  486. private final List<IssueDto> issues = new ArrayList<>();
  487. @Override
  488. public void handleResult(ResultContext<? extends IssueDto> resultContext) {
  489. issues.add(resultContext.getResultObject());
  490. }
  491. public List<IssueDto> getIssues() {
  492. return issues;
  493. }
  494. }
  495. }