Browse Source

SONAR-6703 load common rule parameters from batch report

tags/5.2-RC1
Simon Brandhof 9 years ago
parent
commit
399f6c1000
71 changed files with 9934 additions and 11224 deletions
  1. 2
    2
      server/sonar-server-benchmarks/src/test/java/org/sonar/server/benchmark/PersistFileSourcesStepTest.java
  2. 7
    6
      server/sonar-server/src/main/java/org/sonar/server/computation/batch/BatchReportReader.java
  3. 10
    5
      server/sonar-server/src/main/java/org/sonar/server/computation/batch/BatchReportReaderImpl.java
  4. 9
    12
      server/sonar-server/src/main/java/org/sonar/server/computation/issue/BaseIssuesLoader.java
  5. 0
    5
      server/sonar-server/src/main/java/org/sonar/server/computation/issue/Rule.java
  6. 2
    9
      server/sonar-server/src/main/java/org/sonar/server/computation/issue/RuleCacheLoader.java
  7. 1
    9
      server/sonar-server/src/main/java/org/sonar/server/computation/issue/RuleImpl.java
  8. 8
    6
      server/sonar-server/src/main/java/org/sonar/server/computation/issue/TrackerRawInputFactory.java
  9. 17
    12
      server/sonar-server/src/main/java/org/sonar/server/computation/issue/commonrule/AbstractCoverageRule.java
  10. 2
    1
      server/sonar-server/src/main/java/org/sonar/server/computation/issue/commonrule/BranchCoverageRule.java
  11. 28
    14
      server/sonar-server/src/main/java/org/sonar/server/computation/issue/commonrule/CommentDensityRule.java
  12. 13
    0
      server/sonar-server/src/main/java/org/sonar/server/computation/issue/commonrule/CommonRule.java
  13. 2
    1
      server/sonar-server/src/main/java/org/sonar/server/computation/issue/commonrule/LineCoverageRule.java
  14. 10
    6
      server/sonar-server/src/main/java/org/sonar/server/computation/measure/MeasureRepositoryImpl.java
  15. 9
    1
      server/sonar-server/src/main/java/org/sonar/server/computation/qualityprofile/ActiveRule.java
  16. 5
    0
      server/sonar-server/src/main/java/org/sonar/server/computation/qualityprofile/ActiveRulesHolderImpl.java
  17. 4
    4
      server/sonar-server/src/main/java/org/sonar/server/computation/source/DuplicationLineReader.java
  18. 1
    1
      server/sonar-server/src/main/java/org/sonar/server/computation/source/ReportIterator.java
  19. 17
    17
      server/sonar-server/src/main/java/org/sonar/server/computation/source/SymbolsLineReader.java
  20. 1
    3
      server/sonar-server/src/main/java/org/sonar/server/computation/step/ComputationSteps.java
  21. 20
    15
      server/sonar-server/src/main/java/org/sonar/server/computation/step/FeedActiveRulesStep.java
  22. 12
    9
      server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistDuplicationsStep.java
  23. 20
    23
      server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistFileSourcesStep.java
  24. 1
    1
      server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistIssuesStep.java
  25. 1
    1
      server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistTestsStep.java
  26. 1
    1
      server/sonar-server/src/main/java/org/sonar/server/computation/step/SendIssueNotificationsStep.java
  27. 3
    3
      server/sonar-server/src/main/java/org/sonar/server/rule/CommonRuleDefinitionsImpl.java
  28. 6
    0
      server/sonar-server/src/main/java/org/sonar/server/rule/CommonRuleKeys.java
  29. 1
    0
      server/sonar-server/src/main/java/org/sonar/server/util/ObjectInputStreamIterator.java
  30. 1
    1
      server/sonar-server/src/main/java/org/sonar/server/util/cache/DiskCache.java
  31. 18
    15
      server/sonar-server/src/test/java/org/sonar/server/computation/batch/BatchReportReaderImplTest.java
  32. 28
    15
      server/sonar-server/src/test/java/org/sonar/server/computation/batch/BatchReportReaderRule.java
  33. 0
    11
      server/sonar-server/src/test/java/org/sonar/server/computation/issue/DumbRule.java
  34. 2
    16
      server/sonar-server/src/test/java/org/sonar/server/computation/issue/RuleCacheLoaderTest.java
  35. 5
    0
      server/sonar-server/src/test/java/org/sonar/server/computation/issue/commonrule/BranchCoverageRuleTest.java
  36. 23
    32
      server/sonar-server/src/test/java/org/sonar/server/computation/issue/commonrule/CommentDensityRuleTest.java
  37. 71
    0
      server/sonar-server/src/test/java/org/sonar/server/computation/issue/commonrule/CommonRuleTest.java
  38. 7
    3
      server/sonar-server/src/test/java/org/sonar/server/computation/issue/commonrule/CoverageRuleTest.java
  39. 3
    2
      server/sonar-server/src/test/java/org/sonar/server/computation/issue/commonrule/DuplicatedBlockRuleTest.java
  40. 5
    0
      server/sonar-server/src/test/java/org/sonar/server/computation/issue/commonrule/LineCoverageRuleTest.java
  41. 4
    3
      server/sonar-server/src/test/java/org/sonar/server/computation/issue/commonrule/SkippedTestRuleTest.java
  42. 4
    3
      server/sonar-server/src/test/java/org/sonar/server/computation/issue/commonrule/TestErrorRuleTest.java
  43. 4
    4
      server/sonar-server/src/test/java/org/sonar/server/computation/qualityprofile/ActiveRulesHolderImplTest.java
  44. 10
    8
      server/sonar-server/src/test/java/org/sonar/server/computation/source/DuplicationLineReaderTest.java
  45. 39
    39
      server/sonar-server/src/test/java/org/sonar/server/computation/source/SymbolsLineReaderTest.java
  46. 73
    0
      server/sonar-server/src/test/java/org/sonar/server/computation/step/FeedActiveRulesStepTest.java
  47. 1
    1
      server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistFileSourcesStepTest.java
  48. 1
    1
      server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistIssuesStepTest.java
  49. 1
    1
      server/sonar-server/src/test/java/org/sonar/server/util/cache/DiskCacheTest.java
  50. 4
    0
      sonar-batch-protocol/pom.xml
  51. 9012
    10644
      sonar-batch-protocol/src/main/gen-java/org/sonar/batch/protocol/output/BatchReport.java
  52. 50
    19
      sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/ProtobufUtil.java
  53. 34
    35
      sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/BatchReportReader.java
  54. 14
    21
      sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/BatchReportWriter.java
  55. 4
    0
      sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/FileStructure.java
  56. 10
    34
      sonar-batch-protocol/src/main/protobuf/batch_report.proto
  57. 37
    0
      sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/ProtobufUtilTest.java
  58. 33
    38
      sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/BatchReportReaderTest.java
  59. 19
    24
      sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/BatchReportWriterTest.java
  60. 21
    23
      sonar-batch/src/main/java/org/sonar/batch/mediumtest/TaskResult.java
  61. 62
    0
      sonar-batch/src/main/java/org/sonar/batch/report/ActiveRulesPublisher.java
  62. 1
    19
      sonar-batch/src/main/java/org/sonar/batch/report/MetadataPublisher.java
  63. 2
    0
      sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
  64. 3
    3
      sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorStorage.java
  65. 70
    0
      sonar-batch/src/test/java/org/sonar/batch/report/ActiveRulesPublisherTest.java
  66. 29
    25
      sonar-batch/src/test/java/org/sonar/batch/report/DuplicationsPublisherTest.java
  67. 5
    5
      sonar-batch/src/test/java/org/sonar/batch/report/MeasuresPublisherTest.java
  68. 1
    8
      sonar-batch/src/test/java/org/sonar/batch/report/MetadataPublisherTest.java
  69. 8
    2
      sonar-core/src/main/java/org/sonar/core/issue/DefaultIssue.java
  70. 1
    1
      sonar-core/src/main/java/org/sonar/core/util/CloseableIterator.java
  71. 1
    1
      sonar-core/src/test/java/org/sonar/core/util/CloseableIteratorTest.java

+ 2
- 2
server/sonar-server-benchmarks/src/test/java/org/sonar/server/benchmark/PersistFileSourcesStepTest.java View File

