Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

PersistIssuesStepTest.java 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2021 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 org.junit.After;
  25. import org.junit.Before;
  26. import org.junit.Rule;
  27. import org.junit.Test;
  28. import org.junit.rules.TemporaryFolder;
  29. import org.mockito.ArgumentCaptor;
  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.ce.task.projectanalysis.analysis.AnalysisMetadataHolderRule;
  34. import org.sonar.ce.task.projectanalysis.batch.BatchReportReaderRule;
  35. import org.sonar.ce.task.projectanalysis.issue.AdHocRuleCreator;
  36. import org.sonar.ce.task.projectanalysis.issue.ProtoIssueCache;
  37. import org.sonar.ce.task.projectanalysis.issue.RuleRepositoryImpl;
  38. import org.sonar.ce.task.projectanalysis.issue.UpdateConflictResolver;
  39. import org.sonar.ce.task.projectanalysis.util.cache.DiskCache;
  40. import org.sonar.ce.task.step.ComputationStep;
  41. import org.sonar.ce.task.step.TestComputationStepContext;
  42. import org.sonar.core.issue.DefaultIssue;
  43. import org.sonar.core.issue.DefaultIssueComment;
  44. import org.sonar.core.issue.FieldDiffs;
  45. import org.sonar.core.util.SequenceUuidFactory;
  46. import org.sonar.db.DbClient;
  47. import org.sonar.db.DbSession;
  48. import org.sonar.db.DbTester;
  49. import org.sonar.db.component.ComponentDto;
  50. import org.sonar.db.issue.IssueChangeDto;
  51. import org.sonar.db.issue.IssueDto;
  52. import org.sonar.db.issue.IssueMapper;
  53. import org.sonar.db.rule.RuleDefinitionDto;
  54. import org.sonar.db.rule.RuleTesting;
  55. import org.sonar.scanner.protocol.output.ScannerReport;
  56. import org.sonar.server.issue.IssueStorage;
  57. import static java.util.Collections.singletonList;
  58. import static org.assertj.core.api.Assertions.assertThat;
  59. import static org.assertj.core.data.MapEntry.entry;
  60. import static org.mockito.ArgumentMatchers.any;
  61. import static org.mockito.ArgumentMatchers.eq;
  62. import static org.mockito.Mockito.mock;
  63. import static org.mockito.Mockito.verify;
  64. import static org.mockito.Mockito.when;
  65. import static org.sonar.api.issue.Issue.RESOLUTION_FIXED;
  66. import static org.sonar.api.issue.Issue.STATUS_CLOSED;
  67. import static org.sonar.api.issue.Issue.STATUS_OPEN;
  68. import static org.sonar.api.rule.Severity.BLOCKER;
  69. import static org.sonar.db.component.ComponentTesting.newFileDto;
  70. public class PersistIssuesStepTest extends BaseStepTest {
  71. private static final long NOW = 1_400_000_000_000L;
  72. @Rule
  73. public TemporaryFolder temp = new TemporaryFolder();
  74. @Rule
  75. public DbTester db = DbTester.create(System2.INSTANCE);
  76. @Rule
  77. public BatchReportReaderRule reportReader = new BatchReportReaderRule();
  78. private System2 system2 = mock(System2.class);
  79. private DbSession session = db.getSession();
  80. private DbClient dbClient = db.getDbClient();
  81. private UpdateConflictResolver conflictResolver = mock(UpdateConflictResolver.class);
  82. private ProtoIssueCache protoIssueCache;
  83. private ComputationStep underTest;
  84. private AdHocRuleCreator adHocRuleCreator = mock(AdHocRuleCreator.class);
  85. @Override
  86. protected ComputationStep step() {
  87. return underTest;
  88. }
  89. @Before
  90. public void setup() throws Exception {
  91. protoIssueCache = new ProtoIssueCache(temp.newFile(), System2.INSTANCE);
  92. reportReader.setMetadata(ScannerReport.Metadata.getDefaultInstance());
  93. underTest = new PersistIssuesStep(dbClient, system2, conflictResolver, new RuleRepositoryImpl(adHocRuleCreator, dbClient), protoIssueCache,
  94. new IssueStorage(), new SequenceUuidFactory());
  95. }
  96. @After
  97. public void tearDown() {
  98. session.close();
  99. }
  100. @Test
  101. public void insert_copied_issue() {
  102. RuleDefinitionDto rule = RuleTesting.newRule(RuleKey.of("xoo", "S01"));
  103. db.rules().insert(rule);
  104. ComponentDto project = db.components().insertPrivateProject();
  105. ComponentDto file = db.components().insertComponent(newFileDto(project, null));
  106. when(system2.now()).thenReturn(NOW);
  107. protoIssueCache.newAppender().append(new DefaultIssue()
  108. .setKey("ISSUE")
  109. .setType(RuleType.CODE_SMELL)
  110. .setRuleKey(rule.getKey())
  111. .setComponentUuid(file.uuid())
  112. .setComponentKey(file.getKey())
  113. .setProjectUuid(project.uuid())
  114. .setProjectKey(project.getKey())
  115. .setSeverity(BLOCKER)
  116. .setStatus(STATUS_OPEN)
  117. .setTags(singletonList("test"))
  118. .setNew(false)
  119. .setCopied(true)
  120. .setType(RuleType.BUG)
  121. .setCreationDate(new Date(NOW))
  122. .setSelectedAt(NOW)
  123. .addComment(new DefaultIssueComment()
  124. .setKey("COMMENT")
  125. .setIssueKey("ISSUE")
  126. .setUserUuid("john_uuid")
  127. .setMarkdownText("Some text")
  128. .setCreatedAt(new Date(NOW))
  129. .setUpdatedAt(new Date(NOW))
  130. .setNew(true))
  131. .setCurrentChange(
  132. new FieldDiffs()
  133. .setIssueKey("ISSUE")
  134. .setUserUuid("john_uuid")
  135. .setDiff("technicalDebt", null, 1L)
  136. .setCreationDate(new Date(NOW))))
  137. .close();
  138. TestComputationStepContext context = new TestComputationStepContext();
  139. underTest.execute(context);
  140. IssueDto result = dbClient.issueDao().selectOrFailByKey(session, "ISSUE");
  141. assertThat(result.getKey()).isEqualTo("ISSUE");
  142. assertThat(result.getRuleKey()).isEqualTo(rule.getKey());
  143. assertThat(result.getComponentUuid()).isEqualTo(file.uuid());
  144. assertThat(result.getProjectUuid()).isEqualTo(project.uuid());
  145. assertThat(result.getSeverity()).isEqualTo(BLOCKER);
  146. assertThat(result.getStatus()).isEqualTo(STATUS_OPEN);
  147. assertThat(result.getType()).isEqualTo(RuleType.BUG.getDbConstant());
  148. assertThat(result.getTags()).containsExactlyInAnyOrder("test");
  149. List<IssueChangeDto> changes = dbClient.issueChangeDao().selectByIssueKeys(session, Arrays.asList("ISSUE"));
  150. assertThat(changes).extracting(IssueChangeDto::getChangeType).containsExactly(IssueChangeDto.TYPE_COMMENT, IssueChangeDto.TYPE_FIELD_CHANGE);
  151. assertThat(context.getStatistics().getAll()).contains(
  152. entry("inserts", "1"), entry("updates", "0"), entry("merged", "0"));
  153. }
  154. @Test
  155. public void insert_copied_issue_with_minimal_info() {
  156. RuleDefinitionDto rule = RuleTesting.newRule(RuleKey.of("xoo", "S01"));
  157. db.rules().insert(rule);
  158. ComponentDto project = db.components().insertPrivateProject();
  159. ComponentDto file = db.components().insertComponent(newFileDto(project, null));
  160. when(system2.now()).thenReturn(NOW);
  161. protoIssueCache.newAppender().append(new DefaultIssue()
  162. .setKey("ISSUE")
  163. .setType(RuleType.CODE_SMELL)
  164. .setRuleKey(rule.getKey())
  165. .setComponentUuid(file.uuid())
  166. .setComponentKey(file.getKey())
  167. .setProjectUuid(project.uuid())
  168. .setProjectKey(project.getKey())
  169. .setSeverity(BLOCKER)
  170. .setStatus(STATUS_OPEN)
  171. .setNew(false)
  172. .setCopied(true)
  173. .setType(RuleType.BUG)
  174. .setCreationDate(new Date(NOW))
  175. .setSelectedAt(NOW))
  176. .close();
  177. TestComputationStepContext context = new TestComputationStepContext();
  178. underTest.execute(context);
  179. IssueDto result = dbClient.issueDao().selectOrFailByKey(session, "ISSUE");
  180. assertThat(result.getKey()).isEqualTo("ISSUE");
  181. assertThat(result.getRuleKey()).isEqualTo(rule.getKey());
  182. assertThat(result.getComponentUuid()).isEqualTo(file.uuid());
  183. assertThat(result.getProjectUuid()).isEqualTo(project.uuid());
  184. assertThat(result.getSeverity()).isEqualTo(BLOCKER);
  185. assertThat(result.getStatus()).isEqualTo(STATUS_OPEN);
  186. assertThat(result.getType()).isEqualTo(RuleType.BUG.getDbConstant());
  187. assertThat(result.getTags()).isEmpty();
  188. assertThat(dbClient.issueChangeDao().selectByIssueKeys(session, Arrays.asList("ISSUE"))).isEmpty();
  189. assertThat(context.getStatistics().getAll()).contains(
  190. entry("inserts", "1"), entry("updates", "0"), entry("merged", "0"));
  191. }
  192. @Test
  193. public void insert_merged_issue() {
  194. RuleDefinitionDto rule = RuleTesting.newRule(RuleKey.of("xoo", "S01"));
  195. db.rules().insert(rule);
  196. ComponentDto project = db.components().insertPrivateProject();
  197. ComponentDto file = db.components().insertComponent(newFileDto(project, null));
  198. when(system2.now()).thenReturn(NOW);
  199. protoIssueCache.newAppender().append(new DefaultIssue()
  200. .setKey("ISSUE")
  201. .setType(RuleType.CODE_SMELL)
  202. .setRuleKey(rule.getKey())
  203. .setComponentUuid(file.uuid())
  204. .setComponentKey(file.getKey())
  205. .setProjectUuid(project.uuid())
  206. .setProjectKey(project.getKey())
  207. .setSeverity(BLOCKER)
  208. .setStatus(STATUS_OPEN)
  209. .setNew(true)
  210. .setCopied(true)
  211. .setType(RuleType.BUG)
  212. .setCreationDate(new Date(NOW))
  213. .setSelectedAt(NOW)
  214. .addComment(new DefaultIssueComment()
  215. .setKey("COMMENT")
  216. .setIssueKey("ISSUE")
  217. .setUserUuid("john_uuid")
  218. .setMarkdownText("Some text")
  219. .setUpdatedAt(new Date(NOW))
  220. .setCreatedAt(new Date(NOW))
  221. .setNew(true))
  222. .setCurrentChange(new FieldDiffs()
  223. .setIssueKey("ISSUE")
  224. .setUserUuid("john_uuid")
  225. .setDiff("technicalDebt", null, 1L)
  226. .setCreationDate(new Date(NOW))))
  227. .close();
  228. TestComputationStepContext context = new TestComputationStepContext();
  229. underTest.execute(context);
  230. IssueDto result = dbClient.issueDao().selectOrFailByKey(session, "ISSUE");
  231. assertThat(result.getKey()).isEqualTo("ISSUE");
  232. assertThat(result.getRuleKey()).isEqualTo(rule.getKey());
  233. assertThat(result.getComponentUuid()).isEqualTo(file.uuid());
  234. assertThat(result.getProjectUuid()).isEqualTo(project.uuid());
  235. assertThat(result.getSeverity()).isEqualTo(BLOCKER);
  236. assertThat(result.getStatus()).isEqualTo(STATUS_OPEN);
  237. assertThat(result.getType()).isEqualTo(RuleType.BUG.getDbConstant());
  238. List<IssueChangeDto> changes = dbClient.issueChangeDao().selectByIssueKeys(session, Arrays.asList("ISSUE"));
  239. assertThat(changes).extracting(IssueChangeDto::getChangeType).containsExactly(IssueChangeDto.TYPE_COMMENT, IssueChangeDto.TYPE_FIELD_CHANGE);
  240. assertThat(context.getStatistics().getAll()).contains(
  241. entry("inserts", "1"), entry("updates", "0"), entry("merged", "0"));
  242. }
  243. @Test
  244. public void update_conflicting_issue() {
  245. RuleDefinitionDto rule = RuleTesting.newRule(RuleKey.of("xoo", "S01"));
  246. db.rules().insert(rule);
  247. ComponentDto project = db.components().insertPrivateProject();
  248. ComponentDto file = db.components().insertComponent(newFileDto(project, null));
  249. IssueDto issue = db.issues().insert(rule, project, file,
  250. i -> i.setStatus(STATUS_OPEN)
  251. .setResolution(null)
  252. .setCreatedAt(NOW - 1_000_000_000L)
  253. // simulate the issue has been updated after the analysis ran
  254. .setUpdatedAt(NOW + 1_000_000_000L));
  255. issue = dbClient.issueDao().selectByKey(db.getSession(), issue.getKey()).get();
  256. DiskCache.CacheAppender issueCacheAppender = protoIssueCache.newAppender();
  257. when(system2.now()).thenReturn(NOW);
  258. DefaultIssue defaultIssue = issue.toDefaultIssue()
  259. .setStatus(STATUS_CLOSED)
  260. .setResolution(RESOLUTION_FIXED)
  261. .setSelectedAt(NOW)
  262. .setNew(false)
  263. .setChanged(true);
  264. issueCacheAppender.append(defaultIssue).close();
  265. TestComputationStepContext context = new TestComputationStepContext();
  266. underTest.execute(context);
  267. ArgumentCaptor<IssueDto> issueDtoCaptor = ArgumentCaptor.forClass(IssueDto.class);
  268. verify(conflictResolver).resolve(eq(defaultIssue), issueDtoCaptor.capture(), any(IssueMapper.class));
  269. assertThat(issueDtoCaptor.getValue().getKey()).isEqualTo(issue.getKey());
  270. assertThat(context.getStatistics().getAll()).contains(
  271. entry("inserts", "0"), entry("updates", "1"), entry("merged", "1"));
  272. }
  273. @Test
  274. public void insert_new_issue() {
  275. RuleDefinitionDto rule = RuleTesting.newRule(RuleKey.of("xoo", "S01"));
  276. db.rules().insert(rule);
  277. ComponentDto project = db.components().insertPrivateProject();
  278. ComponentDto file = db.components().insertComponent(newFileDto(project, null));
  279. session.commit();
  280. protoIssueCache.newAppender().append(new DefaultIssue()
  281. .setKey("ISSUE")
  282. .setType(RuleType.CODE_SMELL)
  283. .setRuleKey(rule.getKey())
  284. .setComponentUuid(file.uuid())
  285. .setComponentKey(file.getKey())
  286. .setProjectUuid(project.uuid())
  287. .setProjectKey(project.getKey())
  288. .setSeverity(BLOCKER)
  289. .setStatus(STATUS_OPEN)
  290. .setCreationDate(new Date(NOW))
  291. .setNew(true)
  292. .setType(RuleType.BUG)).close();
  293. TestComputationStepContext context = new TestComputationStepContext();
  294. underTest.execute(context);
  295. IssueDto result = dbClient.issueDao().selectOrFailByKey(session, "ISSUE");
  296. assertThat(result.getKey()).isEqualTo("ISSUE");
  297. assertThat(result.getRuleKey()).isEqualTo(rule.getKey());
  298. assertThat(result.getComponentUuid()).isEqualTo(file.uuid());
  299. assertThat(result.getProjectUuid()).isEqualTo(project.uuid());
  300. assertThat(result.getSeverity()).isEqualTo(BLOCKER);
  301. assertThat(result.getStatus()).isEqualTo(STATUS_OPEN);
  302. assertThat(result.getType()).isEqualTo(RuleType.BUG.getDbConstant());
  303. assertThat(context.getStatistics().getAll()).contains(
  304. entry("inserts", "1"), entry("updates", "0"), entry("merged", "0"));
  305. }
  306. @Test
  307. public void close_issue() {
  308. ComponentDto project = db.components().insertPrivateProject();
  309. ComponentDto file = db.components().insertComponent(newFileDto(project));
  310. RuleDefinitionDto rule = db.rules().insert();
  311. IssueDto issue = db.issues().insert(rule, project, file,
  312. i -> i.setStatus(STATUS_OPEN)
  313. .setResolution(null)
  314. .setCreatedAt(NOW - 1_000_000_000L)
  315. .setUpdatedAt(NOW - 1_000_000_000L));
  316. DiskCache.CacheAppender issueCacheAppender = protoIssueCache.newAppender();
  317. issueCacheAppender.append(
  318. issue.toDefaultIssue()
  319. .setStatus(STATUS_CLOSED)
  320. .setResolution(RESOLUTION_FIXED)
  321. .setSelectedAt(NOW)
  322. .setNew(false)
  323. .setChanged(true))
  324. .close();
  325. TestComputationStepContext context = new TestComputationStepContext();
  326. underTest.execute(context);
  327. IssueDto issueReloaded = db.getDbClient().issueDao().selectByKey(db.getSession(), issue.getKey()).get();
  328. assertThat(issueReloaded.getStatus()).isEqualTo(STATUS_CLOSED);
  329. assertThat(issueReloaded.getResolution()).isEqualTo(RESOLUTION_FIXED);
  330. assertThat(context.getStatistics().getAll()).contains(
  331. entry("inserts", "0"), entry("updates", "1"), entry("merged", "0"));
  332. }
  333. @Test
  334. public void add_comment() {
  335. ComponentDto project = db.components().insertPrivateProject();
  336. ComponentDto file = db.components().insertComponent(newFileDto(project));
  337. RuleDefinitionDto rule = db.rules().insert();
  338. IssueDto issue = db.issues().insert(rule, project, file,
  339. i -> i.setStatus(STATUS_OPEN)
  340. .setResolution(null)
  341. .setCreatedAt(NOW - 1_000_000_000L)
  342. .setUpdatedAt(NOW - 1_000_000_000L));
  343. DiskCache.CacheAppender issueCacheAppender = protoIssueCache.newAppender();
  344. issueCacheAppender.append(
  345. issue.toDefaultIssue()
  346. .setStatus(STATUS_CLOSED)
  347. .setResolution(RESOLUTION_FIXED)
  348. .setSelectedAt(NOW)
  349. .setNew(false)
  350. .setChanged(true)
  351. .addComment(new DefaultIssueComment()
  352. .setKey("COMMENT")
  353. .setIssueKey(issue.getKey())
  354. .setUserUuid("john_uuid")
  355. .setMarkdownText("Some text")
  356. .setCreatedAt(new Date(NOW))
  357. .setUpdatedAt(new Date(NOW))
  358. .setNew(true)))
  359. .close();
  360. TestComputationStepContext context = new TestComputationStepContext();
  361. underTest.execute(context);
  362. IssueChangeDto issueChangeDto = db.getDbClient().issueChangeDao().selectByIssueKeys(db.getSession(), singletonList(issue.getKey())).get(0);
  363. assertThat(issueChangeDto)
  364. .extracting(IssueChangeDto::getChangeType, IssueChangeDto::getUserUuid, IssueChangeDto::getChangeData, IssueChangeDto::getIssueKey,
  365. IssueChangeDto::getIssueChangeCreationDate)
  366. .containsOnly(IssueChangeDto.TYPE_COMMENT, "john_uuid", "Some text", issue.getKey(), NOW);
  367. assertThat(context.getStatistics().getAll()).contains(
  368. entry("inserts", "0"), entry("updates", "1"), entry("merged", "0"));
  369. }
  370. @Test
  371. public void add_change() {
  372. ComponentDto project = db.components().insertPrivateProject();
  373. ComponentDto file = db.components().insertComponent(newFileDto(project));
  374. RuleDefinitionDto rule = db.rules().insert();
  375. IssueDto issue = db.issues().insert(rule, project, file,
  376. i -> i.setStatus(STATUS_OPEN)
  377. .setResolution(null)
  378. .setCreatedAt(NOW - 1_000_000_000L)
  379. .setUpdatedAt(NOW - 1_000_000_000L));
  380. DiskCache.CacheAppender issueCacheAppender = protoIssueCache.newAppender();
  381. issueCacheAppender.append(
  382. issue.toDefaultIssue()
  383. .setStatus(STATUS_CLOSED)
  384. .setResolution(RESOLUTION_FIXED)
  385. .setSelectedAt(NOW)
  386. .setNew(false)
  387. .setChanged(true)
  388. .setCurrentChange(new FieldDiffs()
  389. .setIssueKey("ISSUE")
  390. .setUserUuid("john_uuid")
  391. .setDiff("technicalDebt", null, 1L)
  392. .setCreationDate(new Date(NOW))))
  393. .close();
  394. TestComputationStepContext context = new TestComputationStepContext();
  395. underTest.execute(context);
  396. IssueChangeDto issueChangeDto = db.getDbClient().issueChangeDao().selectByIssueKeys(db.getSession(), singletonList(issue.getKey())).get(0);
  397. assertThat(issueChangeDto)
  398. .extracting(IssueChangeDto::getChangeType, IssueChangeDto::getUserUuid, IssueChangeDto::getChangeData, IssueChangeDto::getIssueKey,
  399. IssueChangeDto::getIssueChangeCreationDate)
  400. .containsOnly(IssueChangeDto.TYPE_FIELD_CHANGE, "john_uuid", "technicalDebt=1", issue.getKey(), NOW);
  401. assertThat(context.getStatistics().getAll()).contains(
  402. entry("inserts", "0"), entry("updates", "1"), entry("merged", "0"));
  403. }
  404. }