3 * Copyright (C) 2009-2017 SonarSource SA
4 * mailto:info AT sonarsource DOT com
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.
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.
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.
20 package org.sonar.server.computation.task.projectanalysis.step;
22 import static com.google.common.collect.Lists.newArrayList;
23 import static org.assertj.core.api.Assertions.assertThat;
24 import static org.mockito.Mockito.mock;
25 import static org.mockito.Mockito.when;
27 import java.util.Arrays;
29 import org.junit.Before;
30 import org.junit.Rule;
31 import org.junit.Test;
32 import org.junit.rules.ExpectedException;
33 import org.sonar.api.utils.System2;
34 import org.sonar.db.DbClient;
35 import org.sonar.db.DbSession;
36 import org.sonar.db.DbTester;
37 import org.sonar.db.protobuf.DbFileSources;
38 import org.sonar.db.source.FileSourceDto;
39 import org.sonar.db.source.FileSourceDto.Type;
40 import org.sonar.scanner.protocol.output.ScannerReport;
41 import org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType;
42 import org.sonar.scanner.protocol.output.ScannerReport.SyntaxHighlightingRule.HighlightingType;
43 import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolderRule;
44 import org.sonar.server.computation.task.projectanalysis.batch.BatchReportReaderRule;
45 import org.sonar.server.computation.task.projectanalysis.component.Component;
46 import org.sonar.server.computation.task.projectanalysis.component.Component.Status;
47 import org.sonar.server.computation.task.projectanalysis.component.FileAttributes;
48 import org.sonar.server.computation.task.projectanalysis.component.ReportComponent;
49 import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolderRule;
50 import org.sonar.server.computation.task.projectanalysis.duplication.Duplicate;
51 import org.sonar.server.computation.task.projectanalysis.duplication.Duplication;
52 import org.sonar.server.computation.task.projectanalysis.duplication.DuplicationRepositoryRule;
53 import org.sonar.server.computation.task.projectanalysis.duplication.InnerDuplicate;
54 import org.sonar.server.computation.task.projectanalysis.duplication.TextBlock;
55 import org.sonar.server.computation.task.projectanalysis.scm.Changeset;
56 import org.sonar.server.computation.task.projectanalysis.scm.ScmInfoRepositoryRule;
57 import org.sonar.server.computation.task.projectanalysis.source.SourceLinesRepositoryRule;
58 import org.sonar.server.computation.task.step.ComputationStep;
60 public class PersistFileSourcesStepTest extends BaseStepTest {
62 private static final int FILE1_REF = 3;
63 private static final int FILE2_REF = 4;
64 private static final String PROJECT_UUID = "PROJECT";
65 private static final String PROJECT_KEY = "PROJECT_KEY";
66 private static final String FILE1_UUID = "FILE1";
67 private static final String FILE2_UUID = "FILE2";
68 private static final long NOW = 123456789L;
70 private System2 system2 = mock(System2.class);
73 public ExpectedException thrown = ExpectedException.none();
76 public DbTester dbTester = DbTester.create(system2);
78 public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
80 public BatchReportReaderRule reportReader = new BatchReportReaderRule();
82 public ScmInfoRepositoryRule scmInfoRepository = new ScmInfoRepositoryRule();
84 public SourceLinesRepositoryRule fileSourceRepository = new SourceLinesRepositoryRule();
86 public DuplicationRepositoryRule duplicationRepository = DuplicationRepositoryRule.create(treeRootHolder);
88 public AnalysisMetadataHolderRule analysisMetadataHolder = new AnalysisMetadataHolderRule().setIncrementalAnalysis(false);
90 private DbClient dbClient = dbTester.getDbClient();
91 private DbSession session = dbTester.getSession();
93 private PersistFileSourcesStep underTest;
97 when(system2.now()).thenReturn(NOW);
98 underTest = new PersistFileSourcesStep(dbClient, system2, treeRootHolder, reportReader, fileSourceRepository, scmInfoRepository,
99 duplicationRepository, analysisMetadataHolder);
103 protected ComputationStep step() {
108 public void persist_sources() {
113 assertThat(dbTester.countRowsOfTable("file_sources")).isEqualTo(1);
114 FileSourceDto fileSourceDto = dbClient.fileSourceDao().selectSourceByFileUuid(session, FILE1_UUID);
115 assertThat(fileSourceDto.getProjectUuid()).isEqualTo(PROJECT_UUID);
116 assertThat(fileSourceDto.getFileUuid()).isEqualTo(FILE1_UUID);
117 assertThat(fileSourceDto.getBinaryData()).isNotEmpty();
118 assertThat(fileSourceDto.getDataHash()).isNotEmpty();
119 assertThat(fileSourceDto.getLineHashes()).isNotEmpty();
120 assertThat(fileSourceDto.getCreatedAt()).isEqualTo(NOW);
121 assertThat(fileSourceDto.getUpdatedAt()).isEqualTo(NOW);
123 DbFileSources.Data data = fileSourceDto.getSourceData();
124 assertThat(data.getLinesCount()).isEqualTo(2);
125 assertThat(data.getLines(0).getLine()).isEqualTo(1);
126 assertThat(data.getLines(0).getSource()).isEqualTo("line1");
127 assertThat(data.getLines(1).getLine()).isEqualTo(2);
128 assertThat(data.getLines(1).getSource()).isEqualTo("line2");
132 public void dont_persist_unchanged_sources_if_incremental() {
133 analysisMetadataHolder.setIncrementalAnalysis(true);
134 initIncrementalReport(2);
137 assertThat(dbTester.countRowsOfTable("file_sources")).isEqualTo(1);
141 public void persist_source_hashes() {
146 assertThat(dbTester.countRowsOfTable("file_sources")).isEqualTo(1);
147 FileSourceDto fileSourceDto = dbClient.fileSourceDao().selectSourceByFileUuid(session, FILE1_UUID);
148 assertThat(fileSourceDto.getLineHashes()).isEqualTo("137f72c3708c6bd0de00a0e5a69c699b\ne6251bcf1a7dc3ba5e7933e325bbe605");
149 assertThat(fileSourceDto.getSrcHash()).isEqualTo("ee5a58024a155466b43bc559d953e018");
153 public void persist_coverage() {
156 reportReader.putCoverage(FILE1_REF, newArrayList(ScannerReport.LineCoverage.newBuilder()
160 .setCoveredConditions(2)
165 assertThat(dbTester.countRowsOfTable("file_sources")).isEqualTo(1);
166 FileSourceDto fileSourceDto = dbClient.fileSourceDao().selectSourceByFileUuid(session, FILE1_UUID);
167 DbFileSources.Data data = fileSourceDto.getSourceData();
169 assertThat(data.getLinesList()).hasSize(1);
171 assertThat(data.getLines(0).getLineHits()).isEqualTo(1);
172 assertThat(data.getLines(0).getConditions()).isEqualTo(10);
173 assertThat(data.getLines(0).getCoveredConditions()).isEqualTo(2);
177 public void persist_scm() {
179 scmInfoRepository.setScmInfo(FILE1_REF, Changeset.newChangesetBuilder()
182 .setRevision("rev-1")
187 assertThat(dbTester.countRowsOfTable("file_sources")).isEqualTo(1);
188 FileSourceDto fileSourceDto = dbClient.fileSourceDao().selectSourceByFileUuid(session, FILE1_UUID);
190 assertThat(fileSourceDto.getRevision()).isEqualTo("rev-1");
192 DbFileSources.Data data = fileSourceDto.getSourceData();
194 assertThat(data.getLinesList()).hasSize(1);
196 assertThat(data.getLines(0).getScmAuthor()).isEqualTo("john");
197 assertThat(data.getLines(0).getScmDate()).isEqualTo(123456789L);
198 assertThat(data.getLines(0).getScmRevision()).isEqualTo("rev-1");
202 public void persist_highlighting() {
205 reportReader.putSyntaxHighlighting(FILE1_REF, newArrayList(ScannerReport.SyntaxHighlightingRule.newBuilder()
206 .setRange(ScannerReport.TextRange.newBuilder()
207 .setStartLine(1).setEndLine(1)
208 .setStartOffset(2).setEndOffset(4)
210 .setType(HighlightingType.ANNOTATION)
215 assertThat(dbTester.countRowsOfTable("file_sources")).isEqualTo(1);
216 FileSourceDto fileSourceDto = dbClient.fileSourceDao().selectSourceByFileUuid(session, FILE1_UUID);
217 DbFileSources.Data data = fileSourceDto.getSourceData();
219 assertThat(data.getLinesList()).hasSize(1);
221 assertThat(data.getLines(0).getHighlighting()).isEqualTo("2,4,a");
225 public void persist_symbols() {
228 reportReader.putSymbols(FILE1_REF, newArrayList(
229 ScannerReport.Symbol.newBuilder()
230 .setDeclaration(ScannerReport.TextRange.newBuilder()
231 .setStartLine(1).setEndLine(1).setStartOffset(2).setEndOffset(4)
233 .addReference(ScannerReport.TextRange.newBuilder()
234 .setStartLine(3).setEndLine(3).setStartOffset(1).setEndOffset(3)
240 assertThat(dbTester.countRowsOfTable("file_sources")).isEqualTo(1);
241 FileSourceDto fileSourceDto = dbClient.fileSourceDao().selectSourceByFileUuid(session, FILE1_UUID);
242 DbFileSources.Data data = fileSourceDto.getSourceData();
244 assertThat(data.getLinesList()).hasSize(3);
246 assertThat(data.getLines(0).getSymbols()).isEqualTo("2,4,1");
247 assertThat(data.getLines(1).getSymbols()).isEmpty();
248 assertThat(data.getLines(2).getSymbols()).isEqualTo("1,3,1");
252 public void persist_duplication() {
255 duplicationRepository.add(
257 new Duplication(new TextBlock(1, 2), Arrays.<Duplicate>asList(new InnerDuplicate(new TextBlock(3, 4)))));
261 assertThat(dbTester.countRowsOfTable("file_sources")).isEqualTo(1);
262 FileSourceDto fileSourceDto = dbClient.fileSourceDao().selectSourceByFileUuid(session, FILE1_UUID);
263 DbFileSources.Data data = fileSourceDto.getSourceData();
265 assertThat(data.getLinesList()).hasSize(1);
267 assertThat(data.getLines(0).getDuplicationList()).hasSize(1);
271 public void save_revision() {
273 scmInfoRepository.setScmInfo(FILE1_REF, Changeset.newChangesetBuilder()
276 .setRevision("rev-1")
281 FileSourceDto fileSourceDto = dbClient.fileSourceDao().selectSourceByFileUuid(session, FILE1_UUID);
282 assertThat(fileSourceDto.getRevision()).isEqualTo("rev-1");
286 public void not_save_revision() {
291 FileSourceDto fileSourceDto = dbClient.fileSourceDao().selectSourceByFileUuid(session, FILE1_UUID);
292 assertThat(fileSourceDto.getRevision()).isNull();
296 public void not_update_sources_when_nothing_has_changed() {
299 String srcHash = "137f72c3708c6bd0de00a0e5a69c699b";
300 String lineHashes = "137f72c3708c6bd0de00a0e5a69c699b";
301 String dataHash = "29f25900140c94db38035128cb6de6a2";
303 dbClient.fileSourceDao().insert(dbTester.getSession(), new FileSourceDto()
304 .setProjectUuid(PROJECT_UUID)
305 .setFileUuid(FILE1_UUID)
307 .setLineHashes(lineHashes)
308 .setDataHash(dataHash)
309 .setSourceData(DbFileSources.Data.newBuilder()
310 .addLines(DbFileSources.Line.newBuilder()
316 .setUpdatedAt(past));
317 dbTester.getSession().commit();
319 // Sources from the report
324 assertThat(dbTester.countRowsOfTable("file_sources")).isEqualTo(1);
325 FileSourceDto fileSourceDto = dbClient.fileSourceDao().selectSourceByFileUuid(session, FILE1_UUID);
326 assertThat(fileSourceDto.getSrcHash()).isEqualTo(srcHash);
327 assertThat(fileSourceDto.getLineHashes()).isEqualTo(lineHashes);
328 assertThat(fileSourceDto.getDataHash()).isEqualTo(dataHash);
329 assertThat(fileSourceDto.getCreatedAt()).isEqualTo(past);
330 assertThat(fileSourceDto.getUpdatedAt()).isEqualTo(past);
334 public void update_sources_when_source_updated() {
337 dbClient.fileSourceDao().insert(dbTester.getSession(), new FileSourceDto()
338 .setProjectUuid(PROJECT_UUID)
339 .setFileUuid(FILE1_UUID)
340 .setDataType(Type.SOURCE)
341 .setSrcHash("5b4bd9815cdb17b8ceae19eb1810c34c")
342 .setLineHashes("6438c669e0d0de98e6929c2cc0fac474\n")
343 .setDataHash("6cad150e3d065976c230cddc5a09efaa")
344 .setSourceData(DbFileSources.Data.newBuilder()
345 .addLines(DbFileSources.Line.newBuilder()
347 .setSource("old line")
352 .setRevision("rev-0"));
353 dbTester.getSession().commit();
357 scmInfoRepository.setScmInfo(FILE1_REF, Changeset.newChangesetBuilder()
360 .setRevision("rev-1")
365 assertThat(dbTester.countRowsOfTable("file_sources")).isEqualTo(1);
366 FileSourceDto fileSourceDto = dbClient.fileSourceDao().selectSourceByFileUuid(session, FILE1_UUID);
367 assertThat(fileSourceDto.getCreatedAt()).isEqualTo(past);
368 assertThat(fileSourceDto.getUpdatedAt()).isEqualTo(NOW);
369 assertThat(fileSourceDto.getRevision()).isEqualTo("rev-1");
373 public void update_sources_when_src_hash_is_missing() {
376 dbClient.fileSourceDao().insert(dbTester.getSession(), new FileSourceDto()
377 .setProjectUuid(PROJECT_UUID)
378 .setFileUuid(FILE1_UUID)
379 .setDataType(Type.SOURCE)
380 // Source hash is missing, update will be made
381 .setLineHashes("137f72c3708c6bd0de00a0e5a69c699b")
382 .setDataHash("29f25900140c94db38035128cb6de6a2")
383 .setSourceData(DbFileSources.Data.newBuilder()
384 .addLines(DbFileSources.Line.newBuilder()
390 .setUpdatedAt(past));
391 dbTester.getSession().commit();
397 assertThat(dbTester.countRowsOfTable("file_sources")).isEqualTo(1);
398 FileSourceDto fileSourceDto = dbClient.fileSourceDao().selectSourceByFileUuid(session, FILE1_UUID);
399 assertThat(fileSourceDto.getCreatedAt()).isEqualTo(past);
400 assertThat(fileSourceDto.getUpdatedAt()).isEqualTo(NOW);
401 assertThat(fileSourceDto.getSrcHash()).isEqualTo("137f72c3708c6bd0de00a0e5a69c699b");
405 public void update_sources_when_revision_is_missing() {
408 dbClient.fileSourceDao().insert(dbTester.getSession(), new FileSourceDto()
409 .setProjectUuid(PROJECT_UUID)
410 .setFileUuid(FILE1_UUID)
411 .setDataType(Type.SOURCE)
412 .setSrcHash("137f72c3708c6bd0de00a0e5a69c699b")
413 .setLineHashes("137f72c3708c6bd0de00a0e5a69c699b")
414 .setDataHash("8e84c0d961cfe364e43833c4cc4ddef5")
415 // Revision is missing, update will be made
416 .setSourceData(DbFileSources.Data.newBuilder()
417 .addLines(DbFileSources.Line.newBuilder()
423 .setUpdatedAt(past));
424 dbTester.getSession().commit();
426 scmInfoRepository.setScmInfo(FILE1_REF, Changeset.newChangesetBuilder()
429 .setRevision("rev-1")
436 assertThat(dbTester.countRowsOfTable("file_sources")).isEqualTo(1);
437 FileSourceDto fileSourceDto = dbClient.fileSourceDao().selectSourceByFileUuid(session, FILE1_UUID);
438 assertThat(fileSourceDto.getCreatedAt()).isEqualTo(past);
439 assertThat(fileSourceDto.getUpdatedAt()).isEqualTo(NOW);
440 assertThat(fileSourceDto.getRevision()).isEqualTo("rev-1");
444 public void clear_revision_when_no_ChangeSet() {
447 dbClient.fileSourceDao().insert(dbTester.getSession(), new FileSourceDto()
448 .setProjectUuid(PROJECT_UUID)
449 .setFileUuid(FILE1_UUID)
450 .setDataType(Type.SOURCE)
451 .setSrcHash("137f72c3708c6bd0de00a0e5a69c699b")
452 .setLineHashes("137f72c3708c6bd0de00a0e5a69c699b")
453 .setDataHash("8e84c0d961cfe364e43833c4cc4ddef5")
454 // Revision is missing, update will be made
455 .setSourceData(DbFileSources.Data.newBuilder()
456 .addLines(DbFileSources.Line.newBuilder()
462 .setUpdatedAt(past));
463 dbTester.getSession().commit();
469 assertThat(dbTester.countRowsOfTable("file_sources")).isEqualTo(1);
470 FileSourceDto fileSourceDto = dbClient.fileSourceDao().selectSourceByFileUuid(session, FILE1_UUID);
471 assertThat(fileSourceDto.getCreatedAt()).isEqualTo(past);
472 assertThat(fileSourceDto.getUpdatedAt()).isEqualTo(NOW);
473 assertThat(fileSourceDto.getRevision()).isNull();
476 private void initIncrementalReport(int numberOfLines) {
477 treeRootHolder.setRoot(ReportComponent
478 .builder(Component.Type.PROJECT, 1)
479 .setUuid(PROJECT_UUID)
483 .builder(Component.Type.MODULE, 2)
485 .setKey("MODULE_KEY")
488 .builder(Component.Type.FILE, FILE1_REF)
490 .setKey("MODULE_KEY:src/Foo.java")
491 .setFileAttributes(new FileAttributes(false, null, numberOfLines))
492 .setStatus(Status.CHANGED)
496 .builder(Component.Type.FILE, FILE2_REF)
498 .setKey("MODULE_KEY:src/Foo2.java")
499 .setStatus(Status.SAME).build())
502 reportReader.putComponent(ScannerReport.Component.newBuilder()
504 .setType(ComponentType.PROJECT)
507 reportReader.putComponent(ScannerReport.Component.newBuilder()
509 .setType(ComponentType.MODULE)
510 .addChildRef(FILE1_REF)
512 reportReader.putComponent(ScannerReport.Component.newBuilder()
514 .setType(ComponentType.FILE)
515 .setLines(numberOfLines)
517 reportReader.putComponent(ScannerReport.Component.newBuilder()
519 .setType(ComponentType.FILE)
520 .setLines(numberOfLines)
523 for (int i = 1; i <= numberOfLines; i++) {
524 fileSourceRepository.addLine(FILE1_REF, "line" + i);
528 private void initBasicReport(int numberOfLines) {
529 treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid(PROJECT_UUID).setKey(PROJECT_KEY).addChildren(
530 ReportComponent.builder(Component.Type.MODULE, 2).setUuid("MODULE").setKey("MODULE_KEY").addChildren(
531 ReportComponent.builder(Component.Type.FILE, FILE1_REF).setUuid(FILE1_UUID).setKey("MODULE_KEY:src/Foo.java")
532 .setFileAttributes(new FileAttributes(false, null, numberOfLines)).build())
536 reportReader.putComponent(ScannerReport.Component.newBuilder()
538 .setType(ComponentType.PROJECT)
541 reportReader.putComponent(ScannerReport.Component.newBuilder()
543 .setType(ComponentType.MODULE)
544 .addChildRef(FILE1_REF)
546 reportReader.putComponent(ScannerReport.Component.newBuilder()
548 .setType(ComponentType.FILE)
549 .setLines(numberOfLines)
552 for (int i = 1; i <= numberOfLines; i++) {
553 fileSourceRepository.addLine(FILE1_REF, "line" + i);