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