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

PersistIssuesStepIT.java 32KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765
  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.ce.task.projectanalysis.step;
  21. import java.util.Arrays;
  22. import java.util.Date;
  23. import java.util.List;
  24. import java.util.stream.IntStream;
  25. import org.assertj.core.groups.Tuple;
  26. import org.junit.After;
  27. import org.junit.Before;
  28. import org.junit.Rule;
  29. import org.junit.Test;
  30. import org.junit.rules.TemporaryFolder;
  31. import org.mockito.ArgumentCaptor;
  32. import org.sonar.api.issue.impact.Severity;
  33. import org.sonar.api.issue.impact.SoftwareQuality;
  34. import org.sonar.api.rule.RuleKey;
  35. import org.sonar.api.rules.RuleType;
  36. import org.sonar.api.utils.System2;
  37. import org.sonar.ce.task.projectanalysis.batch.BatchReportReaderRule;
  38. import org.sonar.ce.task.projectanalysis.issue.AdHocRuleCreator;
  39. import org.sonar.ce.task.projectanalysis.issue.ProtoIssueCache;
  40. import org.sonar.ce.task.projectanalysis.issue.RuleRepositoryImpl;
  41. import org.sonar.ce.task.projectanalysis.issue.UpdateConflictResolver;
  42. import org.sonar.ce.task.projectanalysis.period.Period;
  43. import org.sonar.ce.task.projectanalysis.period.PeriodHolderRule;
  44. import org.sonar.ce.task.projectanalysis.util.cache.DiskCache.CacheAppender;
  45. import org.sonar.ce.task.step.ComputationStep;
  46. import org.sonar.ce.task.step.TestComputationStepContext;
  47. import org.sonar.core.issue.DefaultIssue;
  48. import org.sonar.core.issue.DefaultIssueComment;
  49. import org.sonar.core.issue.FieldDiffs;
  50. import org.sonar.core.util.UuidFactoryImpl;
  51. import org.sonar.db.DbClient;
  52. import org.sonar.db.DbSession;
  53. import org.sonar.db.DbTester;
  54. import org.sonar.db.component.ComponentDto;
  55. import org.sonar.db.issue.AnticipatedTransitionDto;
  56. import org.sonar.db.issue.ImpactDto;
  57. import org.sonar.db.issue.IssueChangeDto;
  58. import org.sonar.db.issue.IssueDto;
  59. import org.sonar.db.newcodeperiod.NewCodePeriodType;
  60. import org.sonar.db.rule.RuleDto;
  61. import org.sonar.db.rule.RuleTesting;
  62. import org.sonar.scanner.protocol.output.ScannerReport;
  63. import org.sonar.server.issue.IssueStorage;
  64. import static java.util.Collections.singletonList;
  65. import static org.assertj.core.api.Assertions.assertThat;
  66. import static org.assertj.core.api.Assertions.tuple;
  67. import static org.assertj.core.data.MapEntry.entry;
  68. import static org.mockito.ArgumentMatchers.eq;
  69. import static org.mockito.Mockito.mock;
  70. import static org.mockito.Mockito.spy;
  71. import static org.mockito.Mockito.verify;
  72. import static org.mockito.Mockito.when;
  73. import static org.sonar.api.issue.Issue.RESOLUTION_FIXED;
  74. import static org.sonar.api.issue.Issue.STATUS_CLOSED;
  75. import static org.sonar.api.issue.Issue.STATUS_OPEN;
  76. import static org.sonar.api.rule.Severity.BLOCKER;
  77. import static org.sonar.db.component.ComponentTesting.newFileDto;
  78. import static org.sonar.db.issue.IssueTesting.newCodeReferenceIssue;
  79. public class PersistIssuesStepIT extends BaseStepTest {
  80. private static final long NOW = 1_400_000_000_000L;
  81. @Rule
  82. public TemporaryFolder temp = new TemporaryFolder();
  83. @Rule
  84. public DbTester db = DbTester.create(System2.INSTANCE);
  85. @Rule
  86. public BatchReportReaderRule reportReader = new BatchReportReaderRule();
  87. @Rule
  88. public PeriodHolderRule periodHolder = new PeriodHolderRule();
  89. private final System2 system2 = mock(System2.class);
  90. private final DbSession session = db.getSession();
  91. private final DbClient dbClient = db.getDbClient();
  92. private final UpdateConflictResolver conflictResolver = spy(new UpdateConflictResolver());
  93. private ProtoIssueCache protoIssueCache;
  94. private ComputationStep underTest;
  95. private final AdHocRuleCreator adHocRuleCreator = mock(AdHocRuleCreator.class);
  96. @Override
  97. protected ComputationStep step() {
  98. return underTest;
  99. }
  100. @Before
  101. public void setup() throws Exception {
  102. periodHolder.setPeriod(new Period(NewCodePeriodType.NUMBER_OF_DAYS.name(), "10", 1000L));
  103. protoIssueCache = new ProtoIssueCache(temp.newFile(), System2.INSTANCE);
  104. reportReader.setMetadata(ScannerReport.Metadata.getDefaultInstance());
  105. underTest = new PersistIssuesStep(dbClient, system2, conflictResolver, new RuleRepositoryImpl(adHocRuleCreator, dbClient), periodHolder,
  106. protoIssueCache, new IssueStorage(), UuidFactoryImpl.INSTANCE);
  107. }
  108. @After
  109. public void tearDown() {
  110. session.close();
  111. }
  112. @Test
  113. public void insert_copied_issue() {
  114. RuleDto rule = RuleTesting.newRule(RuleKey.of("xoo", "S01"));
  115. db.rules().insert(rule);
  116. ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent();
  117. ComponentDto file = db.components().insertComponent(newFileDto(project));
  118. when(system2.now()).thenReturn(NOW);
  119. String issueKey = "ISSUE-1";
  120. protoIssueCache.newAppender().append(new DefaultIssue()
  121. .setKey(issueKey)
  122. .setType(RuleType.CODE_SMELL)
  123. .setRuleKey(rule.getKey())
  124. .setComponentUuid(file.uuid())
  125. .setComponentKey(file.getKey())
  126. .setProjectUuid(project.uuid())
  127. .setProjectKey(project.getKey())
  128. .setSeverity(BLOCKER)
  129. .setStatus(STATUS_OPEN)
  130. .setTags(singletonList("test"))
  131. .setNew(false)
  132. .setCopied(true)
  133. .setType(RuleType.BUG)
  134. .setCreationDate(new Date(NOW))
  135. .setSelectedAt(NOW)
  136. .addComment(new DefaultIssueComment()
  137. .setKey("COMMENT")
  138. .setIssueKey(issueKey)
  139. .setUserUuid("john_uuid")
  140. .setMarkdownText("Some text")
  141. .setCreatedAt(new Date(NOW))
  142. .setUpdatedAt(new Date(NOW))
  143. .setNew(true))
  144. .setCurrentChange(
  145. new FieldDiffs()
  146. .setIssueKey(issueKey)
  147. .setUserUuid("john_uuid")
  148. .setDiff("technicalDebt", null, 1L)
  149. .setCreationDate(new Date(NOW)))
  150. .addImpact(SoftwareQuality.SECURITY, Severity.MEDIUM))
  151. .close();
  152. TestComputationStepContext context = new TestComputationStepContext();
  153. underTest.execute(context);
  154. IssueDto result = dbClient.issueDao().selectOrFailByKey(session, issueKey);
  155. assertThat(result.getKey()).isEqualTo(issueKey);
  156. assertThat(result.getRuleKey()).isEqualTo(rule.getKey());
  157. assertThat(result.getComponentUuid()).isEqualTo(file.uuid());
  158. assertThat(result.getProjectUuid()).isEqualTo(project.uuid());
  159. assertThat(result.getSeverity()).isEqualTo(BLOCKER);
  160. assertThat(result.getStatus()).isEqualTo(STATUS_OPEN);
  161. assertThat(result.getType()).isEqualTo(RuleType.BUG.getDbConstant());
  162. assertThat(result.getTags()).containsExactlyInAnyOrder("test");
  163. assertThat(result.isNewCodeReferenceIssue()).isFalse();
  164. assertThat(result.getImpacts())
  165. .extracting(ImpactDto::getSoftwareQuality, ImpactDto::getSeverity)
  166. .containsExactlyInAnyOrder(Tuple.tuple(SoftwareQuality.SECURITY, Severity.MEDIUM));
  167. List<IssueChangeDto> changes = dbClient.issueChangeDao().selectByIssueKeys(session, Arrays.asList(issueKey));
  168. assertThat(changes).extracting(IssueChangeDto::getChangeType).containsExactly(IssueChangeDto.TYPE_COMMENT, IssueChangeDto.TYPE_FIELD_CHANGE);
  169. assertThat(context.getStatistics().getAll()).contains(
  170. entry("inserts", "1"), entry("updates", "0"), entry("merged", "0"));
  171. }
  172. @Test
  173. public void insert_copied_issue_with_minimal_info() {
  174. periodHolder.setPeriod(new Period(NewCodePeriodType.REFERENCE_BRANCH.name(), "master", null));
  175. RuleDto rule = RuleTesting.newRule(RuleKey.of("xoo", "S01"));
  176. db.rules().insert(rule);
  177. ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent();
  178. ComponentDto file = db.components().insertComponent(newFileDto(project));
  179. when(system2.now()).thenReturn(NOW);
  180. String issueKey = "ISSUE-2";
  181. protoIssueCache.newAppender().append(new DefaultIssue()
  182. .setKey(issueKey)
  183. .setType(RuleType.CODE_SMELL)
  184. .setRuleKey(rule.getKey())
  185. .setComponentUuid(file.uuid())
  186. .setComponentKey(file.getKey())
  187. .setProjectUuid(project.uuid())
  188. .setProjectKey(project.getKey())
  189. .setSeverity(BLOCKER)
  190. .setStatus(STATUS_OPEN)
  191. .setNew(false)
  192. .setCopied(true)
  193. .setType(RuleType.BUG)
  194. .setCreationDate(new Date(NOW))
  195. .setSelectedAt(NOW)
  196. .addImpact(SoftwareQuality.SECURITY, Severity.MEDIUM))
  197. .close();
  198. TestComputationStepContext context = new TestComputationStepContext();
  199. underTest.execute(context);
  200. IssueDto result = dbClient.issueDao().selectOrFailByKey(session, issueKey);
  201. assertThat(result.getKey()).isEqualTo(issueKey);
  202. assertThat(result.getRuleKey()).isEqualTo(rule.getKey());
  203. assertThat(result.getComponentUuid()).isEqualTo(file.uuid());
  204. assertThat(result.getProjectUuid()).isEqualTo(project.uuid());
  205. assertThat(result.getSeverity()).isEqualTo(BLOCKER);
  206. assertThat(result.getStatus()).isEqualTo(STATUS_OPEN);
  207. assertThat(result.getType()).isEqualTo(RuleType.BUG.getDbConstant());
  208. assertThat(result.getTags()).isEmpty();
  209. assertThat(result.isNewCodeReferenceIssue()).isFalse();
  210. assertThat(result.getImpacts())
  211. .extracting(ImpactDto::getSoftwareQuality, ImpactDto::getSeverity)
  212. .containsExactlyInAnyOrder(Tuple.tuple(SoftwareQuality.SECURITY, Severity.MEDIUM));
  213. assertThat(dbClient.issueChangeDao().selectByIssueKeys(session, Arrays.asList(issueKey))).isEmpty();
  214. assertThat(context.getStatistics().getAll()).contains(
  215. entry("inserts", "1"), entry("updates", "0"), entry("merged", "0"));
  216. }
  217. @Test
  218. public void insert_merged_issue() {
  219. periodHolder.setPeriod(new Period(NewCodePeriodType.REFERENCE_BRANCH.name(), "master", null));
  220. RuleDto rule = RuleTesting.newRule(RuleKey.of("xoo", "S01"));
  221. db.rules().insert(rule);
  222. ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent();
  223. ComponentDto file = db.components().insertComponent(newFileDto(project));
  224. when(system2.now()).thenReturn(NOW);
  225. String issueKey = "ISSUE-3";
  226. protoIssueCache.newAppender().append(new DefaultIssue()
  227. .setKey(issueKey)
  228. .setType(RuleType.CODE_SMELL)
  229. .setRuleKey(rule.getKey())
  230. .setComponentUuid(file.uuid())
  231. .setComponentKey(file.getKey())
  232. .setProjectUuid(project.uuid())
  233. .setProjectKey(project.getKey())
  234. .setSeverity(BLOCKER)
  235. .setStatus(STATUS_OPEN)
  236. .setNew(true)
  237. .setIsOnChangedLine(true)
  238. .setCopied(true)
  239. .setType(RuleType.BUG)
  240. .setCreationDate(new Date(NOW))
  241. .setSelectedAt(NOW)
  242. .addComment(new DefaultIssueComment()
  243. .setKey("COMMENT")
  244. .setIssueKey(issueKey)
  245. .setUserUuid("john_uuid")
  246. .setMarkdownText("Some text")
  247. .setUpdatedAt(new Date(NOW))
  248. .setCreatedAt(new Date(NOW))
  249. .setNew(true))
  250. .setCurrentChange(new FieldDiffs()
  251. .setIssueKey(issueKey)
  252. .setUserUuid("john_uuid")
  253. .setDiff("technicalDebt", null, 1L)
  254. .setCreationDate(new Date(NOW)))
  255. .addImpact(SoftwareQuality.SECURITY, Severity.MEDIUM))
  256. .close();
  257. TestComputationStepContext context = new TestComputationStepContext();
  258. underTest.execute(context);
  259. IssueDto result = dbClient.issueDao().selectOrFailByKey(session, issueKey);
  260. assertThat(result.getKey()).isEqualTo(issueKey);
  261. assertThat(result.getRuleKey()).isEqualTo(rule.getKey());
  262. assertThat(result.getComponentUuid()).isEqualTo(file.uuid());
  263. assertThat(result.getProjectUuid()).isEqualTo(project.uuid());
  264. assertThat(result.getSeverity()).isEqualTo(BLOCKER);
  265. assertThat(result.getStatus()).isEqualTo(STATUS_OPEN);
  266. assertThat(result.getType()).isEqualTo(RuleType.BUG.getDbConstant());
  267. assertThat(result.isNewCodeReferenceIssue()).isTrue();
  268. assertThat(result.getImpacts())
  269. .extracting(ImpactDto::getSoftwareQuality, ImpactDto::getSeverity)
  270. .containsExactlyInAnyOrder(Tuple.tuple(SoftwareQuality.SECURITY, Severity.MEDIUM));
  271. List<IssueChangeDto> changes = dbClient.issueChangeDao().selectByIssueKeys(session, Arrays.asList(issueKey));
  272. assertThat(changes).extracting(IssueChangeDto::getChangeType).containsExactly(IssueChangeDto.TYPE_COMMENT, IssueChangeDto.TYPE_FIELD_CHANGE);
  273. assertThat(context.getStatistics().getAll()).contains(
  274. entry("inserts", "1"), entry("updates", "0"), entry("merged", "0"));
  275. }
  276. @Test
  277. public void update_conflicting_issue() {
  278. RuleDto rule = RuleTesting.newRule(RuleKey.of("xoo", "S01"));
  279. db.rules().insert(rule);
  280. ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent();
  281. ComponentDto file = db.components().insertComponent(newFileDto(project));
  282. IssueDto issue = db.issues().insert(rule, project, file,
  283. i -> i.setStatus(STATUS_OPEN)
  284. .setResolution(null)
  285. .setCreatedAt(NOW - 1_000_000_000L)
  286. // simulate the issue has been updated after the analysis ran
  287. .setUpdatedAt(NOW + 1_000_000_000L));
  288. issue = dbClient.issueDao().selectByKey(db.getSession(), issue.getKey()).get();
  289. CacheAppender issueCacheAppender = protoIssueCache.newAppender();
  290. when(system2.now()).thenReturn(NOW);
  291. DefaultIssue defaultIssue = issue.toDefaultIssue()
  292. .setStatus(STATUS_CLOSED)
  293. .setResolution(RESOLUTION_FIXED)
  294. .setSelectedAt(NOW)
  295. .setNew(false)
  296. .setChanged(true);
  297. issueCacheAppender.append(defaultIssue).close();
  298. TestComputationStepContext context = new TestComputationStepContext();
  299. underTest.execute(context);
  300. ArgumentCaptor<IssueDto> issueDtoCaptor = ArgumentCaptor.forClass(IssueDto.class);
  301. verify(conflictResolver).resolve(eq(defaultIssue), issueDtoCaptor.capture());
  302. assertThat(issueDtoCaptor.getValue().getKey()).isEqualTo(issue.getKey());
  303. assertThat(context.getStatistics().getAll()).contains(
  304. entry("inserts", "0"), entry("updates", "1"), entry("merged", "1"));
  305. }
  306. @Test
  307. public void insert_new_issue() {
  308. periodHolder.setPeriod(new Period(NewCodePeriodType.REFERENCE_BRANCH.name(), "master", null));
  309. RuleDto rule = RuleTesting.newRule(RuleKey.of("xoo", "S01"));
  310. db.rules().insert(rule);
  311. ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent();
  312. ComponentDto file = db.components().insertComponent(newFileDto(project));
  313. session.commit();
  314. String issueKey = "ISSUE-4";
  315. protoIssueCache.newAppender().append(new DefaultIssue()
  316. .setKey(issueKey)
  317. .setType(RuleType.CODE_SMELL)
  318. .setRuleKey(rule.getKey())
  319. .setComponentUuid(file.uuid())
  320. .setComponentKey(file.getKey())
  321. .setProjectUuid(project.uuid())
  322. .setProjectKey(project.getKey())
  323. .setSeverity(BLOCKER)
  324. .setStatus(STATUS_OPEN)
  325. .setCreationDate(new Date(NOW))
  326. .setNew(true)
  327. .setIsOnChangedLine(true)
  328. .addImpact(SoftwareQuality.SECURITY, Severity.MEDIUM)
  329. .setType(RuleType.BUG)).close();
  330. TestComputationStepContext context = new TestComputationStepContext();
  331. underTest.execute(context);
  332. IssueDto result = dbClient.issueDao().selectOrFailByKey(session, issueKey);
  333. assertThat(result.getKey()).isEqualTo(issueKey);
  334. assertThat(result.getRuleKey()).isEqualTo(rule.getKey());
  335. assertThat(result.getComponentUuid()).isEqualTo(file.uuid());
  336. assertThat(result.getProjectUuid()).isEqualTo(project.uuid());
  337. assertThat(result.getSeverity()).isEqualTo(BLOCKER);
  338. assertThat(result.getStatus()).isEqualTo(STATUS_OPEN);
  339. assertThat(result.getType()).isEqualTo(RuleType.BUG.getDbConstant());
  340. assertThat(result.getImpacts()).extracting(ImpactDto::getSoftwareQuality, ImpactDto::getSeverity)
  341. .containsExactly(tuple(SoftwareQuality.SECURITY, Severity.MEDIUM));
  342. assertThat(context.getStatistics().getAll()).contains(
  343. entry("inserts", "1"), entry("updates", "0"), entry("merged", "0"));
  344. assertThat(result.isNewCodeReferenceIssue()).isTrue();
  345. }
  346. @Test
  347. public void execute_shouldInsertNewIssuesInBatchesWhenGreaterThan500() {
  348. periodHolder.setPeriod(new Period(NewCodePeriodType.REFERENCE_BRANCH.name(), "master", null));
  349. RuleDto rule = RuleTesting.newRule(RuleKey.of("xoo", "S01"));
  350. db.rules().insert(rule);
  351. ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent();
  352. ComponentDto file = db.components().insertComponent(newFileDto(project));
  353. session.commit();
  354. String issueKey = "ISSUE-";
  355. CacheAppender<DefaultIssue> appender = protoIssueCache.newAppender();
  356. IntStream.range(1, 501).forEach(i -> appender.append(new DefaultIssue()
  357. .setKey(issueKey + i)
  358. .setType(RuleType.CODE_SMELL)
  359. .setRuleKey(rule.getKey())
  360. .setComponentUuid(file.uuid())
  361. .setComponentKey(file.getKey())
  362. .setProjectUuid(project.uuid())
  363. .setProjectKey(project.getKey())
  364. .setSeverity(BLOCKER)
  365. .setStatus(STATUS_OPEN)
  366. .setCreationDate(new Date(NOW))
  367. .setNew(true)
  368. .setIsOnChangedLine(true)
  369. .addImpact(SoftwareQuality.SECURITY, Severity.MEDIUM)
  370. .setType(RuleType.BUG)));
  371. appender.close();
  372. TestComputationStepContext context = new TestComputationStepContext();
  373. underTest.execute(context);
  374. assertThat(context.getStatistics().getAll()).contains(
  375. entry("inserts", "500"), entry("updates", "0"), entry("merged", "0"));
  376. }
  377. @Test
  378. public void execute_shouldUpdateIssuesInBatchesWhenGreaterThan500() {
  379. ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent();
  380. ComponentDto file = db.components().insertComponent(newFileDto(project));
  381. RuleDto rule = db.rules().insert();
  382. List<IssueDto> issues = IntStream.range(1, 501)
  383. .mapToObj(value -> db.issues().insert(rule, project, file,
  384. i -> i.setStatus(STATUS_OPEN)
  385. .setResolution(null)
  386. .setCreatedAt(NOW - 1_000_000_000L)
  387. .setUpdatedAt(NOW - 1_000_000_000L)))
  388. .toList();
  389. CacheAppender issueCacheAppender = protoIssueCache.newAppender();
  390. issues.forEach(issue -> issueCacheAppender.append(issue.toDefaultIssue()
  391. .setStatus(STATUS_CLOSED)
  392. .setResolution(RESOLUTION_FIXED)
  393. .setSelectedAt(NOW)
  394. .addImpact(SoftwareQuality.SECURITY, Severity.MEDIUM)
  395. .setNew(false)
  396. .setChanged(true)));
  397. issueCacheAppender.close();
  398. TestComputationStepContext context = new TestComputationStepContext();
  399. underTest.execute(context);
  400. assertThat(context.getStatistics().getAll()).contains(
  401. entry("inserts", "0"), entry("updates", "500"), entry("merged", "0"));
  402. }
  403. @Test
  404. public void close_issue() {
  405. ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent();
  406. ComponentDto file = db.components().insertComponent(newFileDto(project));
  407. RuleDto rule = db.rules().insert();
  408. IssueDto issue = db.issues().insert(rule, project, file,
  409. i -> i.setStatus(STATUS_OPEN)
  410. .setResolution(null)
  411. .setCreatedAt(NOW - 1_000_000_000L)
  412. .setUpdatedAt(NOW - 1_000_000_000L));
  413. CacheAppender issueCacheAppender = protoIssueCache.newAppender();
  414. issueCacheAppender.append(
  415. issue.toDefaultIssue()
  416. .setStatus(STATUS_CLOSED)
  417. .setResolution(RESOLUTION_FIXED)
  418. .setSelectedAt(NOW)
  419. .setNew(false)
  420. .setChanged(true))
  421. .close();
  422. TestComputationStepContext context = new TestComputationStepContext();
  423. underTest.execute(context);
  424. IssueDto issueReloaded = db.getDbClient().issueDao().selectByKey(db.getSession(), issue.getKey()).get();
  425. assertThat(issueReloaded.getStatus()).isEqualTo(STATUS_CLOSED);
  426. assertThat(issueReloaded.getResolution()).isEqualTo(RESOLUTION_FIXED);
  427. assertThat(context.getStatistics().getAll()).contains(
  428. entry("inserts", "0"), entry("updates", "1"), entry("merged", "0"));
  429. }
  430. @Test
  431. public void handle_no_longer_new_issue() {
  432. periodHolder.setPeriod(new Period(NewCodePeriodType.REFERENCE_BRANCH.name(), "master", null));
  433. RuleDto rule = RuleTesting.newRule(RuleKey.of("xoo", "S01"));
  434. db.rules().insert(rule);
  435. ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent();
  436. ComponentDto file = db.components().insertComponent(newFileDto(project));
  437. when(system2.now()).thenReturn(NOW);
  438. String issueKey = "ISSUE-5";
  439. DefaultIssue defaultIssue = new DefaultIssue()
  440. .setKey(issueKey)
  441. .setType(RuleType.CODE_SMELL)
  442. .setRuleKey(rule.getKey())
  443. .setComponentUuid(file.uuid())
  444. .setComponentKey(file.getKey())
  445. .setProjectUuid(project.uuid())
  446. .setProjectKey(project.getKey())
  447. .setSeverity(BLOCKER)
  448. .setStatus(STATUS_OPEN)
  449. .setNew(true)
  450. .setIsOnChangedLine(true)
  451. .setIsNewCodeReferenceIssue(true)
  452. .setIsNoLongerNewCodeReferenceIssue(false)
  453. .setCopied(false)
  454. .setType(RuleType.BUG)
  455. .setCreationDate(new Date(NOW))
  456. .setSelectedAt(NOW);
  457. IssueDto issueDto = IssueDto.toDtoForComputationInsert(defaultIssue, rule.getUuid(), NOW);
  458. dbClient.issueDao().insert(session, issueDto);
  459. dbClient.issueDao().insertAsNewCodeOnReferenceBranch(session, newCodeReferenceIssue(issueDto));
  460. session.commit();
  461. IssueDto result = dbClient.issueDao().selectOrFailByKey(session, issueKey);
  462. assertThat(result.isNewCodeReferenceIssue()).isTrue();
  463. protoIssueCache.newAppender().append(defaultIssue.setNew(false)
  464. .setIsOnChangedLine(false)
  465. .setIsNewCodeReferenceIssue(false)
  466. .setIsNoLongerNewCodeReferenceIssue(true))
  467. .close();
  468. TestComputationStepContext context = new TestComputationStepContext();
  469. underTest.execute(context);
  470. assertThat(context.getStatistics().getAll()).contains(
  471. entry("inserts", "0"), entry("updates", "1"), entry("merged", "0"));
  472. result = dbClient.issueDao().selectOrFailByKey(session, issueKey);
  473. assertThat(result.isNewCodeReferenceIssue()).isFalse();
  474. }
  475. @Test
  476. public void handle_existing_new_code_issue_migration() {
  477. periodHolder.setPeriod(new Period(NewCodePeriodType.REFERENCE_BRANCH.name(), "master", null));
  478. RuleDto rule = RuleTesting.newRule(RuleKey.of("xoo", "S01"));
  479. db.rules().insert(rule);
  480. ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent();
  481. ComponentDto file = db.components().insertComponent(newFileDto(project));
  482. when(system2.now()).thenReturn(NOW);
  483. String issueKey = "ISSUE-6";
  484. DefaultIssue defaultIssue = new DefaultIssue()
  485. .setKey(issueKey)
  486. .setType(RuleType.CODE_SMELL)
  487. .setRuleKey(rule.getKey())
  488. .setComponentUuid(file.uuid())
  489. .setComponentKey(file.getKey())
  490. .setProjectUuid(project.uuid())
  491. .setProjectKey(project.getKey())
  492. .setSeverity(BLOCKER)
  493. .setStatus(STATUS_OPEN)
  494. .setNew(true)
  495. .setCopied(false)
  496. .setType(RuleType.BUG)
  497. .setCreationDate(new Date(NOW))
  498. .setSelectedAt(NOW);
  499. IssueDto issueDto = IssueDto.toDtoForComputationInsert(defaultIssue, rule.getUuid(), NOW);
  500. dbClient.issueDao().insert(session, issueDto);
  501. session.commit();
  502. IssueDto result = dbClient.issueDao().selectOrFailByKey(session, issueKey);
  503. assertThat(result.isNewCodeReferenceIssue()).isFalse();
  504. protoIssueCache.newAppender().append(defaultIssue.setNew(false)
  505. .setIsOnChangedLine(true)
  506. .setIsNewCodeReferenceIssue(false)
  507. .setIsNoLongerNewCodeReferenceIssue(false))
  508. .close();
  509. TestComputationStepContext context = new TestComputationStepContext();
  510. underTest.execute(context);
  511. assertThat(context.getStatistics().getAll()).contains(
  512. entry("inserts", "0"), entry("updates", "1"), entry("merged", "0"));
  513. result = dbClient.issueDao().selectOrFailByKey(session, issueKey);
  514. assertThat(result.isNewCodeReferenceIssue()).isTrue();
  515. }
  516. @Test
  517. public void handle_existing_without_need_for_new_code_issue_migration() {
  518. periodHolder.setPeriod(new Period(NewCodePeriodType.REFERENCE_BRANCH.name(), "master", null));
  519. RuleDto rule = RuleTesting.newRule(RuleKey.of("xoo", "S01"));
  520. db.rules().insert(rule);
  521. ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent();
  522. ComponentDto file = db.components().insertComponent(newFileDto(project));
  523. when(system2.now()).thenReturn(NOW);
  524. String issueKey = "ISSUE-7";
  525. DefaultIssue defaultIssue = new DefaultIssue()
  526. .setKey(issueKey)
  527. .setType(RuleType.CODE_SMELL)
  528. .setRuleKey(rule.getKey())
  529. .setComponentUuid(file.uuid())
  530. .setComponentKey(file.getKey())
  531. .setProjectUuid(project.uuid())
  532. .setProjectKey(project.getKey())
  533. .setSeverity(BLOCKER)
  534. .setStatus(STATUS_OPEN)
  535. .setNew(true)
  536. .setIsOnChangedLine(true)
  537. .setIsNewCodeReferenceIssue(true)
  538. .setIsNoLongerNewCodeReferenceIssue(false)
  539. .setCopied(false)
  540. .setType(RuleType.BUG)
  541. .setCreationDate(new Date(NOW))
  542. .setSelectedAt(NOW);
  543. IssueDto issueDto = IssueDto.toDtoForComputationInsert(defaultIssue, rule.getUuid(), NOW);
  544. dbClient.issueDao().insert(session, issueDto);
  545. dbClient.issueDao().insertAsNewCodeOnReferenceBranch(session, newCodeReferenceIssue(issueDto));
  546. session.commit();
  547. IssueDto result = dbClient.issueDao().selectOrFailByKey(session, issueKey);
  548. assertThat(result.isNewCodeReferenceIssue()).isTrue();
  549. protoIssueCache.newAppender().append(defaultIssue.setNew(false)
  550. .setIsOnChangedLine(false)
  551. .setIsNewCodeReferenceIssue(true)
  552. .setIsOnChangedLine(true)
  553. .setIsNoLongerNewCodeReferenceIssue(false))
  554. .close();
  555. TestComputationStepContext context = new TestComputationStepContext();
  556. underTest.execute(context);
  557. assertThat(context.getStatistics().getAll()).contains(
  558. entry("inserts", "0"), entry("updates", "0"), entry("merged", "0"));
  559. result = dbClient.issueDao().selectOrFailByKey(session, issueKey);
  560. assertThat(result.isNewCodeReferenceIssue()).isTrue();
  561. }
  562. @Test
  563. public void add_comment() {
  564. ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent();
  565. ComponentDto file = db.components().insertComponent(newFileDto(project));
  566. RuleDto rule = db.rules().insert();
  567. IssueDto issue = db.issues().insert(rule, project, file,
  568. i -> i.setStatus(STATUS_OPEN)
  569. .setResolution(null)
  570. .setCreatedAt(NOW - 1_000_000_000L)
  571. .setUpdatedAt(NOW - 1_000_000_000L));
  572. CacheAppender issueCacheAppender = protoIssueCache.newAppender();
  573. issueCacheAppender.append(
  574. issue.toDefaultIssue()
  575. .setStatus(STATUS_CLOSED)
  576. .setResolution(RESOLUTION_FIXED)
  577. .setSelectedAt(NOW)
  578. .setNew(false)
  579. .setChanged(true)
  580. .addComment(new DefaultIssueComment()
  581. .setKey("COMMENT")
  582. .setIssueKey(issue.getKey())
  583. .setUserUuid("john_uuid")
  584. .setMarkdownText("Some text")
  585. .setCreatedAt(new Date(NOW))
  586. .setUpdatedAt(new Date(NOW))
  587. .setNew(true)))
  588. .close();
  589. TestComputationStepContext context = new TestComputationStepContext();
  590. underTest.execute(context);
  591. IssueChangeDto issueChangeDto = db.getDbClient().issueChangeDao().selectByIssueKeys(db.getSession(), singletonList(issue.getKey())).get(0);
  592. assertThat(issueChangeDto)
  593. .extracting(IssueChangeDto::getChangeType, IssueChangeDto::getUserUuid, IssueChangeDto::getChangeData, IssueChangeDto::getIssueKey,
  594. IssueChangeDto::getIssueChangeCreationDate)
  595. .containsOnly(IssueChangeDto.TYPE_COMMENT, "john_uuid", "Some text", issue.getKey(), NOW);
  596. assertThat(context.getStatistics().getAll()).contains(
  597. entry("inserts", "0"), entry("updates", "1"), entry("merged", "0"));
  598. }
  599. @Test
  600. public void add_change() {
  601. ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent();
  602. ComponentDto file = db.components().insertComponent(newFileDto(project));
  603. RuleDto rule = db.rules().insert();
  604. IssueDto issue = db.issues().insert(rule, project, file,
  605. i -> i.setStatus(STATUS_OPEN)
  606. .setResolution(null)
  607. .setCreatedAt(NOW - 1_000_000_000L)
  608. .setUpdatedAt(NOW - 1_000_000_000L));
  609. CacheAppender issueCacheAppender = protoIssueCache.newAppender();
  610. issueCacheAppender.append(
  611. issue.toDefaultIssue()
  612. .setStatus(STATUS_CLOSED)
  613. .setResolution(RESOLUTION_FIXED)
  614. .setSelectedAt(NOW)
  615. .setNew(false)
  616. .setChanged(true)
  617. .setIsOnChangedLine(false)
  618. .setIsNewCodeReferenceIssue(false)
  619. .setCurrentChange(new FieldDiffs()
  620. .setIssueKey("ISSUE")
  621. .setUserUuid("john_uuid")
  622. .setDiff("technicalDebt", null, 1L)
  623. .setCreationDate(new Date(NOW))))
  624. .close();
  625. TestComputationStepContext context = new TestComputationStepContext();
  626. underTest.execute(context);
  627. IssueChangeDto issueChangeDto = db.getDbClient().issueChangeDao().selectByIssueKeys(db.getSession(), singletonList(issue.getKey())).get(0);
  628. assertThat(issueChangeDto)
  629. .extracting(IssueChangeDto::getChangeType, IssueChangeDto::getUserUuid, IssueChangeDto::getChangeData, IssueChangeDto::getIssueKey,
  630. IssueChangeDto::getIssueChangeCreationDate)
  631. .containsOnly(IssueChangeDto.TYPE_FIELD_CHANGE, "john_uuid", "technicalDebt=1", issue.getKey(), NOW);
  632. assertThat(context.getStatistics().getAll()).contains(
  633. entry("inserts", "0"), entry("updates", "1"), entry("merged", "0"));
  634. }
  635. @Test
  636. public void when_anticipatedTransitionIsPresent_ItShouldBeDeleted() {
  637. periodHolder.setPeriod(new Period(NewCodePeriodType.REFERENCE_BRANCH.name(), "master", null));
  638. RuleDto rule = RuleTesting.newRule(RuleKey.of("xoo", "S01"));
  639. db.rules().insert(rule);
  640. ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent();
  641. ComponentDto file = db.components().insertComponent(newFileDto(project));
  642. session.commit();
  643. String issueKey = "ISSUE-4";
  644. DefaultIssue newIssue = new DefaultIssue()
  645. .setKey(issueKey)
  646. .setType(RuleType.CODE_SMELL)
  647. .setRuleKey(rule.getKey())
  648. .setComponentUuid(file.uuid())
  649. .setComponentKey(file.getKey())
  650. .setProjectUuid(project.uuid())
  651. .setProjectKey(project.getKey())
  652. .setSeverity(BLOCKER)
  653. .setStatus(STATUS_OPEN)
  654. .setCreationDate(new Date(NOW))
  655. .setNew(true)
  656. .setIsOnChangedLine(true)
  657. .setType(RuleType.BUG);
  658. AnticipatedTransitionDto atDto = db.anticipatedTransitions().createForIssue(newIssue, "test_uuid", file.name());
  659. newIssue.setAnticipatedTransitionUuid(atDto.getUuid());
  660. var defaultIssueCacheAppender = protoIssueCache.newAppender();
  661. defaultIssueCacheAppender.append(newIssue).close();
  662. TestComputationStepContext context = new TestComputationStepContext();
  663. underTest.execute(context);
  664. IssueDto result = dbClient.issueDao().selectOrFailByKey(session, issueKey);
  665. assertThat(result.getKey()).isEqualTo(issueKey);
  666. assertThat(result.getRuleKey()).isEqualTo(rule.getKey());
  667. assertThat(result.getComponentUuid()).isEqualTo(file.uuid());
  668. assertThat(result.getProjectUuid()).isEqualTo(project.uuid());
  669. assertThat(result.getSeverity()).isEqualTo(BLOCKER);
  670. assertThat(result.getStatus()).isEqualTo(STATUS_OPEN);
  671. assertThat(result.getType()).isEqualTo(RuleType.BUG.getDbConstant());
  672. assertThat(context.getStatistics().getAll()).contains(
  673. entry("inserts", "1"), entry("updates", "0"), entry("merged", "0"));
  674. assertThat(result.isNewCodeReferenceIssue()).isTrue();
  675. assertThat(db.anticipatedTransitions().selectByProjectUuid(project.uuid())).isEmpty();
  676. }
  677. }