2 * SonarQube, open source software quality management tool.
3 * Copyright (C) 2008-2014 SonarSource
4 * mailto:contact AT sonarsource DOT com
6 * SonarQube 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 * SonarQube 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.
21 package org.sonar.server.benchmark;
24 import java.io.IOException;
25 import java.util.ArrayList;
26 import java.util.List;
27 import org.apache.commons.io.FileUtils;
28 import org.junit.Rule;
29 import org.junit.Test;
30 import org.junit.rules.TemporaryFolder;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33 import org.sonar.api.utils.System2;
34 import org.sonar.batch.protocol.Constants;
35 import org.sonar.batch.protocol.output.BatchReport;
36 import org.sonar.batch.protocol.output.BatchReportWriter;
37 import org.sonar.core.util.Uuids;
38 import org.sonar.db.DbClient;
39 import org.sonar.db.DbTester;
40 import org.sonar.server.computation.analysis.MutableAnalysisMetadataHolderRule;
41 import org.sonar.server.computation.batch.BatchReportDirectoryHolderImpl;
42 import org.sonar.server.computation.batch.BatchReportReaderImpl;
43 import org.sonar.server.computation.batch.TreeRootHolderRule;
44 import org.sonar.server.computation.component.Component;
45 import org.sonar.server.computation.component.ReportComponent;
46 import org.sonar.server.computation.scm.ScmInfoRepositoryImpl;
47 import org.sonar.server.computation.source.SourceHashRepositoryImpl;
48 import org.sonar.server.computation.source.SourceLinesRepositoryImpl;
49 import org.sonar.server.computation.step.PersistFileSourcesStep;
51 import static org.assertj.core.api.Assertions.assertThat;
53 public class PersistFileSourcesStepTest {
55 public static final Logger LOGGER = LoggerFactory.getLogger("perfTestPersistFileSourcesStep");
57 public static final int NUMBER_OF_FILES = 1000;
58 public static final int NUMBER_OF_LINES = 1000;
59 public static final String PROJECT_UUID = Uuids.create();
62 public TemporaryFolder temp = new TemporaryFolder();
65 public DbTester dbTester = DbTester.create(System2.INSTANCE);
68 public Benchmark benchmark = new Benchmark();
71 public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
74 public MutableAnalysisMetadataHolderRule analysisMetadataHolder = new MutableAnalysisMetadataHolderRule();
77 public void benchmark() throws Exception {
78 File reportDir = prepareReport();
79 persistFileSources(reportDir);
82 private void persistFileSources(File reportDir) {
83 LOGGER.info("Persist file sources");
84 DbClient dbClient = dbTester.getDbClient();
86 long start = System.currentTimeMillis();
88 BatchReportDirectoryHolderImpl batchReportDirectoryHolder = new BatchReportDirectoryHolderImpl();
89 batchReportDirectoryHolder.setDirectory(reportDir);
90 org.sonar.server.computation.batch.BatchReportReader batchReportReader = new BatchReportReaderImpl(batchReportDirectoryHolder);
91 analysisMetadataHolder.setIsFirstAnalysis(false);
92 SourceLinesRepositoryImpl sourceLinesRepository = new SourceLinesRepositoryImpl(batchReportReader);
93 SourceHashRepositoryImpl sourceHashRepository = new SourceHashRepositoryImpl(sourceLinesRepository);
94 ScmInfoRepositoryImpl scmInfoRepository = new ScmInfoRepositoryImpl(batchReportReader, analysisMetadataHolder, dbClient, sourceHashRepository);
95 PersistFileSourcesStep step = new PersistFileSourcesStep(dbClient, System2.INSTANCE, treeRootHolder, batchReportReader, sourceLinesRepository, scmInfoRepository);
98 long end = System.currentTimeMillis();
99 long duration = end - start;
101 assertThat(dbTester.countRowsOfTable("file_sources")).isEqualTo(NUMBER_OF_FILES);
102 LOGGER.info(String.format("File sources has been persisted in %d ms", duration));
104 benchmark.expectAround("Duration to persist FILE_SOURCES", duration, 125000, Benchmark.DEFAULT_ERROR_MARGIN_PERCENTS);
107 private File prepareReport() throws IOException {
108 LOGGER.info("Create report");
109 File reportDir = temp.newFolder();
111 BatchReportWriter writer = new BatchReportWriter(reportDir);
112 writer.writeMetadata(BatchReport.Metadata.newBuilder()
113 .setRootComponentRef(1)
115 BatchReport.Component.Builder project = BatchReport.Component.newBuilder()
117 .setType(Constants.ComponentType.PROJECT);
119 List<Component> components = new ArrayList<>();
120 for (int fileRef = 2; fileRef <= NUMBER_OF_FILES + 1; fileRef++) {
121 components.add(generateFileReport(writer, fileRef));
122 project.addChildRef(fileRef);
124 treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1)
125 .setUuid(PROJECT_UUID)
127 .addChildren(components.toArray(new Component[components.size()]))
130 writer.writeComponent(project.build());
135 private Component generateFileReport(BatchReportWriter writer, int fileRef) throws IOException {
136 LineData lineData = new LineData();
137 for (int line = 1; line <= NUMBER_OF_LINES; line++) {
138 lineData.generateLineData(line);
140 writer.writeComponent(BatchReport.Component.newBuilder()
142 .setType(Constants.ComponentType.FILE)
143 .setLines(NUMBER_OF_LINES)
146 FileUtils.writeLines(writer.getSourceFile(fileRef), lineData.lines);
147 writer.writeComponentCoverage(fileRef, lineData.coverages);
148 writer.writeComponentChangesets(lineData.changesetsBuilder.setComponentRef(fileRef).build());
149 writer.writeComponentSyntaxHighlighting(fileRef, lineData.highlightings);
150 writer.writeComponentSymbols(fileRef, lineData.symbols);
151 writer.writeComponentDuplications(fileRef, lineData.duplications);
153 return ReportComponent.builder(Component.Type.FILE, fileRef).setUuid(Uuids.create()).setKey("PROJECT:" + fileRef).build();
156 private static class LineData {
157 List<String> lines = new ArrayList<>();
158 BatchReport.Changesets.Builder changesetsBuilder = BatchReport.Changesets.newBuilder();
159 List<BatchReport.Coverage> coverages = new ArrayList<>();
160 List<BatchReport.SyntaxHighlighting> highlightings = new ArrayList<>();
161 List<BatchReport.Symbol> symbols = new ArrayList<>();
162 List<BatchReport.Duplication> duplications = new ArrayList<>();
164 void generateLineData(int line) {
165 lines.add("line-" + line);
167 changesetsBuilder.addChangeset(BatchReport.Changesets.Changeset.newBuilder()
168 .setAuthor("author-" + line)
170 .setRevision("rev-" + line)
172 .addChangesetIndexByLine(line - 1);
174 coverages.add(BatchReport.Coverage.newBuilder()
178 .setUtCoveredConditions(2)
180 .setItCoveredConditions(3)
181 .setOverallCoveredConditions(4)
184 highlightings.add(BatchReport.SyntaxHighlighting.newBuilder()
185 .setRange(BatchReport.TextRange.newBuilder()
186 .setStartLine(line).setEndLine(line)
187 .setStartOffset(1).setEndOffset(3)
189 .setType(Constants.HighlightingType.ANNOTATION)
192 symbols.add(BatchReport.Symbol.newBuilder()
193 .setDeclaration(BatchReport.TextRange.newBuilder()
194 .setStartLine(line).setEndLine(line).setStartOffset(2).setEndOffset(4)
196 .addReference(BatchReport.TextRange.newBuilder()
197 .setStartLine(line + 1).setEndLine(line + 1).setStartOffset(1).setEndOffset(3)
201 duplications.add(BatchReport.Duplication.newBuilder()
202 .setOriginPosition(BatchReport.TextRange.newBuilder()
206 .addDuplicate(BatchReport.Duplicate.newBuilder()
207 .setRange(BatchReport.TextRange.newBuilder()
208 .setStartLine(line + 1)
209 .setEndLine(line + 1)