@@ -147,7 +147,7 @@ public class PersistFileSourcesStepTest {
BatchReport.Changesets.Builder changesetsBuilder = BatchReport.Changesets.newBuilder();
List<BatchReport.Coverage> coverages = new ArrayList<>();
List<BatchReport.SyntaxHighlighting> highlightings = new ArrayList<>();
List<BatchReport.Symbols.Symbol> symbols = new ArrayList<>();
List<BatchReport.Symbol> symbols = new ArrayList<>();
List<BatchReport.Duplication> duplications = new ArrayList<>();

void generateLineData(int line) {
@@ -178,7 +178,7 @@ public class PersistFileSourcesStepTest {
.setType(Constants.HighlightingType.ANNOTATION)
.build());

symbols.add(BatchReport.Symbols.Symbol.newBuilder()
symbols.add(BatchReport.Symbol.newBuilder()
.setDeclaration(BatchReport.Range.newBuilder()
.setStartLine(line).setEndLine(line).setStartOffset(2).setEndOffset(4)
.build())

+ 7
- 6
server/sonar-server/src/main/java/org/sonar/server/computation/batch/BatchReportReader.java View File

@@ -19,26 +19,27 @@
*/
package org.sonar.server.computation.batch;

import java.util.List;
import javax.annotation.CheckForNull;
import org.sonar.batch.protocol.output.BatchReport;
import org.sonar.server.util.CloseableIterator;
import org.sonar.core.util.CloseableIterator;

public interface BatchReportReader {
BatchReport.Metadata readMetadata();

List<BatchReport.Measure> readComponentMeasures(int componentRef);
CloseableIterator<BatchReport.ActiveRule> readActiveRules();

CloseableIterator<BatchReport.Measure> readComponentMeasures(int componentRef);

@CheckForNull
BatchReport.Changesets readChangesets(int componentRef);

BatchReport.Component readComponent(int componentRef);

List<BatchReport.Issue> readComponentIssues(int componentRef);
CloseableIterator<BatchReport.Issue> readComponentIssues(int componentRef);

List<BatchReport.Duplication> readComponentDuplications(int componentRef);
CloseableIterator<BatchReport.Duplication> readComponentDuplications(int componentRef);

List<BatchReport.Symbols.Symbol> readComponentSymbols(int componentRef);
CloseableIterator<BatchReport.Symbol> readComponentSymbols(int componentRef);

CloseableIterator<BatchReport.SyntaxHighlighting> readComponentSyntaxHighlighting(int fileRef);


+ 10
- 5
server/sonar-server/src/main/java/org/sonar/server/computation/batch/BatchReportReaderImpl.java View File

@@ -33,7 +33,7 @@ import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.LineIterator;
import org.sonar.batch.protocol.output.BatchReport;
import org.sonar.server.util.CloseableIterator;
import org.sonar.core.util.CloseableIterator;

public class BatchReportReaderImpl implements BatchReportReader {
private final org.sonar.batch.protocol.output.BatchReportReader delegate;
@@ -53,7 +53,12 @@ public class BatchReportReaderImpl implements BatchReportReader {
}

@Override
public List<BatchReport.Measure> readComponentMeasures(int componentRef) {
public CloseableIterator<BatchReport.ActiveRule> readActiveRules() {
return delegate.readActiveRules();
}

@Override
public CloseableIterator<BatchReport.Measure> readComponentMeasures(int componentRef) {
return delegate.readComponentMeasures(componentRef);
}

@@ -69,17 +74,17 @@ public class BatchReportReaderImpl implements BatchReportReader {
}

@Override
public List<BatchReport.Issue> readComponentIssues(int componentRef) {
public CloseableIterator<BatchReport.Issue> readComponentIssues(int componentRef) {
return delegate.readComponentIssues(componentRef);
}

@Override
public List<BatchReport.Duplication> readComponentDuplications(int componentRef) {
public CloseableIterator<BatchReport.Duplication> readComponentDuplications(int componentRef) {
return delegate.readComponentDuplications(componentRef);
}

@Override
public List<BatchReport.Symbols.Symbol> readComponentSymbols(int componentRef) {
public CloseableIterator<BatchReport.Symbol> readComponentSymbols(int componentRef) {
return delegate.readComponentSymbols(componentRef);
}


+ 9
- 12
server/sonar-server/src/main/java/org/sonar/server/computation/issue/BaseIssuesLoader.java View File

@@ -29,16 +29,13 @@ import org.apache.ibatis.session.ResultHandler;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.RuleStatus;
import org.sonar.core.issue.DefaultIssue;
import org.sonar.db.issue.IssueDto;
import org.sonar.db.issue.IssueMapper;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.MyBatis;
import org.sonar.server.computation.batch.BatchReportReader;
import org.sonar.db.issue.IssueDto;
import org.sonar.db.issue.IssueMapper;
import org.sonar.server.computation.component.TreeRootHolder;
import org.sonar.db.DbClient;

import static com.google.common.collect.FluentIterable.from;
import static org.sonar.core.rule.RuleKeyFunctions.stringToRuleKey;
import org.sonar.server.computation.qualityprofile.ActiveRulesHolder;

/**
* Loads all the project open issues from database, including manual issues.
@@ -46,14 +43,14 @@ import static org.sonar.core.rule.RuleKeyFunctions.stringToRuleKey;
*/
public class BaseIssuesLoader {

private final Set<RuleKey> activeRuleKeys;
private final TreeRootHolder treeRootHolder;
private final DbClient dbClient;
private final RuleRepository ruleRepository;
private final ActiveRulesHolder activeRulesHolder;

public BaseIssuesLoader(BatchReportReader reportReader, TreeRootHolder treeRootHolder,
DbClient dbClient, RuleRepository ruleRepository) {
this.activeRuleKeys = from(reportReader.readMetadata().getActiveRuleKeyList()).transform(stringToRuleKey()).toSet();
public BaseIssuesLoader(TreeRootHolder treeRootHolder,
DbClient dbClient, RuleRepository ruleRepository, ActiveRulesHolder activeRulesHolder) {
this.activeRulesHolder = activeRulesHolder;
this.treeRootHolder = treeRootHolder;
this.dbClient = dbClient;
this.ruleRepository = ruleRepository;
@@ -87,7 +84,7 @@ public class BaseIssuesLoader {
}

private boolean isActive(RuleKey ruleKey) {
return ruleKey.isManual() || activeRuleKeys.contains(ruleKey);
return ruleKey.isManual() || activeRulesHolder.get(ruleKey).isPresent();
}

/**

+ 0
- 5
server/sonar-server/src/main/java/org/sonar/server/computation/issue/Rule.java View File

@@ -35,11 +35,6 @@ public interface Rule {

RuleStatus getStatus();

/**
* Is activated in a Quality Profile associated to the project
*/
boolean isActivated();

/**
* Get all tags, whatever system or user tags.
*/

+ 2
- 9
server/sonar-server/src/main/java/org/sonar/server/computation/issue/RuleCacheLoader.java View File

@@ -21,26 +21,19 @@ package org.sonar.server.computation.issue;

import java.util.Collection;
import java.util.Map;
import java.util.Set;
import org.sonar.api.rule.RuleKey;
import org.sonar.db.DbSession;
import org.sonar.db.MyBatis;
import org.sonar.db.rule.RuleDto;
import org.sonar.server.computation.batch.BatchReportReader;
import org.sonar.server.db.DbClient;
import org.sonar.server.util.cache.CacheLoader;

import static com.google.common.collect.FluentIterable.from;
import static org.sonar.core.rule.RuleKeyFunctions.stringToRuleKey;

public class RuleCacheLoader implements CacheLoader<RuleKey, Rule> {

private final DbClient dbClient;
private final Set<RuleKey> activatedKeys;

public RuleCacheLoader(DbClient dbClient, BatchReportReader batchReportReader) {
public RuleCacheLoader(DbClient dbClient) {
this.dbClient = dbClient;
this.activatedKeys = from(batchReportReader.readMetadata().getActiveRuleKeyList()).transform(stringToRuleKey()).toSet();
}

@Override
@@ -49,7 +42,7 @@ public class RuleCacheLoader implements CacheLoader<RuleKey, Rule> {
try {
RuleDto dto = dbClient.ruleDao().getNullableByKey(session, key);
if (dto != null) {
return new RuleImpl(dto, activatedKeys.contains(key));
return new RuleImpl(dto);
}
return null;
} finally {

+ 1
- 9
server/sonar-server/src/main/java/org/sonar/server/computation/issue/RuleImpl.java View File

@@ -39,12 +39,11 @@ public class RuleImpl implements Rule {
private final RuleKey key;
private final String name;
private final RuleStatus status;
private final boolean isActivated;
private final Integer subCharacteristicId;
private final Set<String> tags;
private final DebtRemediationFunction remediationFunction;

public RuleImpl(RuleDto dto, boolean isActivated) {
public RuleImpl(RuleDto dto) {
this.id = dto.getId();
this.key = dto.getKey();
this.name = dto.getName();
@@ -52,7 +51,6 @@ public class RuleImpl implements Rule {
this.subCharacteristicId = effectiveCharacteristicId(dto);
this.tags = union(dto.getSystemTags(), dto.getTags());
this.remediationFunction = effectiveRemediationFunction(dto);
this.isActivated = isActivated;
}

@Override
@@ -75,11 +73,6 @@ public class RuleImpl implements Rule {
return status;
}

@Override
public boolean isActivated() {
return isActivated;
}

@Override
public Set<String> getTags() {
return tags;
@@ -119,7 +112,6 @@ public class RuleImpl implements Rule {
.add("key", key)
.add("name", name)
.add("status", status)
.add("isActivated", isActivated)
.add("subCharacteristicId", subCharacteristicId)
.add("tags", tags)
.toString();

+ 8
- 6
server/sonar-server/src/main/java/org/sonar/server/computation/issue/TrackerRawInputFactory.java View File

@@ -33,6 +33,7 @@ import org.sonar.core.issue.DefaultIssue;
import org.sonar.core.issue.tracking.Input;
import org.sonar.core.issue.tracking.LazyInput;
import org.sonar.core.issue.tracking.LineHashSequence;
import org.sonar.core.util.CloseableIterator;
import org.sonar.server.computation.batch.BatchReportReader;
import org.sonar.server.computation.component.Component;
import org.sonar.server.computation.component.TreeRootHolder;
@@ -76,24 +77,25 @@ public class TrackerRawInputFactory {

@Override
protected List<DefaultIssue> loadIssues() {
List<BatchReport.Issue> reportIssues = reportReader.readComponentIssues(component.getRef());
List<DefaultIssue> result = new ArrayList<>();

for (DefaultIssue commonRuleIssue : commonRuleEngine.process(component)) {
result.add(init(commonRuleIssue));
}
if (!reportIssues.isEmpty()) {
// optimization - do not load line hashes if there are no issues
LineHashSequence lineHashSeq = getLineHashSequence();
for (BatchReport.Issue reportIssue : reportIssues) {
try (CloseableIterator<BatchReport.Issue> reportIssues = reportReader.readComponentIssues(component.getRef())) {
// optimization - do not load line hashes if there are no issues -> getLineHashSequence() is executed
// as late as possible
while (reportIssues.hasNext()) {
BatchReport.Issue reportIssue = reportIssues.next();
if (isIssueOnUnsupportedCommonRule(reportIssue)) {
DefaultIssue issue = toIssue(lineHashSeq, reportIssue);
DefaultIssue issue = toIssue(getLineHashSequence(), reportIssue);
result.add(issue);
} else {
Loggers.get(getClass()).debug("Ignored issue from analysis report on rule {}:{}", reportIssue.getRuleRepository(), reportIssue.getRuleKey());
}
}
}

return result;
}


+ 17
- 12
server/sonar-server/src/main/java/org/sonar/server/computation/issue/commonrule/AbstractCoverageRule.java View File

@@ -33,11 +33,13 @@ public abstract class AbstractCoverageRule extends CommonRule {
private final Metric coverageMetric;
private final Metric uncoveredMetric;
private final Metric toCoverMetric;
private final String minPropertyKey;

public AbstractCoverageRule(ActiveRulesHolder activeRulesHolder, String ruleKey,
public AbstractCoverageRule(ActiveRulesHolder activeRulesHolder, String ruleKey, String minPropertyKey,
MeasureRepository measureRepository,
Metric coverageMetric, Metric uncoveredMetric, Metric toCoverMetric) {
super(activeRulesHolder, ruleKey);
this.minPropertyKey = minPropertyKey;
this.measureRepository = measureRepository;
this.coverageMetric = coverageMetric;
this.uncoveredMetric = uncoveredMetric;
@@ -49,22 +51,25 @@ public abstract class AbstractCoverageRule extends CommonRule {
Optional<Measure> coverageMeasure = measureRepository.getRawMeasure(file, coverageMetric);
if (!file.getFileAttributes().isUnitTest() && coverageMeasure.isPresent()) {
double coverage = coverageMeasure.get().getDoubleValue();
// FIXME load threshold from activeRule
double minimumCoverage = 65.0;
double minimumCoverage = getMinDensityParam(activeRule, minPropertyKey);
if (coverage < minimumCoverage) {
Optional<Measure> uncoveredMeasure = measureRepository.getRawMeasure(file, uncoveredMetric);
Optional<Measure> toCoverMeasure = measureRepository.getRawMeasure(file, toCoverMetric);
double uncovered = uncoveredMeasure.isPresent() ? uncoveredMeasure.get().getDoubleValue() : 0.0;
double toCover = toCoverMeasure.isPresent() ? toCoverMeasure.get().getDoubleValue() : 0.0;

// effort to fix is the number of lines/conditions to cover for reaching threshold
int effortToFix = (int) Math.ceil((toCover * minimumCoverage / 100) - (toCover - uncovered));

return new CommonRuleIssue(effortToFix, formatMessage(effortToFix, minimumCoverage));
return generateIssue(file, minimumCoverage);
}
}
return null;
}

private CommonRuleIssue generateIssue(Component file, double minimumCoverage) {
Optional<Measure> uncoveredMeasure = measureRepository.getRawMeasure(file, uncoveredMetric);
Optional<Measure> toCoverMeasure = measureRepository.getRawMeasure(file, toCoverMetric);
double uncovered = uncoveredMeasure.isPresent() ? uncoveredMeasure.get().getDoubleValue() : 0.0;
double toCover = toCoverMeasure.isPresent() ? toCoverMeasure.get().getDoubleValue() : 0.0;

// effort to fix is the number of lines/conditions to cover for reaching threshold
int effortToFix = (int) Math.ceil((toCover * minimumCoverage / 100) - (toCover - uncovered));

return new CommonRuleIssue(effortToFix, formatMessage(effortToFix, minimumCoverage));
}

protected abstract String formatMessage(int effortToFix, double minCoverage);
}

+ 2
- 1
server/sonar-server/src/main/java/org/sonar/server/computation/issue/commonrule/BranchCoverageRule.java View File

@@ -30,7 +30,8 @@ import static java.lang.String.format;
public class BranchCoverageRule extends AbstractCoverageRule {

public BranchCoverageRule(ActiveRulesHolder activeRulesHolder, MetricRepository metricRepository, MeasureRepository measureRepository) {
super(activeRulesHolder, CommonRuleKeys.INSUFFICIENT_BRANCH_COVERAGE, measureRepository,
super(activeRulesHolder, CommonRuleKeys.INSUFFICIENT_BRANCH_COVERAGE, CommonRuleKeys.INSUFFICIENT_BRANCH_COVERAGE_PROPERTY,
measureRepository,
metricRepository.getByKey(CoreMetrics.BRANCH_COVERAGE_KEY),
metricRepository.getByKey(CoreMetrics.UNCOVERED_CONDITIONS_KEY),
metricRepository.getByKey(CoreMetrics.CONDITIONS_TO_COVER_KEY));

+ 28
- 14
server/sonar-server/src/main/java/org/sonar/server/computation/issue/commonrule/CommentDensityRule.java View File

@@ -52,23 +52,37 @@ public class CommentDensityRule extends CommonRule {
Optional<Measure> commentDensityMeasure = measureRepository.getRawMeasure(file, commentDensityMetric);
Optional<Measure> commentLinesMeasure = measureRepository.getRawMeasure(file, commentLinesMetric);
Optional<Measure> nclocMeasure = measureRepository.getRawMeasure(file, nclocMetric);
// FIXME
double minCommentDensity = 25.0;
if (commentDensityMeasure.isPresent() && nclocMeasure.isPresent() && nclocMeasure.get().getIntValue() > 0 && commentDensityMeasure.get().getDoubleValue() < minCommentDensity) {
int commentLines = commentLinesMeasure.isPresent() ? commentLinesMeasure.get().getIntValue() : 0;
int ncloc = nclocMeasure.get().getIntValue();
int minExpectedCommentLines = (int) Math.ceil(minCommentDensity * ncloc / (100 - minCommentDensity));
int missingCommentLines = minExpectedCommentLines - commentLines;
if (missingCommentLines <= 0) {
throw new IllegalStateException(format("Bug in measures of comment lines - density=%s, comment_lines= %d, ncloc=%d, threshold=%s%%", commentDensityMeasure.get()
.getDoubleValue(), commentLines, nclocMeasure.get().getIntValue(), minCommentDensity));

if (commentDensityMeasure.isPresent() && nclocMeasure.isPresent() && nclocMeasure.get().getIntValue() > 0) {
// this is a small optimization to not load the minimum value when the measures are not present
double minCommentDensity = getMinDensity(activeRule);
if (commentDensityMeasure.get().getDoubleValue() < minCommentDensity) {
return generateIssue(commentDensityMeasure, commentLinesMeasure, nclocMeasure, minCommentDensity);
}
}
return null;
}

// TODO declare min threshold as int but not float ?
String message = format("%d more comment lines need to be written to reach the minimum threshold of %s%% comment density.", missingCommentLines, minCommentDensity);
return new CommonRuleIssue(missingCommentLines, message);
private double getMinDensity(ActiveRule activeRule) {
double min = getMinDensityParam(activeRule, CommonRuleKeys.INSUFFICIENT_COMMENT_DENSITY_PROPERTY);
if (min >= 100.0) {
throw new IllegalStateException("Minimum density of rule [" + activeRule.getRuleKey() + "] is incorrect. Got [100] but must be strictly less than 100.");
}
return min;
}

return null;
private CommonRuleIssue generateIssue(Optional<Measure> commentDensityMeasure, Optional<Measure> commentLinesMeasure, Optional<Measure> nclocMeasure, double minCommentDensity) {
int commentLines = commentLinesMeasure.isPresent() ? commentLinesMeasure.get().getIntValue() : 0;
int ncloc = nclocMeasure.get().getIntValue();
int minExpectedCommentLines = (int) Math.ceil(minCommentDensity * ncloc / (100 - minCommentDensity));
int missingCommentLines = minExpectedCommentLines - commentLines;
if (missingCommentLines <= 0) {
throw new IllegalStateException(format("Bug in measures of comment lines - density=%s, comment_lines= %d, ncloc=%d, threshold=%s%%", commentDensityMeasure.get()
.getDoubleValue(), commentLines, nclocMeasure.get().getIntValue(), minCommentDensity));
}

// TODO declare min threshold as int but not float ?
String message = format("%d more comment lines need to be written to reach the minimum threshold of %s%% comment density.", missingCommentLines, minCommentDensity);
return new CommonRuleIssue(missingCommentLines, message);
}
}

+ 13
- 0
server/sonar-server/src/main/java/org/sonar/server/computation/issue/commonrule/CommonRule.java View File

@@ -21,6 +21,7 @@ package org.sonar.server.computation.issue.commonrule;

import com.google.common.base.Optional;
import javax.annotation.CheckForNull;
import org.elasticsearch.common.lang3.StringUtils;
import org.sonar.api.rule.RuleKey;
import org.sonar.core.issue.DefaultIssue;
import org.sonar.server.computation.component.Component;
@@ -76,4 +77,16 @@ public abstract class CommonRule {
this.message = message;
}
}

protected static double getMinDensityParam(ActiveRule activeRule, String paramKey) {
String s = activeRule.getParams().get(paramKey);
if (StringUtils.isNoneBlank(s)) {
double d = Double.parseDouble(s);
if (d < 0.0 || d > 100.0) {
throw new IllegalStateException(String.format("Minimum density of rule [%s] is incorrect. Got [%s] but must be between 0 and 100.", activeRule.getRuleKey(), s));
}
return d;
}
throw new IllegalStateException(String.format("Required parameter [%s] is missing on rule [%s]", paramKey, activeRule.getRuleKey()));
}
}

+ 2
- 1
server/sonar-server/src/main/java/org/sonar/server/computation/issue/commonrule/LineCoverageRule.java View File

@@ -30,7 +30,8 @@ import static java.lang.String.format;
public class LineCoverageRule extends AbstractCoverageRule {

public LineCoverageRule(ActiveRulesHolder activeRulesHolder, MetricRepository metricRepository, MeasureRepository measureRepository) {
super(activeRulesHolder, CommonRuleKeys.INSUFFICIENT_LINE_COVERAGE, measureRepository,
super(activeRulesHolder, CommonRuleKeys.INSUFFICIENT_LINE_COVERAGE, CommonRuleKeys.INSUFFICIENT_LINE_COVERAGE_PROPERTY,
measureRepository,
metricRepository.getByKey(CoreMetrics.LINE_COVERAGE_KEY),
metricRepository.getByKey(CoreMetrics.UNCOVERED_LINES_KEY),
metricRepository.getByKey(CoreMetrics.LINES_TO_COVER_KEY));

+ 10
- 6
server/sonar-server/src/main/java/org/sonar/server/computation/measure/MeasureRepositoryImpl.java View File

@@ -28,6 +28,7 @@ import java.util.Map;
import java.util.Set;
import javax.annotation.Nullable;
import org.sonar.batch.protocol.output.BatchReport;
import org.sonar.core.util.CloseableIterator;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.measure.MeasureDto;
@@ -184,18 +185,21 @@ public class MeasureRepositoryImpl implements MeasureRepository {
return;
}

for (BatchReport.Measure batchMeasure : reportReader.readComponentMeasures(component.getRef())) {
String metricKey = batchMeasure.getMetricKey();
if (reportMetricValidator.validate(metricKey)) {
Metric metric = metricRepository.getByKey(metricKey);
addLocal(component, metric, batchMeasureToMeasure.toMeasure(batchMeasure, metric).get(), OverridePolicy.DO_NOT_OVERRIDE);
try (CloseableIterator<BatchReport.Measure> readIt = reportReader.readComponentMeasures(component.getRef())) {
while (readIt.hasNext()) {
BatchReport.Measure batchMeasure = readIt.next();
String metricKey = batchMeasure.getMetricKey();
if (reportMetricValidator.validate(metricKey)) {
Metric metric = metricRepository.getByKey(metricKey);
addLocal(component, metric, batchMeasureToMeasure.toMeasure(batchMeasure, metric).get(), OverridePolicy.DO_NOT_OVERRIDE);
}
}
}
loadedComponents.add(component.getRef());
}

private Optional<Measure> findLocal(Component component, Metric metric,
@Nullable RuleDto rule, @Nullable Characteristic characteristic) {
@Nullable RuleDto rule, @Nullable Characteristic characteristic) {
Map<MeasureKey, Measure> measuresPerMetric = measures.get(component.getRef());
if (measuresPerMetric == null) {
return Optional.absent();

+ 9
- 1
server/sonar-server/src/main/java/org/sonar/server/computation/qualityprofile/ActiveRule.java View File

@@ -19,6 +19,8 @@
*/
package org.sonar.server.computation.qualityprofile;

import com.google.common.collect.ImmutableMap;
import java.util.Map;
import javax.annotation.concurrent.Immutable;
import org.sonar.api.rule.RuleKey;

@@ -26,10 +28,12 @@ import org.sonar.api.rule.RuleKey;
public class ActiveRule {
private final RuleKey ruleKey;
private final String severity;
private final Map<String, String> params;

public ActiveRule(RuleKey ruleKey, String severity) {
public ActiveRule(RuleKey ruleKey, String severity, Map<String, String> params) {
this.ruleKey = ruleKey;
this.severity = severity;
this.params = ImmutableMap.copyOf(params);
}

public RuleKey getRuleKey() {
@@ -39,4 +43,8 @@ public class ActiveRule {
public String getSeverity() {
return severity;
}

public Map<String, String> getParams() {
return params;
}
}

+ 5
- 0
server/sonar-server/src/main/java/org/sonar/server/computation/qualityprofile/ActiveRulesHolderImpl.java View File

@@ -39,6 +39,11 @@ public class ActiveRulesHolderImpl implements ActiveRulesHolder {
return Optional.fromNullable(activeRulesByKey.get(ruleKey));
}

public Collection<ActiveRule> getAll() {
checkState(activeRulesByKey != null, "Active rules have not been initialized yet");
return activeRulesByKey.values();
}

public void set(Collection<ActiveRule> activeRules) {
requireNonNull(activeRules, "Active rules cannot be null");
checkState(activeRulesByKey == null, "Active rules have already been initialized");

+ 4
- 4
server/sonar-server/src/main/java/org/sonar/server/computation/source/DuplicationLineReader.java View File

@@ -20,14 +20,14 @@

package org.sonar.server.computation.source;

import org.sonar.batch.protocol.output.BatchReport;
import org.sonar.server.source.db.FileSourceDb;

import java.io.Serializable;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.sonar.batch.protocol.output.BatchReport;
import org.sonar.server.source.db.FileSourceDb;

import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Maps.newHashMap;
@@ -37,7 +37,7 @@ public class DuplicationLineReader implements LineReader {
private final List<BatchReport.Duplication> duplications;
private final Map<BatchReport.Range, Integer> duplicationIdsByRange;

public DuplicationLineReader(List<BatchReport.Duplication> duplications) {
public DuplicationLineReader(Iterator<BatchReport.Duplication> duplications) {
this.duplications = newArrayList(duplications);
// Sort duplication to have deterministic results and avoid false variation that would lead to an unnecessary update of the source files
// data

+ 1
- 1
server/sonar-server/src/main/java/org/sonar/server/computation/source/ReportIterator.java View File

@@ -25,7 +25,7 @@ import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.Parser;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.sonar.server.util.CloseableIterator;
import org.sonar.core.util.CloseableIterator;

import java.io.File;
import java.io.IOException;

+ 17
- 17
server/sonar-server/src/main/java/org/sonar/server/computation/source/SymbolsLineReader.java View File

@@ -20,27 +20,27 @@

package org.sonar.server.computation.source;

import com.google.common.collect.Lists;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.sonar.batch.protocol.output.BatchReport;
import org.sonar.server.source.db.FileSourceDb;

import static com.google.common.collect.Lists.newArrayList;

public class SymbolsLineReader implements LineReader {

private final List<BatchReport.Symbols.Symbol> symbols;
private final Map<BatchReport.Symbols.Symbol, Integer> idsBySymbol;
private final List<BatchReport.Symbol> symbols;
private final Map<BatchReport.Symbol, Integer> idsBySymbol;

public SymbolsLineReader(List<BatchReport.Symbols.Symbol> symbols) {
this.symbols = newArrayList(symbols);
public SymbolsLineReader(Iterator<BatchReport.Symbol> symbols) {
this.symbols = Lists.newArrayList(symbols);
// Sort symbols to have deterministic results and avoid false variation that would lead to an unnecessary update of the source files
// data
Collections.sort(this.symbols, new SymbolsComparator());
@@ -51,8 +51,8 @@ public class SymbolsLineReader implements LineReader {
@Override
public void read(FileSourceDb.Line.Builder lineBuilder) {
int line = lineBuilder.getLine();
List<BatchReport.Symbols.Symbol> lineSymbols = findSymbolsMatchingLine(line);
for (BatchReport.Symbols.Symbol lineSymbol : lineSymbols) {
List<BatchReport.Symbol> lineSymbols = findSymbolsMatchingLine(line);
for (BatchReport.Symbol lineSymbol : lineSymbols) {
int symbolId = idsBySymbol.get(lineSymbol);
StringBuilder symbolString = new StringBuilder(lineBuilder.getSymbols());

@@ -81,10 +81,10 @@ public class SymbolsLineReader implements LineReader {
}
}

private List<BatchReport.Symbols.Symbol> findSymbolsMatchingLine(int line) {
List<BatchReport.Symbols.Symbol> lineSymbols = new ArrayList<>();
Set<BatchReport.Symbols.Symbol> symbolsIndex = new HashSet<>();
for (BatchReport.Symbols.Symbol symbol : symbols) {
private List<BatchReport.Symbol> findSymbolsMatchingLine(int line) {
List<BatchReport.Symbol> lineSymbols = new ArrayList<>();
Set<BatchReport.Symbol> symbolsIndex = new HashSet<>();
for (BatchReport.Symbol symbol : symbols) {
if (matchLine(symbol.getDeclaration(), line) && !symbolsIndex.contains(symbol)) {
lineSymbols.add(symbol);
symbolsIndex.add(symbol);
@@ -104,19 +104,19 @@ public class SymbolsLineReader implements LineReader {
return range.getStartLine() <= line && range.getEndLine() >= line;
}

private static Map<BatchReport.Symbols.Symbol, Integer> createIdsBySymbolMap(List<BatchReport.Symbols.Symbol> symbols) {
Map<BatchReport.Symbols.Symbol, Integer> map = new HashMap<>();
private static Map<BatchReport.Symbol, Integer> createIdsBySymbolMap(List<BatchReport.Symbol> symbols) {
Map<BatchReport.Symbol, Integer> map = new HashMap<>();
int symbolId = 1;
for (BatchReport.Symbols.Symbol symbol : symbols) {
for (BatchReport.Symbol symbol : symbols) {
map.put(symbol, symbolId);
symbolId++;
}
return map;
}

private static class SymbolsComparator implements Comparator<BatchReport.Symbols.Symbol>, Serializable {
private static class SymbolsComparator implements Comparator<BatchReport.Symbol>, Serializable {
@Override
public int compare(BatchReport.Symbols.Symbol o1, BatchReport.Symbols.Symbol o2) {
public int compare(BatchReport.Symbol o1, BatchReport.Symbol o2) {
if (o1.getDeclaration().getStartLine() == o2.getDeclaration().getStartLine()) {
return Integer.compare(o1.getDeclaration().getStartOffset(), o2.getDeclaration().getStartOffset());
} else {

+ 1
- 3
server/sonar-server/src/main/java/org/sonar/server/computation/step/ComputationSteps.java View File

@@ -54,11 +54,9 @@ public class ComputationSteps {
// data computation
CoverageMeasuresStep.class,
CommentMeasuresStep.class,

// must be executed after the measures required for common rules (coverage, comment density, duplications)
CustomMeasuresCopyStep.class,
CommentMeasuresStep.class,
DuplicationMeasuresStep.class,
// must be executed after the measures required for common rules (coverage, comment density, duplications)
IntegrateIssuesStep.class,
CoreMetricFormulaExecutorStep.class,


+ 20
- 15
server/sonar-server/src/main/java/org/sonar/server/computation/step/FeedActiveRulesStep.java View File

@@ -19,18 +19,17 @@
*/
package org.sonar.server.computation.step;

import com.google.common.base.Function;
import java.util.Collection;
import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.Severity;
import org.sonar.batch.protocol.output.BatchReport;
import org.sonar.core.util.CloseableIterator;
import org.sonar.server.computation.batch.BatchReportReader;
import org.sonar.server.computation.qualityprofile.ActiveRule;
import org.sonar.server.computation.qualityprofile.ActiveRulesHolderImpl;

import static com.google.common.collect.FluentIterable.from;
import static org.sonar.core.rule.RuleKeyFunctions.stringToRuleKey;

public class FeedActiveRulesStep implements ComputationStep {

private final BatchReportReader batchReportReader;
@@ -43,8 +42,14 @@ public class FeedActiveRulesStep implements ComputationStep {

@Override
public void execute() {
Collection<String> keys = batchReportReader.readMetadata().getActiveRuleKeyList();
activeRulesHolder.set(from(keys).transform(stringToRuleKey()).transform(ToActiveRule.INSTANCE).toList());
List<ActiveRule> activeRules = new ArrayList<>();
try (CloseableIterator<BatchReport.ActiveRule> batchActiveRules = batchReportReader.readActiveRules()) {
while (batchActiveRules.hasNext()) {
BatchReport.ActiveRule batchActiveRule = batchActiveRules.next();
activeRules.add(convert(batchActiveRule));
}
}
activeRulesHolder.set(activeRules);
}

@Override
@@ -52,12 +57,12 @@ public class FeedActiveRulesStep implements ComputationStep {
return getClass().getSimpleName();
}

private enum ToActiveRule implements Function<RuleKey, ActiveRule> {
INSTANCE;
@Override
public ActiveRule apply(@Nonnull RuleKey ruleKey) {
// FIXME load severity
return new ActiveRule(ruleKey, Severity.MAJOR);
private ActiveRule convert(BatchReport.ActiveRule input) {
RuleKey key = RuleKey.of(input.getRuleRepository(), input.getRuleKey());
Map<String, String> params = new HashMap<>();
for (BatchReport.ActiveRule.ActiveRuleParam inputParam : input.getParamList()) {
params.put(inputParam.getKey(), inputParam.getValue());
}
return new ActiveRule(key, input.getSeverity().name(), params);
}
}

+ 12
- 9
server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistDuplicationsStep.java View File

@@ -20,15 +20,16 @@

package org.sonar.server.computation.step;

import java.util.List;
import java.util.Iterator;
import org.apache.commons.lang.StringEscapeUtils;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.batch.protocol.output.BatchReport;
import org.sonar.batch.protocol.output.BatchReport.Range;
import org.sonar.db.measure.MeasureDto;
import org.sonar.db.metric.MetricDto;
import org.sonar.core.util.CloseableIterator;
import org.sonar.db.DbSession;
import org.sonar.db.MyBatis;
import org.sonar.db.measure.MeasureDto;
import org.sonar.db.metric.MetricDto;
import org.sonar.server.computation.batch.BatchReportReader;
import org.sonar.server.computation.component.Component;
import org.sonar.server.computation.component.DbIdsRepository;
@@ -84,13 +85,14 @@ public class PersistDuplicationsStep implements ComputationStep {
}

private void visitComponent(Component component) {
List<BatchReport.Duplication> duplications = reportReader.readComponentDuplications(component.getRef());
if (!duplications.isEmpty()) {
saveDuplications( component, duplications);
try (CloseableIterator<BatchReport.Duplication> duplications = reportReader.readComponentDuplications(component.getRef())) {
if (duplications.hasNext()) {
saveDuplications(component, duplications);
}
}
}

private void saveDuplications(Component component, List<BatchReport.Duplication> duplications) {
private void saveDuplications(Component component, Iterator<BatchReport.Duplication> duplications) {
String duplicationXml = createXmlDuplications(component.getKey(), duplications);
MeasureDto measureDto = new MeasureDto()
.setMetricId(duplicationMetric.getId())
@@ -100,10 +102,11 @@ public class PersistDuplicationsStep implements ComputationStep {
dbClient.measureDao().insert(session, measureDto);
}

private String createXmlDuplications(String componentKey, Iterable<BatchReport.Duplication> duplications) {
private String createXmlDuplications(String componentKey, Iterator<BatchReport.Duplication> duplications) {
StringBuilder xml = new StringBuilder();
xml.append("<duplications>");
for (BatchReport.Duplication duplication : duplications) {
while (duplications.hasNext()) {
BatchReport.Duplication duplication = duplications.next();
xml.append("<g>");
appendDuplication(xml, componentKey, duplication.getOriginPosition());
for (BatchReport.Duplicate duplicationBlock : duplication.getDuplicateList()) {

+ 20
- 23
server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistFileSourcesStep.java View File

@@ -30,6 +30,8 @@ import org.apache.ibatis.session.ResultContext;
import org.apache.ibatis.session.ResultHandler;
import org.sonar.api.utils.System2;
import org.sonar.batch.protocol.output.BatchReport;
import org.sonar.core.util.CloseableIterator;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.MyBatis;
import org.sonar.db.source.FileSourceDto;
@@ -45,9 +47,7 @@ import org.sonar.server.computation.source.HighlightingLineReader;
import org.sonar.server.computation.source.LineReader;
import org.sonar.server.computation.source.ScmLineReader;
import org.sonar.server.computation.source.SymbolsLineReader;
import org.sonar.db.DbClient;
import org.sonar.server.source.db.FileSourceDb;
import org.sonar.server.util.CloseableIterator;

import static org.sonar.server.computation.component.ComponentVisitor.Order.PRE_ORDER;

@@ -164,32 +164,29 @@ public class PersistFileSourcesStep implements ComputationStep {

private static class LineReaders {
private final List<LineReader> readers = new ArrayList<>();
private final List<CloseableIterator<?>> iterators = new ArrayList<>();
private final List<CloseableIterator<?>> closeables = new ArrayList<>();

LineReaders(BatchReportReader reportReader, int componentRef) {
CloseableIterator<BatchReport.Coverage> coverageReportIterator = reportReader.readComponentCoverage(componentRef);
BatchReport.Changesets scmReport = reportReader.readChangesets(componentRef);
CloseableIterator<BatchReport.SyntaxHighlighting> highlightingIterator = reportReader.readComponentSyntaxHighlighting(componentRef);
List<BatchReport.Symbols.Symbol> symbols = reportReader.readComponentSymbols(componentRef);
List<BatchReport.Duplication> duplications = reportReader.readComponentDuplications(componentRef);
CloseableIterator<BatchReport.Coverage> coverageIt = reportReader.readComponentCoverage(componentRef);
closeables.add(coverageIt);
readers.add(new CoverageLineReader(coverageIt));

if (coverageReportIterator != null) {
iterators.add(coverageReportIterator);
readers.add(new CoverageLineReader(coverageReportIterator));
}
BatchReport.Changesets scmReport = reportReader.readChangesets(componentRef);
if (scmReport != null) {
readers.add(new ScmLineReader(scmReport));
}
if (highlightingIterator != null) {
iterators.add(highlightingIterator);
readers.add(new HighlightingLineReader(highlightingIterator));
}
if (!duplications.isEmpty()) {
readers.add(new DuplicationLineReader(duplications));
}
if (!symbols.isEmpty()) {
readers.add(new SymbolsLineReader(symbols));
}

CloseableIterator<BatchReport.SyntaxHighlighting> highlightingIt = reportReader.readComponentSyntaxHighlighting(componentRef);
closeables.add(highlightingIt);
readers.add(new HighlightingLineReader(highlightingIt));

CloseableIterator<BatchReport.Symbol> symbolsIt = reportReader.readComponentSymbols(componentRef);
closeables.add(symbolsIt);
readers.add(new SymbolsLineReader(symbolsIt));

CloseableIterator<BatchReport.Duplication> duplicationsIt = reportReader.readComponentDuplications(componentRef);
closeables.add(duplicationsIt);
readers.add(new DuplicationLineReader(duplicationsIt));
}

List<LineReader> readers() {
@@ -197,7 +194,7 @@ public class PersistFileSourcesStep implements ComputationStep {
}

void close() {
for (CloseableIterator<?> reportIterator : iterators) {
for (CloseableIterator<?> reportIterator : closeables) {
reportIterator.close();
}
}

+ 1
- 1
server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistIssuesStep.java View File

@@ -34,7 +34,7 @@ import org.sonar.db.MyBatis;
import org.sonar.server.computation.issue.IssueCache;
import org.sonar.server.computation.issue.RuleRepository;
import org.sonar.db.DbClient;
import org.sonar.server.util.CloseableIterator;
import org.sonar.core.util.CloseableIterator;

public class PersistIssuesStep implements ComputationStep {


+ 1
- 1
server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistTestsStep.java View File

@@ -51,7 +51,7 @@ import org.sonar.server.computation.component.TreeRootHolder;
import org.sonar.db.DbClient;
import org.sonar.server.source.db.FileSourceDb;
import org.sonar.server.source.db.FileSourceDb.Test.TestStatus;
import org.sonar.server.util.CloseableIterator;
import org.sonar.core.util.CloseableIterator;

public class PersistTestsStep implements ComputationStep {


+ 1
- 1
server/sonar-server/src/main/java/org/sonar/server/computation/step/SendIssueNotificationsStep.java View File

@@ -35,7 +35,7 @@ import org.sonar.server.issue.notification.NewIssuesNotification;
import org.sonar.server.issue.notification.NewIssuesNotificationFactory;
import org.sonar.server.issue.notification.NewIssuesStatistics;
import org.sonar.server.notification.NotificationService;
import org.sonar.server.util.CloseableIterator;
import org.sonar.core.util.CloseableIterator;

/**
* Reads issues from disk cache and send related notifications. For performance reasons,

+ 3
- 3
server/sonar-server/src/main/java/org/sonar/server/rule/CommonRuleDefinitionsImpl.java View File

@@ -66,7 +66,7 @@ public class CommonRuleDefinitionsImpl implements CommonRuleDefinitions {
.setDebtRemediationFunction(rule.debtRemediationFunctions().linear("5min"))
.setEffortToFixDescription("number of uncovered conditions")
.setSeverity(Severity.MAJOR);
rule.createParam("minimumBranchCoverageRatio")
rule.createParam(CommonRuleKeys.INSUFFICIENT_BRANCH_COVERAGE_PROPERTY)
.setName("The minimum required branch coverage ratio")
.setDefaultValue("65")
.setType(RuleParamType.FLOAT);
@@ -82,7 +82,7 @@ public class CommonRuleDefinitionsImpl implements CommonRuleDefinitions {
.setDebtRemediationFunction(rule.debtRemediationFunctions().linear("2min"))
.setEffortToFixDescription("number of lines under the coverage threshold")
.setSeverity(Severity.MAJOR);
rule.createParam("minimumLineCoverageRatio")
rule.createParam(CommonRuleKeys.INSUFFICIENT_LINE_COVERAGE_PROPERTY)
.setName("The minimum required line coverage ratio")
.setDefaultValue("65")
.setType(RuleParamType.FLOAT);
@@ -98,7 +98,7 @@ public class CommonRuleDefinitionsImpl implements CommonRuleDefinitions {
.setDebtRemediationFunction(rule.debtRemediationFunctions().linear("2min"))
.setEffortToFixDescription("number of lines required to meet minimum density")
.setSeverity(Severity.MAJOR);
rule.createParam("minimumCommentDensity")
rule.createParam(CommonRuleKeys.INSUFFICIENT_COMMENT_DENSITY_PROPERTY)
.setName("The minimum required comment density")
.setDefaultValue("25")
.setType(RuleParamType.FLOAT);

+ 6
- 0
server/sonar-server/src/main/java/org/sonar/server/rule/CommonRuleKeys.java View File

@@ -24,8 +24,14 @@ public class CommonRuleKeys {
public static final String REPOSITORY_PREFIX = "common-";

public static final String INSUFFICIENT_BRANCH_COVERAGE = "InsufficientBranchCoverage";
public static final String INSUFFICIENT_BRANCH_COVERAGE_PROPERTY = "minimumBranchCoverageRatio";

public static final String INSUFFICIENT_LINE_COVERAGE = "InsufficientLineCoverage";
public static final String INSUFFICIENT_LINE_COVERAGE_PROPERTY = "minimumLineCoverageRatio";

public static final String INSUFFICIENT_COMMENT_DENSITY = "InsufficientCommentDensity";
public static final String INSUFFICIENT_COMMENT_DENSITY_PROPERTY = "minimumCommentDensity";

public static final String DUPLICATED_BLOCKS = "DuplicatedBlocks";
public static final String FAILED_UNIT_TESTS = "FailedUnitTests";
public static final String SKIPPED_UNIT_TESTS = "SkippedUnitTests";

+ 1
- 0
server/sonar-server/src/main/java/org/sonar/server/util/ObjectInputStreamIterator.java View File

@@ -26,6 +26,7 @@ import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import org.sonar.core.util.CloseableIterator;

public class ObjectInputStreamIterator<E> extends CloseableIterator<E> {


+ 1
- 1
server/sonar-server/src/main/java/org/sonar/server/util/cache/DiskCache.java View File

@@ -28,7 +28,7 @@ import java.io.Serializable;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.sonar.api.utils.System2;
import org.sonar.server.util.CloseableIterator;
import org.sonar.core.util.CloseableIterator;
import org.sonar.server.util.ObjectInputStreamIterator;

/**

+ 18
- 15
server/sonar-server/src/test/java/org/sonar/server/computation/batch/BatchReportReaderImplTest.java View File

@@ -30,7 +30,7 @@ import org.sonar.api.utils.internal.JUnitTempFolder;
import org.sonar.batch.protocol.output.BatchReport;
import org.sonar.batch.protocol.output.BatchReportWriter;
import org.sonar.batch.protocol.output.FileStructure;
import org.sonar.server.util.CloseableIterator;
import org.sonar.core.util.CloseableIterator;

import static com.google.common.collect.ImmutableList.of;
import static org.assertj.core.api.Assertions.assertThat;
@@ -42,9 +42,8 @@ public class BatchReportReaderImplTest {
private static final BatchReport.Measure MEASURE = BatchReport.Measure.newBuilder().build();
private static final BatchReport.Component COMPONENT = BatchReport.Component.newBuilder().setRef(COMPONENT_REF).build();
private static final BatchReport.Issue ISSUE = BatchReport.Issue.newBuilder().build();
private static final BatchReport.Issues ISSUES = BatchReport.Issues.newBuilder().setComponentRef(COMPONENT_REF).addIssue(ISSUE).build();
private static final BatchReport.Duplication DUPLICATION = BatchReport.Duplication.newBuilder().build();
private static final BatchReport.Symbols.Symbol SYMBOL = BatchReport.Symbols.Symbol.newBuilder().build();
private static final BatchReport.Symbol SYMBOL = BatchReport.Symbol.newBuilder().build();
private static final BatchReport.SyntaxHighlighting SYNTAX_HIGHLIGHTING_1 = BatchReport.SyntaxHighlighting.newBuilder().build();
private static final BatchReport.SyntaxHighlighting SYNTAX_HIGHLIGHTING_2 = BatchReport.SyntaxHighlighting.newBuilder().build();
private static final BatchReport.Coverage COVERAGE_1 = BatchReport.Coverage.newBuilder().build();
@@ -94,9 +93,10 @@ public class BatchReportReaderImplTest {
public void verify_readComponentMeasures_returns_measures() {
writer.writeComponentMeasures(COMPONENT_REF, of(MEASURE));

List<BatchReport.Measure> measures = underTest.readComponentMeasures(COMPONENT_REF);
assertThat(measures).hasSize(1);
assertThat(measures.get(0)).isEqualTo(MEASURE);
try (CloseableIterator<BatchReport.Measure> measures = underTest.readComponentMeasures(COMPONENT_REF)) {
assertThat(measures.next()).isEqualTo(MEASURE);
assertThat(measures.hasNext()).isFalse();
}
}

@Test
@@ -154,9 +154,10 @@ public class BatchReportReaderImplTest {
public void verify_readComponentIssues_returns_Issues() {
writer.writeComponentIssues(COMPONENT_REF, of(ISSUE));

List<BatchReport.Issue> res = underTest.readComponentIssues(COMPONENT_REF);
assertThat(res).hasSize(1);
assertThat(res.get(0)).isEqualTo(ISSUE);
try (CloseableIterator<BatchReport.Issue> res = underTest.readComponentIssues(COMPONENT_REF)) {
assertThat(res.next()).isEqualTo(ISSUE);
assertThat(res.hasNext()).isFalse();
}
}

@Test
@@ -175,9 +176,10 @@ public class BatchReportReaderImplTest {
public void verify_readComponentDuplications_returns_Issues() {
writer.writeComponentDuplications(COMPONENT_REF, of(DUPLICATION));

List<BatchReport.Duplication> res = underTest.readComponentDuplications(COMPONENT_REF);
assertThat(res).hasSize(1);
assertThat(res.get(0)).isEqualTo(DUPLICATION);
try (CloseableIterator<BatchReport.Duplication> res = underTest.readComponentDuplications(COMPONENT_REF)) {
assertThat(res.next()).isEqualTo(DUPLICATION);
assertThat(res.hasNext()).isFalse();
}
}

@Test
@@ -196,9 +198,10 @@ public class BatchReportReaderImplTest {
public void verify_readComponentSymbols_returns_Issues() {
writer.writeComponentSymbols(COMPONENT_REF, of(SYMBOL));

List<BatchReport.Symbols.Symbol> res = underTest.readComponentSymbols(COMPONENT_REF);
assertThat(res).hasSize(1);
assertThat(res.get(0)).isEqualTo(SYMBOL);
try (CloseableIterator<BatchReport.Symbol> res = underTest.readComponentSymbols(COMPONENT_REF)) {
assertThat(res.next()).isEqualTo(SYMBOL);
assertThat(res.hasNext()).isFalse();
}
}

@Test

+ 28
- 15
server/sonar-server/src/test/java/org/sonar/server/computation/batch/BatchReportReaderRule.java View File

@@ -20,8 +20,8 @@
package org.sonar.server.computation.batch;

import com.google.common.base.Preconditions;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -31,16 +31,17 @@ import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import org.sonar.batch.protocol.output.BatchReport;
import org.sonar.server.util.CloseableIterator;
import org.sonar.core.util.CloseableIterator;

public class BatchReportReaderRule implements TestRule, BatchReportReader {
private BatchReport.Metadata metadata;
private List<BatchReport.ActiveRule> activeRules = new ArrayList<>();
private Map<Integer, List<BatchReport.Measure>> measures = new HashMap<>();
private Map<Integer, BatchReport.Changesets> changesets = new HashMap<>();
private Map<Integer, BatchReport.Component> components = new HashMap<>();
private Map<Integer, List<BatchReport.Issue>> issues = new HashMap<>();
private Map<Integer, List<BatchReport.Duplication>> duplications = new HashMap<>();
private Map<Integer, List<BatchReport.Symbols.Symbol>> symbols = new HashMap<>();
private Map<Integer, List<BatchReport.Symbol>> symbols = new HashMap<>();
private Map<Integer, List<BatchReport.SyntaxHighlighting>> syntaxHighlightings = new HashMap<>();
private Map<Integer, List<BatchReport.Coverage>> coverages = new HashMap<>();
private Map<Integer, List<String>> fileSources = new HashMap<>();
@@ -89,12 +90,24 @@ public class BatchReportReaderRule implements TestRule, BatchReportReader {
}

@Override
public List<BatchReport.Measure> readComponentMeasures(int componentRef) {
public CloseableIterator<BatchReport.ActiveRule> readActiveRules() {
if (activeRules == null) {
throw new IllegalStateException("Active rules are not set");
}
return CloseableIterator.from(activeRules.iterator());
}

public void putActiveRules(List<BatchReport.ActiveRule> activeRules) {
this.activeRules = activeRules;
}

@Override
public CloseableIterator<BatchReport.Measure> readComponentMeasures(int componentRef) {
List<BatchReport.Measure> res = this.measures.get(componentRef);
if (res == null) {
return Collections.emptyList();
return CloseableIterator.emptyCloseableIterator();
}
return res;
return CloseableIterator.from(res.iterator());
}

public void putMeasures(int componentRef, List<BatchReport.Measure> measures) {
@@ -121,8 +134,8 @@ public class BatchReportReaderRule implements TestRule, BatchReportReader {
}

@Override
public List<BatchReport.Issue> readComponentIssues(int componentRef) {
return nonNull(issues.get(componentRef));
public CloseableIterator<BatchReport.Issue> readComponentIssues(int componentRef) {
return closeableIterator(issues.get(componentRef));
}

public void putIssues(int componentRef, List<BatchReport.Issue> issue) {
@@ -130,8 +143,8 @@ public class BatchReportReaderRule implements TestRule, BatchReportReader {
}

@Override
public List<BatchReport.Duplication> readComponentDuplications(int componentRef) {
return nonNull(this.duplications.get(componentRef));
public CloseableIterator<BatchReport.Duplication> readComponentDuplications(int componentRef) {
return closeableIterator(this.duplications.get(componentRef));
}

public void putDuplications(int componentRef, List<BatchReport.Duplication> duplications) {
@@ -139,15 +152,15 @@ public class BatchReportReaderRule implements TestRule, BatchReportReader {
}

@Override
public List<BatchReport.Symbols.Symbol> readComponentSymbols(int componentRef) {
return nonNull(this.symbols.get(componentRef));
public CloseableIterator<BatchReport.Symbol> readComponentSymbols(int componentRef) {
return closeableIterator(this.symbols.get(componentRef));
}

private static <T> List<T> nonNull(@Nullable List<T> symbols) {
return symbols == null ? Collections.<T>emptyList() : symbols;
private static <T> CloseableIterator<T> closeableIterator(@Nullable List<T> list) {
return list == null ? CloseableIterator.<T>emptyCloseableIterator() : CloseableIterator.from(list.iterator());
}

public void putSymbols(int componentRef, List<BatchReport.Symbols.Symbol> symbols) {
public void putSymbols(int componentRef, List<BatchReport.Symbol> symbols) {
this.symbols.put(componentRef, symbols);
}


+ 0
- 11
server/sonar-server/src/test/java/org/sonar/server/computation/issue/DumbRule.java View File

@@ -33,7 +33,6 @@ public class DumbRule implements Rule {
private RuleKey key;
private String name;
private RuleStatus status = RuleStatus.READY;
private boolean isActivated = false;
private Set<String> tags = new HashSet<>();
private Integer subCharacteristicId;
private DebtRemediationFunction function;
@@ -62,11 +61,6 @@ public class DumbRule implements Rule {
return requireNonNull(status);
}

@Override
public boolean isActivated() {
return isActivated;
}

@Override
public Set<String> getTags() {
return requireNonNull(tags);
@@ -97,11 +91,6 @@ public class DumbRule implements Rule {
return this;
}

public DumbRule setIsActivated(boolean isActivated) {
this.isActivated = isActivated;
return this;
}

public DumbRule setSubCharacteristicId(@Nullable Integer subCharacteristicId) {
this.subCharacteristicId = subCharacteristicId;
return this;

+ 2
- 16
server/sonar-server/src/test/java/org/sonar/server/computation/issue/RuleCacheLoaderTest.java View File

@@ -25,14 +25,11 @@ import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.utils.System2;
import org.sonar.batch.protocol.output.BatchReport;
import org.sonar.db.DbTester;
import org.sonar.server.computation.batch.BatchReportReaderRule;
import org.sonar.server.db.DbClient;
import org.sonar.server.rule.db.RuleDao;
import org.sonar.test.DbTests;

import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
@@ -43,9 +40,6 @@ public class RuleCacheLoaderTest {
@org.junit.Rule
public DbTester dbTester = DbTester.create(System2.INSTANCE);

@org.junit.Rule
public BatchReportReaderRule reportReader = new BatchReportReaderRule();

@Before
public void setUp() {
dbTester.truncateTables();
@@ -53,31 +47,23 @@ public class RuleCacheLoaderTest {

@Test
public void load_by_key() {
BatchReport.Metadata metadata = BatchReport.Metadata.newBuilder()
.addAllActiveRuleKey(asList("java:JAV01")).build();
reportReader.setMetadata(metadata);

dbTester.prepareDbUnit(getClass(), "shared.xml");
DbClient dbClient = new DbClient(dbTester.database(), dbTester.myBatis(), new RuleDao(mock(System2.class)));
RuleCacheLoader loader = new RuleCacheLoader(dbClient, reportReader);
RuleCacheLoader loader = new RuleCacheLoader(dbClient);

Rule javaRule = loader.load(RuleKey.of("java", "JAV01"));
assertThat(javaRule.getName()).isEqualTo("Java One");
assertThat(javaRule.isActivated()).isTrue();

Rule jsRule = loader.load(RuleKey.of("js", "JS01"));
assertThat(jsRule.getName()).isEqualTo("JS One");
assertThat(jsRule.isActivated()).isFalse();

assertThat(loader.load(RuleKey.of("java", "MISSING"))).isNull();
}

@Test
public void load_by_keys_is_not_supported() {
reportReader.setMetadata(BatchReport.Metadata.newBuilder().build());

DbClient dbClient = new DbClient(dbTester.database(), dbTester.myBatis(), new RuleDao(mock(System2.class)));
RuleCacheLoader loader = new RuleCacheLoader(dbClient, reportReader);
RuleCacheLoader loader = new RuleCacheLoader(dbClient);
try {
loader.loadAll(Collections.<RuleKey>emptyList());
fail();

+ 5
- 0
server/sonar-server/src/test/java/org/sonar/server/computation/issue/commonrule/BranchCoverageRuleTest.java View File

@@ -35,6 +35,11 @@ public class BranchCoverageRuleTest extends CoverageRuleTest {
return RuleKey.of("common-java", CommonRuleKeys.INSUFFICIENT_BRANCH_COVERAGE);
}

@Override
protected String getMinPropertyKey() {
return CommonRuleKeys.INSUFFICIENT_BRANCH_COVERAGE_PROPERTY;
}

@Override
protected String getCoverageMetricKey() {
return CoreMetrics.BRANCH_COVERAGE_KEY;

+ 23
- 32
server/sonar-server/src/test/java/org/sonar/server/computation/issue/commonrule/CommentDensityRuleTest.java View File

@@ -19,8 +19,10 @@
*/
package org.sonar.server.computation.issue.commonrule;

import com.google.common.collect.ImmutableMap;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.Severity;
@@ -47,6 +49,9 @@ public class CommentDensityRuleTest {
.setFileAttributes(new FileAttributes(false, "java"))
.build();

@Rule
public ExpectedException thrown = ExpectedException.none();

@Rule
public ActiveRulesHolderRule activeRuleHolder = new ActiveRulesHolderRule();

@@ -66,7 +71,7 @@ public class CommentDensityRuleTest {

@Test
public void no_issues_if_enough_comments() {
activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL));
activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, ImmutableMap.of(CommonRuleKeys.INSUFFICIENT_COMMENT_DENSITY_PROPERTY, "25")));
measureRepository.addRawMeasure(FILE.getRef(), CoreMetrics.COMMENT_LINES_DENSITY_KEY, Measure.newMeasureBuilder().create(90.0));

DefaultIssue issue = underTest.processFile(FILE, "java");
@@ -76,7 +81,7 @@ public class CommentDensityRuleTest {

@Test
public void issue_if_not_enough_comments() {
activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL));
activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, ImmutableMap.of(CommonRuleKeys.INSUFFICIENT_COMMENT_DENSITY_PROPERTY, "25")));
measureRepository.addRawMeasure(FILE.getRef(), CoreMetrics.COMMENT_LINES_DENSITY_KEY, Measure.newMeasureBuilder().create(10.0));
measureRepository.addRawMeasure(FILE.getRef(), CoreMetrics.COMMENT_LINES_KEY, Measure.newMeasureBuilder().create(40));
measureRepository.addRawMeasure(FILE.getRef(), CoreMetrics.NCLOC_KEY, Measure.newMeasureBuilder().create(360));
@@ -93,7 +98,7 @@ public class CommentDensityRuleTest {

@Test
public void issue_if_not_enough_comments__test_ceil() {
activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL));
activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, ImmutableMap.of(CommonRuleKeys.INSUFFICIENT_COMMENT_DENSITY_PROPERTY, "25")));
measureRepository.addRawMeasure(FILE.getRef(), CoreMetrics.COMMENT_LINES_DENSITY_KEY, Measure.newMeasureBuilder().create(0.0));
measureRepository.addRawMeasure(FILE.getRef(), CoreMetrics.COMMENT_LINES_KEY, Measure.newMeasureBuilder().create(0));
measureRepository.addRawMeasure(FILE.getRef(), CoreMetrics.NCLOC_KEY, Measure.newMeasureBuilder().create(1));
@@ -107,33 +112,19 @@ public class CommentDensityRuleTest {
assertThat(issue.message()).isEqualTo("1 more comment lines need to be written to reach the minimum threshold of 25.0% comment density.");
}

// /**
// * SQALE-110
// */
// @Test
// public void shouldFailIfMinimumCommentDensitySetTo100() {
// check.setMinimumCommentDensity(100);
//
// thrown.expect(IllegalArgumentException.class);
// thrown.expectMessage("100.0 is not a valid value for minimum required comment density for rule 'CommentDensityCheck' (must be >= 0 and < 100).");
//
// check.checkResource(resource, context, null, perspectives);
//
// verify(perspectives, times(0)).as(Issuable.class, resource);
// }
//
// /**
// * SQALE-110
// */
// @Test
// public void shouldFailIfMinimumCommentDensitySetToNegative() {
// check.setMinimumCommentDensity(-5);
//
// thrown.expect(IllegalArgumentException.class);
// thrown.expectMessage("-5.0 is not a valid value for minimum required comment density for rule 'CommentDensityCheck' (must be >= 0 and < 100).");
//
// check.checkResource(resource, context, null, mock(ResourcePerspectives.class));
//
// verify(perspectives, times(0)).as(Issuable.class, resource);
// }
/**
* SQALE-110
*/
@Test
public void fail_if_min_density_is_100() {
thrown.expect(IllegalStateException.class);
thrown.expectMessage("Minimum density of rule [common-java:InsufficientCommentDensity] is incorrect. Got [100] but must be strictly less than 100.");

activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, ImmutableMap.of(CommonRuleKeys.INSUFFICIENT_COMMENT_DENSITY_PROPERTY, "100")));
measureRepository.addRawMeasure(FILE.getRef(), CoreMetrics.COMMENT_LINES_DENSITY_KEY, Measure.newMeasureBuilder().create(0.0));
measureRepository.addRawMeasure(FILE.getRef(), CoreMetrics.COMMENT_LINES_KEY, Measure.newMeasureBuilder().create(0));
measureRepository.addRawMeasure(FILE.getRef(), CoreMetrics.NCLOC_KEY, Measure.newMeasureBuilder().create(1));

underTest.processFile(FILE, "java");
}
}

+ 71
- 0
server/sonar-server/src/test/java/org/sonar/server/computation/issue/commonrule/CommonRuleTest.java View File

@@ -0,0 +1,71 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* SonarQube is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.computation.issue.commonrule;

import com.google.common.collect.ImmutableMap;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.rule.Severity;
import org.sonar.db.rule.RuleTesting;
import org.sonar.server.computation.qualityprofile.ActiveRule;

import static org.assertj.core.api.Assertions.assertThat;

public class CommonRuleTest {

@Rule
public ExpectedException thrown = ExpectedException.none();

@Test
public void test_getMinDensityParam() throws Exception {
ActiveRule activeRule = new ActiveRule(RuleTesting.XOO_X1, Severity.MAJOR, ImmutableMap.of("minDensity", "30.5"));
double minDensity = CommonRule.getMinDensityParam(activeRule, "minDensity");

assertThat(minDensity).isEqualTo(30.5);
}

@Test
public void getMinDensityParam_fails_if_param_value_is_absent() throws Exception {
thrown.expect(IllegalStateException.class);
thrown.expectMessage("Required parameter [minDensity] is missing on rule [xoo:x1]");

ActiveRule activeRule = new ActiveRule(RuleTesting.XOO_X1, Severity.MAJOR, ImmutableMap.<String, String>of());
CommonRule.getMinDensityParam(activeRule, "minDensity");
}

@Test
public void getMinDensityParam_fails_if_param_value_is_negative() throws Exception {
thrown.expect(IllegalStateException.class);
thrown.expectMessage("Minimum density of rule [xoo:x1] is incorrect. Got [-30.5] but must be between 0 and 100.");

ActiveRule activeRule = new ActiveRule(RuleTesting.XOO_X1, Severity.MAJOR, ImmutableMap.of("minDensity", "-30.5"));
CommonRule.getMinDensityParam(activeRule, "minDensity");
}

@Test
public void getMinDensityParam_fails_if_param_value_is_greater_than_100() throws Exception {
thrown.expect(IllegalStateException.class);
thrown.expectMessage("Minimum density of rule [xoo:x1] is incorrect. Got [305] but must be between 0 and 100.");

ActiveRule activeRule = new ActiveRule(RuleTesting.XOO_X1, Severity.MAJOR, ImmutableMap.of("minDensity", "305"));
CommonRule.getMinDensityParam(activeRule, "minDensity");
}
}

+ 7
- 3
server/sonar-server/src/test/java/org/sonar/server/computation/issue/commonrule/CoverageRuleTest.java View File

@@ -19,6 +19,8 @@
*/
package org.sonar.server.computation.issue.commonrule;

import com.google.common.collect.ImmutableMap;
import java.util.Collections;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -74,6 +76,8 @@ public abstract class CoverageRuleTest {

protected abstract RuleKey getRuleKey();

protected abstract String getMinPropertyKey();

protected abstract String getCoverageMetricKey();

protected abstract String getToCoverMetricKey();
@@ -82,7 +86,7 @@ public abstract class CoverageRuleTest {

@Test
public void no_issue_if_enough_coverage() {
activeRuleHolder.put(new ActiveRule(getRuleKey(), Severity.CRITICAL));
activeRuleHolder.put(new ActiveRule(getRuleKey(), Severity.CRITICAL, ImmutableMap.of(getMinPropertyKey(), "65")));
measureRepository.addRawMeasure(FILE.getRef(), getCoverageMetricKey(), Measure.newMeasureBuilder().create(90.0));

DefaultIssue issue = underTest.processFile(FILE, "java");
@@ -92,7 +96,7 @@ public abstract class CoverageRuleTest {

@Test
public void issue_if_coverage_is_too_low() {
activeRuleHolder.put(new ActiveRule(getRuleKey(), Severity.CRITICAL));
activeRuleHolder.put(new ActiveRule(getRuleKey(), Severity.CRITICAL, ImmutableMap.of(getMinPropertyKey(), "65")));
measureRepository.addRawMeasure(FILE.getRef(), getCoverageMetricKey(), Measure.newMeasureBuilder().create(20.0));
measureRepository.addRawMeasure(FILE.getRef(), getUncoveredMetricKey(), Measure.newMeasureBuilder().create(40.0));
measureRepository.addRawMeasure(FILE.getRef(), getToCoverMetricKey(), Measure.newMeasureBuilder().create(50.0));
@@ -110,7 +114,7 @@ public abstract class CoverageRuleTest {

@Test
public void no_issue_if_coverage_is_not_set() {
activeRuleHolder.put(new ActiveRule(getRuleKey(), Severity.CRITICAL));
activeRuleHolder.put(new ActiveRule(getRuleKey(), Severity.CRITICAL, ImmutableMap.of(getMinPropertyKey(), "65")));

DefaultIssue issue = underTest.processFile(FILE, "java");


+ 3
- 2
server/sonar-server/src/test/java/org/sonar/server/computation/issue/commonrule/DuplicatedBlockRuleTest.java View File

@@ -19,6 +19,7 @@
*/
package org.sonar.server.computation.issue.commonrule;

import java.util.Collections;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.measures.CoreMetrics;
@@ -64,7 +65,7 @@ public class DuplicatedBlockRuleTest {

@Test
public void no_issue_if_no_duplicated_blocks() throws Exception {
activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL));
activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.<String, String>emptyMap()));
measureRepository.addRawMeasure(FILE.getRef(), CoreMetrics.DUPLICATED_BLOCKS_KEY, Measure.newMeasureBuilder().create(0));

DefaultIssue issue = underTest.processFile(FILE, "java");
@@ -74,7 +75,7 @@ public class DuplicatedBlockRuleTest {

@Test
public void issue_if_duplicated_blocks() throws Exception {
activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL));
activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.<String, String>emptyMap()));
measureRepository.addRawMeasure(FILE.getRef(), CoreMetrics.DUPLICATED_BLOCKS_KEY, Measure.newMeasureBuilder().create(3));

DefaultIssue issue = underTest.processFile(FILE, "java");

+ 5
- 0
server/sonar-server/src/test/java/org/sonar/server/computation/issue/commonrule/LineCoverageRuleTest.java View File

@@ -35,6 +35,11 @@ public class LineCoverageRuleTest extends CoverageRuleTest {
return RuleKey.of("common-java", CommonRuleKeys.INSUFFICIENT_LINE_COVERAGE);
}

@Override
protected String getMinPropertyKey() {
return CommonRuleKeys.INSUFFICIENT_LINE_COVERAGE_PROPERTY;
}

@Override
protected String getCoverageMetricKey() {
return CoreMetrics.LINE_COVERAGE_KEY;

+ 4
- 3
server/sonar-server/src/test/java/org/sonar/server/computation/issue/commonrule/SkippedTestRuleTest.java View File

@@ -19,6 +19,7 @@
*/
package org.sonar.server.computation.issue.commonrule;

import java.util.Collections;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.measures.CoreMetrics;
@@ -65,7 +66,7 @@ public class SkippedTestRuleTest {

@Test
public void issue_if_skipped_tests() throws Exception {
activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL));
activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.<String, String>emptyMap()));
measureRepository.addRawMeasure(FILE.getRef(), CoreMetrics.SKIPPED_TESTS_KEY, Measure.newMeasureBuilder().create(2));

DefaultIssue issue = underTest.processFile(FILE, "java");
@@ -78,7 +79,7 @@ public class SkippedTestRuleTest {

@Test
public void no_issues_if_zero_skipped_tests() throws Exception {
activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL));
activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.<String, String>emptyMap()));
measureRepository.addRawMeasure(FILE.getRef(), CoreMetrics.SKIPPED_TESTS_KEY, Measure.newMeasureBuilder().create(0));

DefaultIssue issue = underTest.processFile(FILE, "java");
@@ -88,7 +89,7 @@ public class SkippedTestRuleTest {

@Test
public void no_issues_if_measure_is_absent() throws Exception {
activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL));
activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.<String, String>emptyMap()));

DefaultIssue issue = underTest.processFile(FILE, "java");


+ 4
- 3
server/sonar-server/src/test/java/org/sonar/server/computation/issue/commonrule/TestErrorRuleTest.java View File

@@ -19,6 +19,7 @@
*/
package org.sonar.server.computation.issue.commonrule;

import java.util.Collections;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.measures.CoreMetrics;
@@ -66,7 +67,7 @@ public class TestErrorRuleTest {

@Test
public void issue_if_errors_or_failures() throws Exception {
activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL));
activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.<String, String>emptyMap()));
measureRepository.addRawMeasure(FILE.getRef(), CoreMetrics.TEST_ERRORS_KEY, Measure.newMeasureBuilder().create(2));
measureRepository.addRawMeasure(FILE.getRef(), CoreMetrics.TEST_FAILURES_KEY, Measure.newMeasureBuilder().create(1));

@@ -80,7 +81,7 @@ public class TestErrorRuleTest {

@Test
public void no_issues_if_zero_errors_and_failures() throws Exception {
activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL));
activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.<String, String>emptyMap()));
measureRepository.addRawMeasure(FILE.getRef(), CoreMetrics.TEST_ERRORS_KEY, Measure.newMeasureBuilder().create(0));
measureRepository.addRawMeasure(FILE.getRef(), CoreMetrics.TEST_FAILURES_KEY, Measure.newMeasureBuilder().create(0));

@@ -91,7 +92,7 @@ public class TestErrorRuleTest {

@Test
public void no_issues_if_test_measures_are_absent() throws Exception {
activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL));
activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.<String, String>emptyMap()));

DefaultIssue issue = underTest.processFile(FILE, "java");


+ 4
- 4
server/sonar-server/src/test/java/org/sonar/server/computation/qualityprofile/ActiveRulesHolderImplTest.java View File

@@ -48,7 +48,7 @@ public class ActiveRulesHolderImplTest {

@Test
public void get_active_rule() throws Exception {
underTest.set(asList(new ActiveRule(RULE_KEY, Severity.BLOCKER)));
underTest.set(asList(new ActiveRule(RULE_KEY, Severity.BLOCKER, Collections.<String, String>emptyMap())));

Optional<ActiveRule> activeRule = underTest.get(RULE_KEY);
assertThat(activeRule.isPresent()).isTrue();
@@ -61,7 +61,7 @@ public class ActiveRulesHolderImplTest {
thrown.expect(IllegalStateException.class);
thrown.expectMessage("Active rules have already been initialized");

underTest.set(asList(new ActiveRule(RULE_KEY, Severity.BLOCKER)));
underTest.set(asList(new ActiveRule(RULE_KEY, Severity.BLOCKER, Collections.<String, String>emptyMap())));
underTest.set(Collections.<ActiveRule>emptyList());

}
@@ -80,8 +80,8 @@ public class ActiveRulesHolderImplTest {
thrown.expectMessage("Active rule must not be declared multiple times: java:S001");

underTest.set(asList(
new ActiveRule(RULE_KEY, Severity.BLOCKER),
new ActiveRule(RULE_KEY, Severity.MAJOR)
new ActiveRule(RULE_KEY, Severity.BLOCKER, Collections.<String, String>emptyMap()),
new ActiveRule(RULE_KEY, Severity.MAJOR, Collections.<String, String>emptyMap())
));
}
}

+ 10
- 8
server/sonar-server/src/test/java/org/sonar/server/computation/source/DuplicationLineReaderTest.java View File

@@ -20,8 +20,10 @@

package org.sonar.server.computation.source;

import com.google.common.collect.Iterators;
import org.junit.Test;
import org.sonar.batch.protocol.output.BatchReport;
import org.sonar.core.util.CloseableIterator;
import org.sonar.server.source.db.FileSourceDb;

import java.util.Collections;
@@ -39,7 +41,7 @@ public class DuplicationLineReaderTest {

@Test
public void read_nothing() {
DuplicationLineReader reader = new DuplicationLineReader(Collections.<BatchReport.Duplication>emptyList());
DuplicationLineReader reader = new DuplicationLineReader(CloseableIterator.<BatchReport.Duplication>emptyCloseableIterator());

reader.read(line1);

@@ -48,7 +50,7 @@ public class DuplicationLineReaderTest {

@Test
public void read_duplication_with_duplicates_on_same_file() {
DuplicationLineReader reader = new DuplicationLineReader(newArrayList(
DuplicationLineReader reader = new DuplicationLineReader(Iterators.forArray(
BatchReport.Duplication.newBuilder()
.setOriginPosition(BatchReport.Range.newBuilder()
.setStartLine(1)
@@ -61,7 +63,7 @@ public class DuplicationLineReaderTest {
.build())
.build())
.build()
));
));

reader.read(line1);
reader.read(line2);
@@ -76,7 +78,7 @@ public class DuplicationLineReaderTest {

@Test
public void read_duplication_with_duplicates_on_other_file() {
DuplicationLineReader reader = new DuplicationLineReader(newArrayList(
DuplicationLineReader reader = new DuplicationLineReader(Iterators.forArray(
BatchReport.Duplication.newBuilder()
.setOriginPosition(BatchReport.Range.newBuilder()
.setStartLine(1)
@@ -105,7 +107,7 @@ public class DuplicationLineReaderTest {

@Test
public void read_duplication_with_duplicates_on_other_file_from_other_project() {
DuplicationLineReader reader = new DuplicationLineReader(newArrayList(
DuplicationLineReader reader = new DuplicationLineReader(Iterators.forArray(
BatchReport.Duplication.newBuilder()
.setOriginPosition(BatchReport.Range.newBuilder()
.setStartLine(1)
@@ -134,7 +136,7 @@ public class DuplicationLineReaderTest {

@Test
public void read_many_duplications() {
DuplicationLineReader reader = new DuplicationLineReader(newArrayList(
DuplicationLineReader reader = new DuplicationLineReader(Iterators.forArray(
BatchReport.Duplication.newBuilder()
.setOriginPosition(BatchReport.Range.newBuilder()
.setStartLine(1)
@@ -174,7 +176,7 @@ public class DuplicationLineReaderTest {

@Test
public void should_be_sorted_by_line_block() {
DuplicationLineReader reader = new DuplicationLineReader(newArrayList(
DuplicationLineReader reader = new DuplicationLineReader(Iterators.forArray(
BatchReport.Duplication.newBuilder()
.setOriginPosition(BatchReport.Range.newBuilder()
.setStartLine(2)
@@ -214,7 +216,7 @@ public class DuplicationLineReaderTest {

@Test
public void should_be_sorted_by_line_length() {
DuplicationLineReader reader = new DuplicationLineReader(newArrayList(
DuplicationLineReader reader = new DuplicationLineReader(Iterators.forArray(
BatchReport.Duplication.newBuilder()
.setOriginPosition(BatchReport.Range.newBuilder()
.setStartLine(1)

+ 39
- 39
server/sonar-server/src/test/java/org/sonar/server/computation/source/SymbolsLineReaderTest.java View File

@@ -20,13 +20,13 @@

package org.sonar.server.computation.source;

import java.util.Collections;
import java.util.List;
import org.junit.Test;
import org.sonar.batch.protocol.output.BatchReport;
import org.sonar.core.util.CloseableIterator;
import org.sonar.server.source.db.FileSourceDb;

import java.util.Collections;
import java.util.List;

import static com.google.common.collect.Lists.newArrayList;
import static org.assertj.core.api.Assertions.assertThat;

@@ -40,7 +40,7 @@ public class SymbolsLineReaderTest {

@Test
public void read_nothing() {
SymbolsLineReader symbolsLineReader = new SymbolsLineReader(Collections.<BatchReport.Symbols.Symbol>emptyList());
SymbolsLineReader symbolsLineReader = new SymbolsLineReader(CloseableIterator.<BatchReport.Symbol>emptyCloseableIterator());

symbolsLineReader.read(line1);

@@ -49,8 +49,8 @@ public class SymbolsLineReaderTest {

@Test
public void read_symbols() {
List<BatchReport.Symbols.Symbol> symbols = newArrayList(
BatchReport.Symbols.Symbol.newBuilder()
List<BatchReport.Symbol> symbols = newArrayList(
BatchReport.Symbol.newBuilder()
.setDeclaration(BatchReport.Range.newBuilder()
.setStartLine(1).setEndLine(1).setStartOffset(2).setEndOffset(4)
.build())
@@ -60,7 +60,7 @@ public class SymbolsLineReaderTest {
.build()
);

SymbolsLineReader symbolsLineReader = new SymbolsLineReader(symbols);
SymbolsLineReader symbolsLineReader = new SymbolsLineReader(symbols.iterator());
symbolsLineReader.read(line1);
symbolsLineReader.read(line2);
symbolsLineReader.read(line3);
@@ -72,8 +72,8 @@ public class SymbolsLineReaderTest {

@Test
public void read_symbols_with_reference_on_same_line() {
List<BatchReport.Symbols.Symbol> symbols = newArrayList(
BatchReport.Symbols.Symbol.newBuilder()
List<BatchReport.Symbol> symbols = newArrayList(
BatchReport.Symbol.newBuilder()
.setDeclaration(BatchReport.Range.newBuilder()
.setStartLine(1).setEndLine(1).setStartOffset(0).setEndOffset(1)
.build())
@@ -83,7 +83,7 @@ public class SymbolsLineReaderTest {
.build()
);

SymbolsLineReader symbolsLineReader = new SymbolsLineReader(symbols);
SymbolsLineReader symbolsLineReader = new SymbolsLineReader(symbols.iterator());
symbolsLineReader.read(line1);

assertThat(line1.getSymbols()).isEqualTo("0,1,1;2,3,1");
@@ -91,8 +91,8 @@ public class SymbolsLineReaderTest {

@Test
public void read_symbols_with_two_references() {
List<BatchReport.Symbols.Symbol> symbols = newArrayList(
BatchReport.Symbols.Symbol.newBuilder()
List<BatchReport.Symbol> symbols = newArrayList(
BatchReport.Symbol.newBuilder()
.setDeclaration(BatchReport.Range.newBuilder()
.setStartLine(1).setEndLine(1).setStartOffset(2).setEndOffset(4)
.build())
@@ -105,7 +105,7 @@ public class SymbolsLineReaderTest {
.build()
);

SymbolsLineReader symbolsLineReader = new SymbolsLineReader(symbols);
SymbolsLineReader symbolsLineReader = new SymbolsLineReader(symbols.iterator());
symbolsLineReader.read(line1);
symbolsLineReader.read(line2);
symbolsLineReader.read(line3);
@@ -117,8 +117,8 @@ public class SymbolsLineReaderTest {

@Test
public void read_symbols_with_two_references_on_the_same_line() {
List<BatchReport.Symbols.Symbol> symbols = newArrayList(
BatchReport.Symbols.Symbol.newBuilder()
List<BatchReport.Symbol> symbols = newArrayList(
BatchReport.Symbol.newBuilder()
.setDeclaration(BatchReport.Range.newBuilder()
.setStartLine(1).setEndLine(1).setStartOffset(2).setEndOffset(3)
.build())
@@ -129,9 +129,9 @@ public class SymbolsLineReaderTest {
.setStartLine(2).setEndLine(2).setStartOffset(2).setEndOffset(3)
.build())
.build()
);
);

SymbolsLineReader symbolsLineReader = new SymbolsLineReader(symbols);
SymbolsLineReader symbolsLineReader = new SymbolsLineReader(symbols.iterator());
symbolsLineReader.read(line1);
symbolsLineReader.read(line2);

@@ -141,8 +141,8 @@ public class SymbolsLineReaderTest {

@Test
public void read_symbols_when_reference_line_is_before_declaration_line() {
List<BatchReport.Symbols.Symbol> symbols = newArrayList(
BatchReport.Symbols.Symbol.newBuilder()
List<BatchReport.Symbol> symbols = newArrayList(
BatchReport.Symbol.newBuilder()
.setDeclaration(BatchReport.Range.newBuilder()
.setStartLine(2).setEndLine(2).setStartOffset(3).setEndOffset(4)
.build())
@@ -152,7 +152,7 @@ public class SymbolsLineReaderTest {
.build()
);

SymbolsLineReader symbolsLineReader = new SymbolsLineReader(symbols);
SymbolsLineReader symbolsLineReader = new SymbolsLineReader(symbols.iterator());
symbolsLineReader.read(line1);
symbolsLineReader.read(line2);

@@ -162,8 +162,8 @@ public class SymbolsLineReaderTest {

@Test
public void read_many_symbols_on_lines() {
List<BatchReport.Symbols.Symbol> symbols = newArrayList(
BatchReport.Symbols.Symbol.newBuilder()
List<BatchReport.Symbol> symbols = newArrayList(
BatchReport.Symbol.newBuilder()
.setDeclaration(BatchReport.Range.newBuilder()
.setStartLine(1).setEndLine(1).setStartOffset(1).setEndOffset(2)
.build())
@@ -171,7 +171,7 @@ public class SymbolsLineReaderTest {
.setStartLine(3).setEndLine(3).setStartOffset(2).setEndOffset(3)
.build())
.build(),
BatchReport.Symbols.Symbol.newBuilder()
BatchReport.Symbol.newBuilder()
.setDeclaration(BatchReport.Range.newBuilder()
.setStartLine(1).setEndLine(1).setStartOffset(3).setEndOffset(4)
.build())
@@ -181,7 +181,7 @@ public class SymbolsLineReaderTest {
.build()
);

SymbolsLineReader symbolsLineReader = new SymbolsLineReader(symbols);
SymbolsLineReader symbolsLineReader = new SymbolsLineReader(symbols.iterator());
symbolsLineReader.read(line1);
symbolsLineReader.read(line2);
symbolsLineReader.read(line3);
@@ -193,8 +193,8 @@ public class SymbolsLineReaderTest {

@Test
public void symbol_declaration_should_be_sorted_by_offset() {
List<BatchReport.Symbols.Symbol> symbols = newArrayList(
BatchReport.Symbols.Symbol.newBuilder()
List<BatchReport.Symbol> symbols = newArrayList(
BatchReport.Symbol.newBuilder()
.setDeclaration(BatchReport.Range.newBuilder()
// This symbol begins after the second symbol, it should appear in second place
.setStartLine(1).setEndLine(1).setStartOffset(2).setEndOffset(3)
@@ -203,7 +203,7 @@ public class SymbolsLineReaderTest {
.setStartLine(3).setEndLine(3).setStartOffset(2).setEndOffset(3)
.build())
.build(),
BatchReport.Symbols.Symbol.newBuilder()
BatchReport.Symbol.newBuilder()
.setDeclaration(BatchReport.Range.newBuilder()
.setStartLine(1).setEndLine(1).setStartOffset(0).setEndOffset(1)
.build())
@@ -212,7 +212,7 @@ public class SymbolsLineReaderTest {
.build())
.build());

SymbolsLineReader symbolsLineReader = new SymbolsLineReader(symbols);
SymbolsLineReader symbolsLineReader = new SymbolsLineReader(symbols.iterator());
symbolsLineReader.read(line1);
symbolsLineReader.read(line2);
symbolsLineReader.read(line3);
@@ -224,8 +224,8 @@ public class SymbolsLineReaderTest {

@Test
public void symbol_declaration_should_be_sorted_by_line() {
List<BatchReport.Symbols.Symbol> symbols = newArrayList(
BatchReport.Symbols.Symbol.newBuilder()
List<BatchReport.Symbol> symbols = newArrayList(
BatchReport.Symbol.newBuilder()
.setDeclaration(BatchReport.Range.newBuilder()
// This symbol begins after the second symbol, it should appear in second place
.setStartLine(2).setEndLine(2).setStartOffset(0).setEndOffset(1)
@@ -234,7 +234,7 @@ public class SymbolsLineReaderTest {
.setStartLine(3).setEndLine(3).setStartOffset(2).setEndOffset(3)
.build())
.build(),
BatchReport.Symbols.Symbol.newBuilder()
BatchReport.Symbol.newBuilder()
.setDeclaration(BatchReport.Range.newBuilder()
.setStartLine(1).setEndLine(1).setStartOffset(0).setEndOffset(1)
.build())
@@ -243,7 +243,7 @@ public class SymbolsLineReaderTest {
.build())
.build());

SymbolsLineReader symbolsLineReader = new SymbolsLineReader(symbols);
SymbolsLineReader symbolsLineReader = new SymbolsLineReader(symbols.iterator());
symbolsLineReader.read(line1);
symbolsLineReader.read(line2);
symbolsLineReader.read(line3);
@@ -255,8 +255,8 @@ public class SymbolsLineReaderTest {

@Test
public void read_symbols_defined_on_many_lines() {
List<BatchReport.Symbols.Symbol> symbols = newArrayList(
BatchReport.Symbols.Symbol.newBuilder()
List<BatchReport.Symbol> symbols = newArrayList(
BatchReport.Symbol.newBuilder()
.setDeclaration(BatchReport.Range.newBuilder()
.setStartLine(1).setEndLine(2).setStartOffset(1).setEndOffset(3)
.build())
@@ -265,7 +265,7 @@ public class SymbolsLineReaderTest {
.build())
.build());

SymbolsLineReader symbolsLineReader = new SymbolsLineReader(symbols);
SymbolsLineReader symbolsLineReader = new SymbolsLineReader(symbols.iterator());
symbolsLineReader.read(line1);
symbolsLineReader.read(line2);
symbolsLineReader.read(line3);
@@ -279,8 +279,8 @@ public class SymbolsLineReaderTest {

@Test
public void read_symbols_declared_on_a_whole_line() {
List<BatchReport.Symbols.Symbol> symbols = newArrayList(
BatchReport.Symbols.Symbol.newBuilder()
List<BatchReport.Symbol> symbols = newArrayList(
BatchReport.Symbol.newBuilder()
.setDeclaration(BatchReport.Range.newBuilder()
.setStartLine(1).setEndLine(2).setStartOffset(0).setEndOffset(0)
.build())
@@ -288,9 +288,9 @@ public class SymbolsLineReaderTest {
.setStartLine(3).setEndLine(3).setStartOffset(1).setEndOffset(3)
.build())
.build()
);
);

SymbolsLineReader symbolsLineReader = new SymbolsLineReader(symbols);
SymbolsLineReader symbolsLineReader = new SymbolsLineReader(symbols.iterator());
symbolsLineReader.read(line1);
symbolsLineReader.read(line2);
symbolsLineReader.read(line3);

+ 73
- 0
server/sonar-server/src/test/java/org/sonar/server/computation/step/FeedActiveRulesStepTest.java View File

@@ -0,0 +1,73 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* SonarQube is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.computation.step;

import com.google.common.base.Optional;
import java.util.Arrays;
import org.assertj.core.data.MapEntry;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.Severity;
import org.sonar.batch.protocol.Constants;
import org.sonar.batch.protocol.output.BatchReport;
import org.sonar.server.computation.batch.BatchReportReaderRule;
import org.sonar.server.computation.qualityprofile.ActiveRule;
import org.sonar.server.computation.qualityprofile.ActiveRulesHolderImpl;

import static org.assertj.core.api.Assertions.assertThat;

public class FeedActiveRulesStepTest {

@Rule
public TemporaryFolder temp = new TemporaryFolder();

@Rule
public BatchReportReaderRule batchReportReader = new BatchReportReaderRule();

ActiveRulesHolderImpl activeRulesHolder = new ActiveRulesHolderImpl();
FeedActiveRulesStep underTest = new FeedActiveRulesStep(batchReportReader, activeRulesHolder);

@Test
public void write() throws Exception {
BatchReport.ActiveRule.Builder batch1 = BatchReport.ActiveRule.newBuilder()
.setRuleRepository("java").setRuleKey("S001")
.setSeverity(Constants.Severity.BLOCKER);
batch1.addParamBuilder().setKey("p1").setValue("v1").build();

BatchReport.ActiveRule.Builder batch2 = BatchReport.ActiveRule.newBuilder()
.setRuleRepository("java").setRuleKey("S002").setSeverity(Constants.Severity.MAJOR);
batchReportReader.putActiveRules(Arrays.asList(batch1.build(), batch2.build()));

underTest.execute();

assertThat(activeRulesHolder.getAll()).hasSize(2);
Optional<ActiveRule> ar1 = activeRulesHolder.get(RuleKey.of("java", "S001"));
assertThat(ar1.get().getSeverity()).isEqualTo(Severity.BLOCKER);
assertThat(ar1.get().getParams()).containsExactly(MapEntry.entry("p1", "v1"));
Optional<ActiveRule> ar2 = activeRulesHolder.get(RuleKey.of("java", "S002"));
assertThat(ar2.get().getSeverity()).isEqualTo(Severity.MAJOR);
assertThat(ar2.get().getParams()).isEmpty();

}
}

+ 1
- 1
server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistFileSourcesStepTest.java View File

@@ -243,7 +243,7 @@ public class PersistFileSourcesStepTest extends BaseStepTest {
initBasicReport(3);

reportReader.putSymbols(FILE_REF, newArrayList(
BatchReport.Symbols.Symbol.newBuilder()
BatchReport.Symbol.newBuilder()
.setDeclaration(BatchReport.Range.newBuilder()
.setStartLine(1).setEndLine(1).setStartOffset(2).setEndOffset(4)
.build())

+ 1
- 1
server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistIssuesStepTest.java View File

@@ -85,7 +85,7 @@ public class PersistIssuesStepTest extends BaseStepTest {
when(system2.now()).thenReturn(NOW);
reportReader.setMetadata(BatchReport.Metadata.getDefaultInstance());

step = new PersistIssuesStep(dbClient, system2, new UpdateConflictResolver(), new RuleRepositoryImpl(new RuleCacheLoader(dbClient, reportReader)), issueCache);
step = new PersistIssuesStep(dbClient, system2, new UpdateConflictResolver(), new RuleRepositoryImpl(new RuleCacheLoader(dbClient)), issueCache);
}

@After

+ 1
- 1
server/sonar-server/src/test/java/org/sonar/server/util/cache/DiskCacheTest.java View File

@@ -23,7 +23,7 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.utils.System2;
import org.sonar.server.util.CloseableIterator;
import org.sonar.core.util.CloseableIterator;

import java.io.ObjectOutputStream;
import java.io.Serializable;

+ 4
- 0
sonar-batch-protocol/pom.xml View File

@@ -34,6 +34,10 @@
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
<dependency>
<groupId>org.codehaus.sonar</groupId>
<artifactId>sonar-core</artifactId>
</dependency>

<!-- unit tests -->
<dependency>

+ 9012
- 10644
sonar-batch-protocol/src/main/gen-java/org/sonar/batch/protocol/output/BatchReport.java
File diff suppressed because it is too large
View File


+ 50
- 19
sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/ProtobufUtil.java View File

@@ -19,72 +19,103 @@
*/
package org.sonar.batch.protocol;

import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.Message;
import com.google.protobuf.Parser;
import org.apache.commons.io.IOUtils;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.apache.commons.io.IOUtils;
import org.sonar.core.util.CloseableIterator;

import static java.lang.String.format;

public class ProtobufUtil {
private ProtobufUtil() {
// only static stuff
}

public static <T extends Message> T readFile(File file, Parser<T> parser) {
/**
* Returns the message contained in the given file. Throws an unchecked exception
* if the file does not exist or is empty.
*/
public static <MSG extends Message> MSG readFile(File file, Parser<MSG> parser) {
InputStream input = null;
try {
input = new BufferedInputStream(new FileInputStream(file));
return parser.parseFrom(input);
} catch (IOException e) {
throw new IllegalStateException("Failed to read file: " + file, e);
throw new IllegalStateException(format("Unable to read file %s", file), e);
} finally {
IOUtils.closeQuietly(input);
}
}

/**
* Writes a single message to a file, by replacing existing content. The message is
* NOT appended.
*/
public static void writeToFile(Message message, File toFile) {
OutputStream out = null;
try {
out = new BufferedOutputStream(new FileOutputStream(toFile, false));
message.writeTo(out);
} catch (IOException e) {
throw new IllegalStateException("Unable to write protocol buffer data to file " + toFile, e);
throw new IllegalStateException(format("Unable to write protobuf message to file %s", toFile), e);
} finally {
IOUtils.closeQuietly(out);
}
}

public static void appendToFile(Message message, File toFile) {
public static void writeStreamToFile(Iterable<? extends Message> messages, File toFile, boolean append) {
OutputStream out = null;
try {
out = new BufferedOutputStream(new FileOutputStream(toFile, true));
message.writeDelimitedTo(out);
out = new BufferedOutputStream(new FileOutputStream(toFile, append));
for (Message message : messages) {
message.writeDelimitedTo(out);
}
} catch (IOException e) {
throw new IllegalStateException("Unable to append protocol buffer data to file " + toFile, e);
throw new IllegalStateException(format("Unable to write protobuf messages to file %s", toFile), e);
} finally {
IOUtils.closeQuietly(out);
}
}

public static <MESSAGE extends Message> void writeMessagesToFile(Iterable<MESSAGE> messages, File file) {
OutputStream out = null;
public static <MSG extends Message> CloseableIterator<MSG> readStreamFromFile(File file, Parser<MSG> parser) {
try {
out = new BufferedOutputStream(new FileOutputStream(file, true));
for (MESSAGE message : messages) {
message.writeDelimitedTo(out);
}
} catch (IOException e) {
throw new IllegalStateException("Failed to read file: " + file, e);
} finally {
IOUtils.closeQuietly(out);
return new ProtobufIterator<>(parser, new BufferedInputStream(new FileInputStream(file)));
} catch (FileNotFoundException e) {
throw new IllegalStateException(format("Unable to read protobuf file %s", file), e);
}
}

private static class ProtobufIterator<MSG extends Message> extends CloseableIterator<MSG> {
private final Parser<MSG> parser;
private final InputStream input;

private ProtobufIterator(Parser<MSG> parser, InputStream input) {
this.parser = parser;
this.input = input;
}

@Override
protected MSG doNext() {
try {
return parser.parseDelimitedFrom(input);
} catch (InvalidProtocolBufferException e) {
throw new IllegalStateException(e);
}
}

@Override
protected void doClose() throws Exception {
IOUtils.closeQuietly(input);
}
}
}

+ 34
- 35
sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/BatchReportReader.java View File

@@ -20,10 +20,9 @@
package org.sonar.batch.protocol.output;

import java.io.File;
import java.util.Collections;
import java.util.List;
import javax.annotation.CheckForNull;
import org.sonar.batch.protocol.ProtobufUtil;
import org.sonar.core.util.CloseableIterator;

public class BatchReportReader {

@@ -35,26 +34,32 @@ public class BatchReportReader {

public BatchReport.Metadata readMetadata() {
File file = fileStructure.metadataFile();
if (!doesFileExists(file)) {
if (!fileExists(file)) {
throw new IllegalStateException("Metadata file is missing in analysis report: " + file);
}
return ProtobufUtil.readFile(file, BatchReport.Metadata.PARSER);
}

public List<BatchReport.Measure> readComponentMeasures(int componentRef) {
public CloseableIterator<BatchReport.ActiveRule> readActiveRules() {
File file = fileStructure.activeRules();
if (!fileExists(file)) {
return CloseableIterator.emptyCloseableIterator();
}
return ProtobufUtil.readStreamFromFile(file, BatchReport.ActiveRule.PARSER);
}

public CloseableIterator<BatchReport.Measure> readComponentMeasures(int componentRef) {
File file = fileStructure.fileFor(FileStructure.Domain.MEASURES, componentRef);
if (doesFileExists(file)) {
// all the measures are loaded in memory
BatchReport.Measures measures = ProtobufUtil.readFile(file, BatchReport.Measures.PARSER);
return measures.getMeasureList();
if (fileExists(file)) {
return ProtobufUtil.readStreamFromFile(file, BatchReport.Measure.PARSER);
}
return Collections.emptyList();
return CloseableIterator.emptyCloseableIterator();
}

@CheckForNull
public BatchReport.Changesets readChangesets(int componentRef) {
File file = fileStructure.fileFor(FileStructure.Domain.CHANGESETS, componentRef);
if (doesFileExists(file)) {
if (fileExists(file)) {
return ProtobufUtil.readFile(file, BatchReport.Changesets.PARSER);
}
return null;
@@ -62,40 +67,34 @@ public class BatchReportReader {

public BatchReport.Component readComponent(int componentRef) {
File file = fileStructure.fileFor(FileStructure.Domain.COMPONENT, componentRef);
if (!doesFileExists(file)) {
if (!fileExists(file)) {
throw new IllegalStateException("Unable to find report for component #" + componentRef + ". File does not exist: " + file);
}
return ProtobufUtil.readFile(file, BatchReport.Component.PARSER);
}

public List<BatchReport.Issue> readComponentIssues(int componentRef) {
public CloseableIterator<BatchReport.Issue> readComponentIssues(int componentRef) {
File file = fileStructure.fileFor(FileStructure.Domain.ISSUES, componentRef);
if (doesFileExists(file)) {
// all the issues are loaded in memory
BatchReport.Issues issues = ProtobufUtil.readFile(file, BatchReport.Issues.PARSER);
return issues.getIssueList();
if (fileExists(file)) {
return ProtobufUtil.readStreamFromFile(file, BatchReport.Issue.PARSER);
}
return Collections.emptyList();
return CloseableIterator.emptyCloseableIterator();
}

public List<BatchReport.Duplication> readComponentDuplications(int componentRef) {
public CloseableIterator<BatchReport.Duplication> readComponentDuplications(int componentRef) {
File file = fileStructure.fileFor(FileStructure.Domain.DUPLICATIONS, componentRef);
if (doesFileExists(file)) {
// all the duplications are loaded in memory
BatchReport.Duplications duplications = ProtobufUtil.readFile(file, BatchReport.Duplications.PARSER);
return duplications.getDuplicationList();
if (fileExists(file)) {
return ProtobufUtil.readStreamFromFile(file, BatchReport.Duplication.PARSER);
}
return Collections.emptyList();
return CloseableIterator.emptyCloseableIterator();
}

public List<BatchReport.Symbols.Symbol> readComponentSymbols(int componentRef) {
public CloseableIterator<BatchReport.Symbol> readComponentSymbols(int componentRef) {
File file = fileStructure.fileFor(FileStructure.Domain.SYMBOLS, componentRef);
if (doesFileExists(file)) {
// all the symbols are loaded in memory
BatchReport.Symbols symbols = ProtobufUtil.readFile(file, BatchReport.Symbols.PARSER);
return symbols.getSymbolList();
if (fileExists(file)) {
return ProtobufUtil.readStreamFromFile(file, BatchReport.Symbol.PARSER);
}
return Collections.emptyList();
return CloseableIterator.emptyCloseableIterator();
}

public boolean hasSyntaxHighlighting(int componentRef) {
@@ -106,7 +105,7 @@ public class BatchReportReader {
@CheckForNull
public File readComponentSyntaxHighlighting(int fileRef) {
File file = fileStructure.fileFor(FileStructure.Domain.SYNTAX_HIGHLIGHTINGS, fileRef);
if (doesFileExists(file)) {
if (fileExists(file)) {
return file;
}
return null;
@@ -115,7 +114,7 @@ public class BatchReportReader {
@CheckForNull
public File readComponentCoverage(int fileRef) {
File file = fileStructure.fileFor(FileStructure.Domain.COVERAGES, fileRef);
if (doesFileExists(file)) {
if (fileExists(file)) {
return file;
}
return null;
@@ -123,7 +122,7 @@ public class BatchReportReader {

public File readFileSource(int fileRef) {
File file = fileStructure.fileFor(FileStructure.Domain.SOURCE, fileRef);
if (!doesFileExists(file)) {
if (!fileExists(file)) {
throw new IllegalStateException("Unable to find source for file #" + fileRef + ". File does not exist: " + file);
}
return file;
@@ -132,7 +131,7 @@ public class BatchReportReader {
@CheckForNull
public File readTests(int testFileRef) {
File file = fileStructure.fileFor(FileStructure.Domain.TESTS, testFileRef);
if (doesFileExists(file)) {
if (fileExists(file)) {
return file;
}

@@ -142,14 +141,14 @@ public class BatchReportReader {
@CheckForNull
public File readCoverageDetails(int testFileRef) {
File file = fileStructure.fileFor(FileStructure.Domain.COVERAGE_DETAILS, testFileRef);
if (doesFileExists(file)) {
if (fileExists(file)) {
return file;
}

return null;
}

private static boolean doesFileExists(File file) {
private static boolean fileExists(File file) {
return file.exists() && file.isFile();
}
}

+ 14
- 21
sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/BatchReportWriter.java View File

@@ -50,6 +50,11 @@ public class BatchReportWriter {
return fileStructure.metadataFile();
}

public File writeActiveRules(Iterable<BatchReport.ActiveRule> activeRules) {
ProtobufUtil.writeStreamToFile(activeRules, fileStructure.activeRules(), false);
return fileStructure.metadataFile();
}

public File writeComponent(BatchReport.Component component) {
File file = fileStructure.fileFor(FileStructure.Domain.COMPONENT, component.getRef());
ProtobufUtil.writeToFile(component, file);
@@ -57,20 +62,14 @@ public class BatchReportWriter {
}

public File writeComponentIssues(int componentRef, Iterable<BatchReport.Issue> issues) {
BatchReport.Issues.Builder issuesBuilder = BatchReport.Issues.newBuilder();
issuesBuilder.setComponentRef(componentRef);
issuesBuilder.addAllIssue(issues);
File file = fileStructure.fileFor(FileStructure.Domain.ISSUES, componentRef);
ProtobufUtil.writeToFile(issuesBuilder.build(), file);
ProtobufUtil.writeStreamToFile(issues, file, false);
return file;
}

public File writeComponentMeasures(int componentRef, Iterable<BatchReport.Measure> measures) {
BatchReport.Measures.Builder measuresBuilder = BatchReport.Measures.newBuilder();
measuresBuilder.setComponentRef(componentRef);
measuresBuilder.addAllMeasure(measures);
File file = fileStructure.fileFor(FileStructure.Domain.MEASURES, componentRef);
ProtobufUtil.writeToFile(measuresBuilder.build(), file);
ProtobufUtil.writeStreamToFile(measures, file, false);
return file;
}

@@ -81,44 +80,38 @@ public class BatchReportWriter {
}

public File writeComponentDuplications(int componentRef, Iterable<BatchReport.Duplication> duplications) {
BatchReport.Duplications.Builder builder = BatchReport.Duplications.newBuilder();
builder.setComponentRef(componentRef);
builder.addAllDuplication(duplications);
File file = fileStructure.fileFor(FileStructure.Domain.DUPLICATIONS, componentRef);
ProtobufUtil.writeToFile(builder.build(), file);
ProtobufUtil.writeStreamToFile(duplications, file, false);
return file;
}

public File writeComponentSymbols(int componentRef, Iterable<BatchReport.Symbols.Symbol> symbols) {
BatchReport.Symbols.Builder builder = BatchReport.Symbols.newBuilder();
builder.setFileRef(componentRef);
builder.addAllSymbol(symbols);
public File writeComponentSymbols(int componentRef, Iterable<BatchReport.Symbol> symbols) {
File file = fileStructure.fileFor(FileStructure.Domain.SYMBOLS, componentRef);
ProtobufUtil.writeToFile(builder.build(), file);
ProtobufUtil.writeStreamToFile(symbols, file, false);
return file;
}

public File writeComponentSyntaxHighlighting(int componentRef, Iterable<BatchReport.SyntaxHighlighting> syntaxHighlightingRules) {
File file = fileStructure.fileFor(FileStructure.Domain.SYNTAX_HIGHLIGHTINGS, componentRef);
ProtobufUtil.writeMessagesToFile(syntaxHighlightingRules, file);
ProtobufUtil.writeStreamToFile(syntaxHighlightingRules, file, false);
return file;
}

public File writeComponentCoverage(int componentRef, Iterable<BatchReport.Coverage> coverageList) {
File file = fileStructure.fileFor(FileStructure.Domain.COVERAGES, componentRef);
ProtobufUtil.writeMessagesToFile(coverageList, file);
ProtobufUtil.writeStreamToFile(coverageList, file, false);
return file;
}

public File writeTests(int componentRef, Iterable<BatchReport.Test> tests) {
File file = fileStructure.fileFor(FileStructure.Domain.TESTS, componentRef);
ProtobufUtil.writeMessagesToFile(tests, file);
ProtobufUtil.writeStreamToFile(tests, file, false);
return file;
}

public File writeCoverageDetails(int componentRef, Iterable<BatchReport.CoverageDetail> tests) {
File file = fileStructure.fileFor(FileStructure.Domain.COVERAGE_DETAILS, componentRef);
ProtobufUtil.writeMessagesToFile(tests, file);
ProtobufUtil.writeStreamToFile(tests, file, false);
return file;
}


+ 4
- 0
sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/FileStructure.java View File

@@ -62,6 +62,10 @@ public class FileStructure {
return new File(dir, "metadata.pb");
}

public File activeRules() {
return new File(dir, "activerules.pb");
}

public File fileFor(Domain domain, int componentRef) {
return new File(dir, domain.filePrefix + componentRef + domain.fileSuffix);
}

+ 10
- 34
sonar-batch-protocol/src/main/protobuf/batch_report.proto View File

@@ -47,19 +47,17 @@ message Metadata {
optional int32 root_component_ref = 4;
}

message ActiveRuleParameter {
optional string key = 1;
optional string value = 2;
}

/*
The rules that are enabled in the Quality profiles associated with the project
*/
message ActiveRule {
optional string rule_repository = 1;
optional string rule_key = 2;
optional Severity severity = 3;
repeated ActiveRuleParameter parameter = 4;
repeated ActiveRuleParam param = 4;

// TODO replace by map
message ActiveRuleParam {
optional string key = 1;
optional string value = 2;
}
}

message ComponentLink {
@@ -107,12 +105,6 @@ message Measure {
optional int32 person_id = 20;
}

/* TODO to be removed. It prevents streaming */
message Measures {
optional int32 component_ref = 1;
repeated Measure measure = 2;
}

message Issue {
optional string rule_repository = 1;
optional string rule_key = 2;
@@ -124,12 +116,6 @@ message Issue {
optional string attributes = 8;
}

/* TODO to be removed. It prevents streaming */
message Issues {
optional int32 component_ref = 1;
repeated Issue issue = 2;
}

message Changesets {
optional int32 component_ref = 1;
repeated Changeset changeset = 2;
@@ -158,11 +144,6 @@ message Duplication {
repeated Duplicate duplicate = 2;
}

message Duplications {
optional int32 component_ref = 1;
repeated Duplication duplication = 2;
}

// Lines start at 1 and line offsets start at 0
message Range {
// Should never be null
@@ -175,14 +156,9 @@ message Range {
optional int32 end_offset = 4;
}

message Symbols {
optional int32 file_ref = 1;
repeated Symbol symbol = 2;

message Symbol {
optional Range declaration = 1;
repeated Range reference = 2;
}
message Symbol {
optional Range declaration = 1;
repeated Range reference = 2;
}

// Only FILE component has coverage information, and only executable lines should contains this information.

+ 37
- 0
sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/ProtobufUtilTest.java View File

@@ -19,16 +19,53 @@
*/
package org.sonar.batch.protocol;

import java.io.File;
import org.apache.commons.io.FileUtils;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import org.sonar.batch.protocol.output.BatchReport;
import org.sonar.test.TestUtils;

import static org.assertj.core.api.Assertions.assertThat;

public class ProtobufUtilTest {

@Rule
public ExpectedException thrown = ExpectedException.none();

@Rule
public TemporaryFolder temp = new TemporaryFolder();

@Test
public void only_utils() {
assertThat(TestUtils.hasOnlyPrivateConstructors(ProtobufUtil.class));
}

@Test
public void readFile_fails_if_file_does_not_exist() throws Exception {
thrown.expect(IllegalStateException.class);

File file = temp.newFile();
FileUtils.forceDelete(file);
ProtobufUtil.readFile(file, BatchReport.Metadata.PARSER);
}

@Test
public void readFile_returns_empty_message_if_file_is_empty() throws Exception {
File file = temp.newFile();
BatchReport.Metadata msg = ProtobufUtil.readFile(file, BatchReport.Metadata.PARSER);
assertThat(msg).isNotNull();
assertThat(msg.isInitialized()).isTrue();
}

@Test
public void readFile_returns_message() throws Exception {
File file = temp.newFile();
ProtobufUtil.writeToFile(BatchReport.Metadata.getDefaultInstance(), file);
BatchReport.Metadata message = ProtobufUtil.readFile(file, BatchReport.Metadata.PARSER);
assertThat(message).isNotNull();
assertThat(message.isInitialized()).isTrue();
}
}

+ 33
- 38
sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/BatchReportReaderTest.java View File

@@ -42,12 +42,12 @@ public class BatchReportReaderTest {

File dir;

BatchReportReader underTest;
BatchReportReader sut;

@Before
public void setUp() throws Exception {
dir = temp.newFolder();
underTest = new BatchReportReader(dir);
sut = new BatchReportReader(dir);
}

@Test
@@ -59,7 +59,7 @@ public class BatchReportReaderTest {
.setRootComponentRef(1);
writer.writeMetadata(metadata.build());

BatchReport.Metadata readMetadata = underTest.readMetadata();
BatchReport.Metadata readMetadata = sut.readMetadata();
assertThat(readMetadata.getAnalysisDate()).isEqualTo(15000000L);
assertThat(readMetadata.getProjectKey()).isEqualTo("PROJECT_A");
assertThat(readMetadata.getRootComponentRef()).isEqualTo(1);
@@ -67,7 +67,7 @@ public class BatchReportReaderTest {

@Test(expected = IllegalStateException.class)
public void fail_if_missing_metadata_file() {
underTest.readMetadata();
sut.readMetadata();
}

@Test
@@ -78,12 +78,12 @@ public class BatchReportReaderTest {
.setPath("src/main/java/Foo.java");
writer.writeComponent(component.build());

assertThat(underTest.readComponent(1).getPath()).isEqualTo("src/main/java/Foo.java");
assertThat(sut.readComponent(1).getPath()).isEqualTo("src/main/java/Foo.java");
}

@Test(expected = IllegalStateException.class)
public void fail_if_missing_file_on_component() {
underTest.readComponent(UNKNOWN_COMPONENT_REF);
sut.readComponent(UNKNOWN_COMPONENT_REF);
}

@Test
@@ -94,13 +94,13 @@ public class BatchReportReaderTest {
.build();
writer.writeComponentIssues(1, Arrays.asList(issue));

assertThat(underTest.readComponentIssues(1)).hasSize(1);
assertThat(underTest.readComponentIssues(200)).isEmpty();
assertThat(sut.readComponentIssues(1)).hasSize(1);
assertThat(sut.readComponentIssues(200)).isEmpty();
}

@Test
public void empty_list_if_no_issue_found() {
assertThat(underTest.readComponentIssues(UNKNOWN_COMPONENT_REF)).isEmpty();
assertThat(sut.readComponentIssues(UNKNOWN_COMPONENT_REF)).isEmpty();
}

@Test
@@ -110,13 +110,12 @@ public class BatchReportReaderTest {
.setStringValue("value_a");
writer.writeComponentMeasures(1, Arrays.asList(measure.build()));

assertThat(underTest.readComponentMeasures(1)).hasSize(1);
assertThat(underTest.readComponentMeasures(1).get(0).getStringValue()).isEqualTo("value_a");
assertThat(sut.readComponentMeasures(1)).hasSize(1);
}

@Test
public void empty_list_if_no_measure_found() {
assertThat(underTest.readComponentMeasures(UNKNOWN_COMPONENT_REF)).isEmpty();
assertThat(sut.readComponentMeasures(UNKNOWN_COMPONENT_REF)).isEmpty();
}

@Test
@@ -127,13 +126,13 @@ public class BatchReportReaderTest {
.addChangeset(BatchReport.Changesets.Changeset.newBuilder().setDate(123_456_789).setAuthor("jack.daniels").setRevision("123-456-789"));
writer.writeComponentChangesets(scm.build());

assertThat(underTest.readChangesets(1).getChangesetList()).hasSize(1);
assertThat(underTest.readChangesets(1).getChangeset(0).getDate()).isEqualTo(123_456_789L);
assertThat(sut.readChangesets(1).getChangesetList()).hasSize(1);
assertThat(sut.readChangesets(1).getChangeset(0).getDate()).isEqualTo(123_456_789L);
}

@Test
public void null_if_no_changeset_found() {
assertThat(underTest.readChangesets(UNKNOWN_COMPONENT_REF)).isNull();
assertThat(sut.readChangesets(UNKNOWN_COMPONENT_REF)).isNull();
}

@Test
@@ -160,15 +159,13 @@ public class BatchReportReaderTest {
.build();
writer.writeComponentDuplications(1, Arrays.asList(duplication));

BatchReportReader underTest = new BatchReportReader(dir);
assertThat(underTest.readComponentDuplications(1)).hasSize(1);
assertThat(underTest.readComponentDuplications(1).get(0).getOriginPosition()).isNotNull();
assertThat(underTest.readComponentDuplications(1).get(0).getDuplicateList()).hasSize(1);
BatchReportReader sut = new BatchReportReader(dir);
assertThat(sut.readComponentDuplications(1)).hasSize(1);
}

@Test
public void empty_list_if_no_duplication_found() {
assertThat(underTest.readComponentDuplications(UNKNOWN_COMPONENT_REF)).isEmpty();
assertThat(sut.readComponentDuplications(UNKNOWN_COMPONENT_REF)).isEmpty();
}

@Test
@@ -188,9 +185,9 @@ public class BatchReportReaderTest {
.build())
.setType(Constants.HighlightingType.ANNOTATION)
.build()
));
));

try (InputStream inputStream = FileUtils.openInputStream(underTest.readComponentSyntaxHighlighting(1))) {
try (InputStream inputStream = FileUtils.openInputStream(sut.readComponentSyntaxHighlighting(1))) {
BatchReport.SyntaxHighlighting syntaxHighlighting = BatchReport.SyntaxHighlighting.PARSER.parseDelimitedFrom(inputStream);
assertThat(syntaxHighlighting.getRange()).isNotNull();
assertThat(syntaxHighlighting.getRange().getStartLine()).isEqualTo(1);
@@ -201,7 +198,7 @@ public class BatchReportReaderTest {

@Test
public void return_null_if_no_highlighting_found() {
assertThat(underTest.readComponentSyntaxHighlighting(UNKNOWN_COMPONENT_REF)).isNull();
assertThat(sut.readComponentSyntaxHighlighting(UNKNOWN_COMPONENT_REF)).isNull();
}

@Test
@@ -213,7 +210,7 @@ public class BatchReportReaderTest {
writer.writeComponent(BatchReport.Component.newBuilder()
.setRef(1).build());

writer.writeComponentSymbols(1, Arrays.asList(BatchReport.Symbols.Symbol.newBuilder()
writer.writeComponentSymbols(1, Arrays.asList(BatchReport.Symbol.newBuilder()
.setDeclaration(BatchReport.Range.newBuilder()
.setStartLine(1)
.setStartOffset(3)
@@ -228,15 +225,13 @@ public class BatchReportReaderTest {
.build())
.build()));

underTest = new BatchReportReader(dir);
assertThat(underTest.readComponentSymbols(1)).hasSize(1);
assertThat(underTest.readComponentSymbols(1).get(0).getDeclaration().getStartLine()).isEqualTo(1);
assertThat(underTest.readComponentSymbols(1).get(0).getReference(0).getStartLine()).isEqualTo(10);
sut = new BatchReportReader(dir);
assertThat(sut.readComponentSymbols(1)).hasSize(1);
}

@Test
public void empty_list_if_no_symbol_found() {
assertThat(underTest.readComponentSymbols(UNKNOWN_COMPONENT_REF)).isEmpty();
assertThat(sut.readComponentSymbols(UNKNOWN_COMPONENT_REF)).isEmpty();
}

@Test
@@ -268,7 +263,7 @@ public class BatchReportReaderTest {
.setOverallCoveredConditions(5)
.build()));

underTest = new BatchReportReader(dir);
sut = new BatchReportReader(dir);

try (InputStream inputStream = FileUtils.openInputStream(new BatchReportReader(dir).readComponentCoverage(1))) {
BatchReport.Coverage coverage = BatchReport.Coverage.PARSER.parseDelimitedFrom(inputStream);
@@ -293,7 +288,7 @@ public class BatchReportReaderTest {

@Test
public void return_null_if_no_coverage_found() {
assertThat(underTest.readComponentCoverage(UNKNOWN_COMPONENT_REF)).isNull();
assertThat(sut.readComponentCoverage(UNKNOWN_COMPONENT_REF)).isNull();
}

@Test
@@ -317,7 +312,7 @@ public class BatchReportReaderTest {
.setStatus(Constants.TestStatus.OK)
.build()));

try (InputStream inputStream = FileUtils.openInputStream(underTest.readTests(1))) {
try (InputStream inputStream = FileUtils.openInputStream(sut.readTests(1))) {
BatchReport.Test testResult = BatchReport.Test.PARSER.parseDelimitedFrom(inputStream);
assertThat(testResult.getDurationInMs()).isEqualTo(60_000);
assertThat(testResult.getStacktrace()).isEqualTo("stacktrace");
@@ -328,7 +323,7 @@ public class BatchReportReaderTest {

@Test
public void null_if_no_test_found() {
assertThat(underTest.readTests(UNKNOWN_COMPONENT_REF)).isNull();
assertThat(sut.readTests(UNKNOWN_COMPONENT_REF)).isNull();
}

@Test
@@ -338,13 +333,13 @@ public class BatchReportReaderTest {
BatchReport.CoverageDetail.newBuilder()
.setTestName("test-name")
.addCoveredFile(BatchReport.CoverageDetail.CoveredFile.newBuilder()
.addAllCoveredLine(Arrays.asList(1, 2, 3, 5, 7))
.setFileRef(2)
.addAllCoveredLine(Arrays.asList(1, 2, 3, 5, 7))
.setFileRef(2)
)
.build()
));
));

try (InputStream inputStream = FileUtils.openInputStream(underTest.readCoverageDetails(1))) {
try (InputStream inputStream = FileUtils.openInputStream(sut.readCoverageDetails(1))) {
BatchReport.CoverageDetail coverageDetail = BatchReport.CoverageDetail.PARSER.parseDelimitedFrom(inputStream);
assertThat(coverageDetail.getTestName()).isEqualTo("test-name");
assertThat(coverageDetail.getCoveredFile(0).getFileRef()).isEqualTo(2);
@@ -354,7 +349,7 @@ public class BatchReportReaderTest {

@Test
public void null_if_no_coverage_detail_found() {
assertThat(underTest.readCoverageDetails(UNKNOWN_COMPONENT_REF)).isNull();
assertThat(sut.readCoverageDetails(UNKNOWN_COMPONENT_REF)).isNull();
}

}

+ 19
- 24
sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/output/BatchReportWriterTest.java View File

@@ -19,6 +19,9 @@
*/
package org.sonar.batch.protocol.output;

import com.google.common.collect.Iterators;
import java.io.File;
import java.util.Arrays;
import org.apache.commons.io.FileUtils;
import org.junit.Before;
import org.junit.Rule;
@@ -27,9 +30,7 @@ import org.junit.rules.TemporaryFolder;
import org.sonar.batch.protocol.Constants;
import org.sonar.batch.protocol.ProtobufUtil;
import org.sonar.batch.protocol.output.BatchReport.Range;

import java.io.File;
import java.util.Arrays;
import org.sonar.core.util.CloseableIterator;

import static org.assertj.core.api.Assertions.assertThat;

@@ -110,9 +111,9 @@ public class BatchReportWriterTest {
assertThat(underTest.hasComponentData(FileStructure.Domain.ISSUES, 1)).isTrue();
File file = underTest.getFileStructure().fileFor(FileStructure.Domain.ISSUES, 1);
assertThat(file).exists().isFile();
BatchReport.Issues read = ProtobufUtil.readFile(file, BatchReport.Issues.PARSER);
assertThat(read.getComponentRef()).isEqualTo(1);
assertThat(read.getIssueCount()).isEqualTo(1);
try (CloseableIterator<BatchReport.Issue> read = ProtobufUtil.readStreamFromFile(file, BatchReport.Issue.PARSER)) {
assertThat(Iterators.size(read)).isEqualTo(1);
}
}

@Test
@@ -131,13 +132,9 @@ public class BatchReportWriterTest {
assertThat(underTest.hasComponentData(FileStructure.Domain.MEASURES, 1)).isTrue();
File file = underTest.getFileStructure().fileFor(FileStructure.Domain.MEASURES, 1);
assertThat(file).exists().isFile();
BatchReport.Measures measures = ProtobufUtil.readFile(file, BatchReport.Measures.PARSER);
assertThat(measures.getComponentRef()).isEqualTo(1);
assertThat(measures.getMeasureCount()).isEqualTo(1);
assertThat(measures.getMeasure(0).getStringValue()).isEqualTo("text-value");
assertThat(measures.getMeasure(0).getDoubleValue()).isEqualTo(2.5d);
assertThat(measures.getMeasure(0).getValueType()).isEqualTo(Constants.MeasureValueType.DOUBLE);
assertThat(measures.getMeasure(0).getDescription()).isEqualTo("description");
try (CloseableIterator<BatchReport.Measure> read = ProtobufUtil.readStreamFromFile(file, BatchReport.Measure.PARSER)) {
assertThat(Iterators.size(read)).isEqualTo(1);
}
}

@Test
@@ -188,11 +185,11 @@ public class BatchReportWriterTest {
assertThat(underTest.hasComponentData(FileStructure.Domain.DUPLICATIONS, 1)).isTrue();
File file = underTest.getFileStructure().fileFor(FileStructure.Domain.DUPLICATIONS, 1);
assertThat(file).exists().isFile();
BatchReport.Duplications duplications = ProtobufUtil.readFile(file, BatchReport.Duplications.PARSER);
assertThat(duplications.getComponentRef()).isEqualTo(1);
assertThat(duplications.getDuplicationList()).hasSize(1);
assertThat(duplications.getDuplication(0).getOriginPosition()).isNotNull();
assertThat(duplications.getDuplication(0).getDuplicateList()).hasSize(1);
try (CloseableIterator<BatchReport.Duplication> duplications = ProtobufUtil.readStreamFromFile(file, BatchReport.Duplication.PARSER)) {
BatchReport.Duplication dup = duplications.next();
assertThat(dup.getOriginPosition()).isNotNull();
assertThat(dup.getDuplicateList()).hasSize(1);
}
}

@Test
@@ -201,7 +198,7 @@ public class BatchReportWriterTest {
assertThat(underTest.hasComponentData(FileStructure.Domain.SYMBOLS, 1)).isFalse();

// write data
BatchReport.Symbols.Symbol symbol = BatchReport.Symbols.Symbol.newBuilder()
BatchReport.Symbol symbol = BatchReport.Symbol.newBuilder()
.setDeclaration(BatchReport.Range.newBuilder()
.setStartLine(1)
.setStartOffset(3)
@@ -222,11 +219,9 @@ public class BatchReportWriterTest {

File file = underTest.getFileStructure().fileFor(FileStructure.Domain.SYMBOLS, 1);
assertThat(file).exists().isFile();
BatchReport.Symbols read = ProtobufUtil.readFile(file, BatchReport.Symbols.PARSER);
assertThat(read.getFileRef()).isEqualTo(1);
assertThat(read.getSymbolList()).hasSize(1);
assertThat(read.getSymbol(0).getDeclaration().getStartLine()).isEqualTo(1);
assertThat(read.getSymbol(0).getReference(0).getStartLine()).isEqualTo(10);
try (CloseableIterator<BatchReport.Symbol> read = ProtobufUtil.readStreamFromFile(file, BatchReport.Symbol.PARSER)) {
assertThat(read).hasSize(1);
}
}

@Test

+ 21
- 23
sonar-batch/src/main/java/org/sonar/batch/mediumtest/TaskResult.java View File

@@ -22,6 +22,17 @@ package org.sonar.batch.mediumtest;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import java.io.File;
import java.io.InputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
@@ -37,36 +48,24 @@ import org.sonar.api.batch.sensor.duplication.Duplication;
import org.sonar.api.batch.sensor.highlighting.TypeOfText;
import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure;
import org.sonar.api.issue.Issue;
import org.sonar.core.issue.DefaultIssue;
import org.sonar.api.measures.Measure;
import org.sonar.batch.duplication.DuplicationCache;
import org.sonar.batch.index.Cache.Entry;
import org.sonar.batch.index.BatchComponentCache;
import org.sonar.batch.index.Cache.Entry;
import org.sonar.batch.issue.IssueCache;
import org.sonar.batch.protocol.output.BatchReport;
import org.sonar.batch.protocol.output.BatchReport.Component;
import org.sonar.batch.protocol.output.BatchReport.Metadata;
import org.sonar.batch.protocol.output.BatchReport.Range;
import org.sonar.batch.protocol.output.BatchReport.Symbols.Symbol;
import org.sonar.batch.protocol.output.BatchReport.Symbol;
import org.sonar.batch.protocol.output.BatchReportReader;
import org.sonar.batch.report.BatchReportUtils;
import org.sonar.batch.report.ReportPublisher;
import org.sonar.batch.scan.ProjectScanContainer;
import org.sonar.batch.scan.filesystem.InputPathCache;
import org.sonar.batch.scan.measure.MeasureCache;

import javax.annotation.CheckForNull;
import javax.annotation.Nullable;

import java.io.File;
import java.io.InputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.sonar.core.issue.DefaultIssue;
import org.sonar.core.util.CloseableIterator;

public class TaskResult implements org.sonar.batch.mediumtest.ScanTaskObserver {

@@ -237,13 +236,12 @@ public class TaskResult implements org.sonar.batch.mediumtest.ScanTaskObserver {
@CheckForNull
public List<Range> symbolReferencesFor(InputFile file, int symbolStartLine, int symbolStartLineOffset) {
int ref = reportComponents.get(((DefaultInputFile) file).key()).getRef();
List<Symbol> symbols = getReportReader().readComponentSymbols(ref);
if (symbols.isEmpty()) {
return Collections.emptyList();
}
for (Symbol symbol : symbols) {
if (symbol.getDeclaration().getStartLine() == symbolStartLine && symbol.getDeclaration().getStartOffset() == symbolStartLineOffset) {
return symbol.getReferenceList();
try (CloseableIterator<Symbol> symbols = getReportReader().readComponentSymbols(ref)) {
while (symbols.hasNext()) {
Symbol symbol = symbols.next();
if (symbol.getDeclaration().getStartLine() == symbolStartLine && symbol.getDeclaration().getStartOffset() == symbolStartLineOffset) {
return symbol.getReferenceList();
}
}
}
return Collections.emptyList();

+ 62
- 0
sonar-batch/src/main/java/org/sonar/batch/report/ActiveRulesPublisher.java View File

@@ -0,0 +1,62 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* SonarQube is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.batch.report;

import com.google.common.base.Function;
import com.google.common.collect.FluentIterable;
import java.util.Map;
import javax.annotation.Nonnull;
import org.sonar.api.batch.rule.ActiveRule;
import org.sonar.api.batch.rule.ActiveRules;
import org.sonar.batch.protocol.Constants;
import org.sonar.batch.protocol.output.BatchReport;
import org.sonar.batch.protocol.output.BatchReportWriter;

public class ActiveRulesPublisher implements ReportPublisherStep {

private final ActiveRules activeRules;

public ActiveRulesPublisher(ActiveRules activeRules) {
this.activeRules = activeRules;
}

@Override
public void publish(BatchReportWriter writer) {
Iterable<BatchReport.ActiveRule> activeRuleMessages = FluentIterable.from(activeRules.findAll()).transform(new ToMessage());
writer.writeActiveRules(activeRuleMessages);
}

private class ToMessage implements Function<ActiveRule, BatchReport.ActiveRule> {
private final BatchReport.ActiveRule.Builder builder = BatchReport.ActiveRule.newBuilder();

@Override
public BatchReport.ActiveRule apply(@Nonnull ActiveRule input) {
builder.clear();
builder.setRuleRepository(input.ruleKey().repository());
builder.setRuleKey(input.ruleKey().rule());
builder.setSeverity(Constants.Severity.valueOf(input.severity()));
for (Map.Entry<String, String> entry : input.params().entrySet()) {
builder.addParamBuilder().setKey(entry.getKey()).setValue(entry.getValue()).build();

}
return builder.build();
}
}
}

+ 1
- 19
sonar-batch/src/main/java/org/sonar/batch/report/MetadataPublisher.java View File

@@ -19,12 +19,8 @@
*/
package org.sonar.batch.report;

import com.google.common.base.Function;
import javax.annotation.Nonnull;
import org.sonar.api.CoreProperties;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.rule.ActiveRule;
import org.sonar.api.batch.rule.ActiveRules;
import org.sonar.api.resources.Project;
import org.sonar.batch.index.BatchComponent;
import org.sonar.batch.index.BatchComponentCache;
@@ -32,18 +28,14 @@ import org.sonar.batch.protocol.output.BatchReport;
import org.sonar.batch.protocol.output.BatchReportWriter;
import org.sonar.batch.scan.ImmutableProjectReactor;

import static com.google.common.collect.FluentIterable.from;

public class MetadataPublisher implements ReportPublisherStep {

private final BatchComponentCache componentCache;
private final ImmutableProjectReactor reactor;
private final ActiveRules activeRules;

public MetadataPublisher(BatchComponentCache componentCache, ImmutableProjectReactor reactor, ActiveRules activeRules) {
public MetadataPublisher(BatchComponentCache componentCache, ImmutableProjectReactor reactor) {
this.componentCache = componentCache;
this.reactor = reactor;
this.activeRules = activeRules;
}

@Override
@@ -59,16 +51,6 @@ public class MetadataPublisher implements ReportPublisherStep {
if (branch != null) {
builder.setBranch(branch);
}
builder.addAllActiveRuleKey(from(activeRules.findAll()).transform(ToRuleKey.INSTANCE));
writer.writeMetadata(builder.build());
}

private enum ToRuleKey implements Function<ActiveRule, String> {
INSTANCE;
@Nonnull
@Override
public String apply(@Nonnull ActiveRule input) {
return input.ruleKey().toString();
}
}
}

+ 2
- 0
sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java View File

@@ -54,6 +54,7 @@ import org.sonar.batch.issue.tracking.ServerIssueRepository;
import org.sonar.batch.mediumtest.ScanTaskObservers;
import org.sonar.batch.phases.PhasesTimeProfiler;
import org.sonar.batch.profiling.PhasesSumUpTimeProfiler;
import org.sonar.batch.report.ActiveRulesPublisher;
import org.sonar.batch.report.ComponentsPublisher;
import org.sonar.batch.report.CoveragePublisher;
import org.sonar.batch.report.DuplicationsPublisher;
@@ -184,6 +185,7 @@ public class ProjectScanContainer extends ComponentContainer {
// Report
ReportPublisher.class,
MetadataPublisher.class,
ActiveRulesPublisher.class,
ComponentsPublisher.class,
IssuesPublisher.class,
MeasuresPublisher.class,

+ 3
- 3
sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorStorage.java View File

@@ -200,12 +200,12 @@ public class DefaultSensorStorage implements SensorStorage {
public void store(DefaultInputFile inputFile, Map<Symbol, Set<TextRange>> referencesBySymbol) {
BatchReportWriter writer = reportPublisher.getWriter();
writer.writeComponentSymbols(resourceCache.get(inputFile).batchId(),
Iterables.transform(referencesBySymbol.entrySet(), new Function<Map.Entry<Symbol, Set<TextRange>>, BatchReport.Symbols.Symbol>() {
private BatchReport.Symbols.Symbol.Builder builder = BatchReport.Symbols.Symbol.newBuilder();
Iterables.transform(referencesBySymbol.entrySet(), new Function<Map.Entry<Symbol, Set<TextRange>>, BatchReport.Symbol>() {
private BatchReport.Symbol.Builder builder = BatchReport.Symbol.newBuilder();
private Range.Builder rangeBuilder = Range.newBuilder();

@Override
public BatchReport.Symbols.Symbol apply(Map.Entry<Symbol, Set<TextRange>> input) {
public BatchReport.Symbol apply(Map.Entry<Symbol, Set<TextRange>> input) {
builder.clear();
rangeBuilder.clear();
DefaultSymbol symbol = (DefaultSymbol) input.getKey();

+ 70
- 0
sonar-batch/src/test/java/org/sonar/batch/report/ActiveRulesPublisherTest.java View File

@@ -0,0 +1,70 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* SonarQube is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.batch.report;

import java.io.File;
import java.util.Arrays;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.rule.ActiveRules;
import org.sonar.api.batch.rule.Severity;
import org.sonar.api.batch.rule.internal.ActiveRulesBuilder;
import org.sonar.api.batch.rule.internal.DefaultActiveRules;
import org.sonar.api.batch.rule.internal.NewActiveRule;
import org.sonar.api.rule.RuleKey;
import org.sonar.batch.protocol.Constants;
import org.sonar.batch.protocol.output.BatchReport;
import org.sonar.batch.protocol.output.BatchReportReader;
import org.sonar.batch.protocol.output.BatchReportWriter;
import org.sonar.core.util.CloseableIterator;

import static org.assertj.core.api.Assertions.assertThat;

public class ActiveRulesPublisherTest {

@Rule
public TemporaryFolder temp = new TemporaryFolder();

@Test
public void write() throws Exception {
File outputDir = temp.newFolder();
BatchReportWriter writer = new BatchReportWriter(outputDir);

NewActiveRule ar = new ActiveRulesBuilder().create(RuleKey.of("java", "S001")).setSeverity("BLOCKER").setParam("p1", "v1");
ActiveRules activeRules = new DefaultActiveRules(Arrays.asList(ar));

ActiveRulesPublisher underTest = new ActiveRulesPublisher(activeRules);
underTest.publish(writer);

BatchReportReader reader = new BatchReportReader(outputDir);
try (CloseableIterator<BatchReport.ActiveRule> readIt = reader.readActiveRules()) {
BatchReport.ActiveRule reportAr = readIt.next();
assertThat(reportAr.getRuleRepository()).isEqualTo("java");
assertThat(reportAr.getRuleKey()).isEqualTo("S001");
assertThat(reportAr.getSeverity()).isEqualTo(Constants.Severity.BLOCKER);
assertThat(reportAr.getParamCount()).isEqualTo(1);
assertThat(reportAr.getParam(0).getKey()).isEqualTo("p1");
assertThat(reportAr.getParam(0).getValue()).isEqualTo("v1");

assertThat(readIt.hasNext()).isFalse();
}
}
}

+ 29
- 25
sonar-batch/src/test/java/org/sonar/batch/report/DuplicationsPublisherTest.java View File

@@ -28,6 +28,7 @@ import org.sonar.api.batch.sensor.duplication.internal.DefaultDuplication;
import org.sonar.api.resources.Project;
import org.sonar.batch.duplication.DuplicationCache;
import org.sonar.batch.index.BatchComponentCache;
import org.sonar.batch.protocol.output.BatchReport;
import org.sonar.batch.protocol.output.BatchReportReader;
import org.sonar.batch.protocol.output.BatchReportWriter;

@@ -35,6 +36,7 @@ import java.io.File;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.sonar.core.util.CloseableIterator;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Matchers.anyString;
@@ -85,31 +87,33 @@ public class DuplicationsPublisherTest {
BatchReportReader reader = new BatchReportReader(outputDir);

assertThat(reader.readComponentDuplications(1)).hasSize(0);
List<org.sonar.batch.protocol.output.BatchReport.Duplication> componentDuplications = reader.readComponentDuplications(2);
assertThat(componentDuplications).hasSize(3);
org.sonar.batch.protocol.output.BatchReport.Duplication savedDup1 = componentDuplications.get(0);
assertThat(savedDup1.getOriginPosition().getStartLine()).isEqualTo(1);
assertThat(savedDup1.getOriginPosition().getEndLine()).isEqualTo(10);
assertThat(savedDup1.getDuplicate(0).hasOtherFileKey()).isFalse();
assertThat(savedDup1.getDuplicate(0).hasOtherFileRef()).isFalse();
assertThat(savedDup1.getDuplicate(0).getRange().getStartLine()).isEqualTo(20);
assertThat(savedDup1.getDuplicate(0).getRange().getEndLine()).isEqualTo(50);

org.sonar.batch.protocol.output.BatchReport.Duplication savedDup2 = componentDuplications.get(1);
assertThat(savedDup2.getOriginPosition().getStartLine()).isEqualTo(11);
assertThat(savedDup2.getOriginPosition().getEndLine()).isEqualTo(20);
assertThat(savedDup2.getDuplicate(0).getOtherFileKey()).isEqualTo("another");
assertThat(savedDup2.getDuplicate(0).hasOtherFileRef()).isFalse();
assertThat(savedDup2.getDuplicate(0).getRange().getStartLine()).isEqualTo(20);
assertThat(savedDup2.getDuplicate(0).getRange().getEndLine()).isEqualTo(50);

org.sonar.batch.protocol.output.BatchReport.Duplication savedDup3 = componentDuplications.get(2);
assertThat(savedDup3.getOriginPosition().getStartLine()).isEqualTo(11);
assertThat(savedDup3.getOriginPosition().getEndLine()).isEqualTo(20);
assertThat(savedDup3.getDuplicate(0).hasOtherFileKey()).isFalse();
assertThat(savedDup3.getDuplicate(0).getOtherFileRef()).isEqualTo(3);
assertThat(savedDup3.getDuplicate(0).getRange().getStartLine()).isEqualTo(20);
assertThat(savedDup3.getDuplicate(0).getRange().getEndLine()).isEqualTo(50);
try (CloseableIterator<BatchReport.Duplication> componentDuplications = reader.readComponentDuplications(2)) {
org.sonar.batch.protocol.output.BatchReport.Duplication savedDup1 = componentDuplications.next();
assertThat(savedDup1.getOriginPosition().getStartLine()).isEqualTo(1);
assertThat(savedDup1.getOriginPosition().getEndLine()).isEqualTo(10);
assertThat(savedDup1.getDuplicate(0).hasOtherFileKey()).isFalse();
assertThat(savedDup1.getDuplicate(0).hasOtherFileRef()).isFalse();
assertThat(savedDup1.getDuplicate(0).getRange().getStartLine()).isEqualTo(20);
assertThat(savedDup1.getDuplicate(0).getRange().getEndLine()).isEqualTo(50);

org.sonar.batch.protocol.output.BatchReport.Duplication savedDup2 = componentDuplications.next();
assertThat(savedDup2.getOriginPosition().getStartLine()).isEqualTo(11);
assertThat(savedDup2.getOriginPosition().getEndLine()).isEqualTo(20);
assertThat(savedDup2.getDuplicate(0).getOtherFileKey()).isEqualTo("another");
assertThat(savedDup2.getDuplicate(0).hasOtherFileRef()).isFalse();
assertThat(savedDup2.getDuplicate(0).getRange().getStartLine()).isEqualTo(20);
assertThat(savedDup2.getDuplicate(0).getRange().getEndLine()).isEqualTo(50);

org.sonar.batch.protocol.output.BatchReport.Duplication savedDup3 = componentDuplications.next();
assertThat(savedDup3.getOriginPosition().getStartLine()).isEqualTo(11);
assertThat(savedDup3.getOriginPosition().getEndLine()).isEqualTo(20);
assertThat(savedDup3.getDuplicate(0).hasOtherFileKey()).isFalse();
assertThat(savedDup3.getDuplicate(0).getOtherFileRef()).isEqualTo(3);
assertThat(savedDup3.getDuplicate(0).getRange().getStartLine()).isEqualTo(20);
assertThat(savedDup3.getDuplicate(0).getRange().getEndLine()).isEqualTo(50);

assertThat(componentDuplications.hasNext()).isFalse();
}

}


+ 5
- 5
sonar-batch/src/test/java/org/sonar/batch/report/MeasuresPublisherTest.java View File

@@ -22,7 +22,6 @@ package org.sonar.batch.report;
import java.io.File;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -35,9 +34,11 @@ import org.sonar.api.measures.MetricFinder;
import org.sonar.api.resources.Project;
import org.sonar.api.resources.Resource;
import org.sonar.batch.index.BatchComponentCache;
import org.sonar.batch.protocol.output.BatchReport;
import org.sonar.batch.protocol.output.BatchReportReader;
import org.sonar.batch.protocol.output.BatchReportWriter;
import org.sonar.batch.scan.measure.MeasureCache;
import org.sonar.core.util.CloseableIterator;

import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.assertThat;
@@ -112,10 +113,9 @@ public class MeasuresPublisherTest {
BatchReportReader reader = new BatchReportReader(outputDir);

assertThat(reader.readComponentMeasures(1)).hasSize(0);
List<org.sonar.batch.protocol.output.BatchReport.Measure> componentMeasures = reader.readComponentMeasures(2);
assertThat(componentMeasures).hasSize(6);
assertThat(componentMeasures.get(0).getDoubleValue()).isEqualTo(2.0);
assertThat(componentMeasures.get(0).getPersonId()).isEqualTo(2);
try (CloseableIterator<BatchReport.Measure> componentMeasures = reader.readComponentMeasures(2)) {
assertThat(componentMeasures).hasSize(6);
}

}


+ 1
- 8
sonar-batch/src/test/java/org/sonar/batch/report/MetadataPublisherTest.java View File

@@ -20,7 +20,6 @@
package org.sonar.batch.report;

import java.io.File;
import java.util.Collections;
import java.util.Date;
import org.junit.Before;
import org.junit.Rule;
@@ -28,9 +27,6 @@ import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.CoreProperties;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.rule.ActiveRules;
import org.sonar.api.batch.rule.internal.DefaultActiveRules;
import org.sonar.api.batch.rule.internal.NewActiveRule;
import org.sonar.api.resources.Project;
import org.sonar.batch.index.BatchComponentCache;
import org.sonar.batch.protocol.output.BatchReport;
@@ -45,7 +41,6 @@ public class MetadataPublisherTest {
@Rule
public TemporaryFolder temp = new TemporaryFolder();

ActiveRules activeRules = new DefaultActiveRules(Collections.<NewActiveRule>emptyList());
ProjectDefinition projectDef;
Project project;

@@ -59,12 +54,11 @@ public class MetadataPublisherTest {
org.sonar.api.resources.Resource sampleFile = org.sonar.api.resources.File.create("src/Foo.php").setEffectiveKey("foo:src/Foo.php");
componentCache.add(project, null);
componentCache.add(sampleFile, project);
underTest = new MetadataPublisher(componentCache, new ImmutableProjectReactor(projectDef), activeRules);
underTest = new MetadataPublisher(componentCache, new ImmutableProjectReactor(projectDef));
}

@Test
public void write_metadata() throws Exception {

File outputDir = temp.newFolder();
BatchReportWriter writer = new BatchReportWriter(outputDir);

@@ -74,7 +68,6 @@ public class MetadataPublisherTest {
BatchReport.Metadata metadata = reader.readMetadata();
assertThat(metadata.getAnalysisDate()).isEqualTo(1234567L);
assertThat(metadata.getProjectKey()).isEqualTo("foo");

}

@Test

+ 8
- 2
sonar-core/src/main/java/org/sonar/core/issue/DefaultIssue.java View File

@@ -265,8 +265,14 @@ public class DefaultIssue implements Issue, Trackable {
}

public DefaultIssue setEffortToFix(@Nullable Double d) {
Preconditions.checkArgument(d == null || d >= 0, "Effort to fix must be greater than or equal 0 (got " + d + ")");
this.effortToFix = d;
//Preconditions.checkArgument(d == null || d >= 0, "Effort to fix must be greater than or equal 0 (got " + d + ")");
if (d != null) {
// FIXME this is temp hack while Decorator are not dropped (Comment Density common-rule is buggy as
// the measure comment_line_density is compute by CE)
this.effortToFix = Math.max(d, 0.0);
} else {
this.effortToFix = null;
}
return this;
}


server/sonar-server/src/main/java/org/sonar/server/util/CloseableIterator.java → sonar-core/src/main/java/org/sonar/core/util/CloseableIterator.java View File

@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.util;
package org.sonar.core.util;

import com.google.common.base.Throwables;
import java.util.Iterator;

server/sonar-server/src/test/java/org/sonar/server/util/CloseableIteratorTest.java → sonar-core/src/test/java/org/sonar/core/util/CloseableIteratorTest.java View File

@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.util;
package org.sonar.core.util;

import java.io.IOException;
import java.util.Collections;

Loading…
Cancel
Save