From 5b93180b18e756c6a246b8d22307785d333d0002 Mon Sep 17 00:00:00 2001 From: Julien HENRY Date: Wed, 29 Jul 2015 01:45:49 +0200 Subject: [PATCH] Write raw issues directly in protobuf report Avoid intermediate storage in persistit --- .../protocol/output/BatchReportWriter.java | 13 ++ .../sonar/batch/issue/DefaultIssuable.java | 22 +-- .../sonar/batch/issue/IssuableFactory.java | 6 +- .../org/sonar/batch/issue/IssueFilters.java | 4 +- .../org/sonar/batch/issue/ModuleIssues.java | 81 +++++++- .../batch/issue/tracking/IssueTracking.java | 180 +++++++++--------- .../issue/tracking/IssueTrackingResult.java | 20 +- .../issue/tracking/LocalIssueTracking.java | 132 +++++++++---- .../sonar/batch/mediumtest/TaskResult.java | 21 +- .../sonar/batch/report/IssuesPublisher.java | 84 -------- .../batch/scan/ProjectScanContainer.java | 2 - .../batch/sensor/DefaultSensorStorage.java | 28 +-- .../batch/issue/DefaultIssuableTest.java | 64 ------- .../batch/issue/IssuableFactoryTest.java | 6 +- .../sonar/batch/issue/ModuleIssuesTest.java | 123 ++++++------ .../deprecated/DeprecatedApiMediumTest.java | 20 +- .../fs/ProjectBuilderMediumTest.java | 40 ++-- .../fs/RandomFsAccessMediumTest.java | 18 +- .../mediumtest/issues/ChecksMediumTest.java | 27 ++- .../mediumtest/issues/IssuesMediumTest.java | 75 +++----- .../issues/IssuesOnDirMediumTest.java | 12 +- .../issues/MultilineIssuesMediumTest.java | 10 +- .../mediumtest/preview/EmptyFileTest.java | 2 +- .../preview/IncrementalModeMediumTest.java | 38 ++-- .../preview/PreviewAndReportsMediumTest.java | 62 ++++-- .../batch/report/IssuesPublisherTest.java | 106 ----------- .../sensor/DefaultSensorStorageTest.java | 71 ------- .../java/org/sonar/api/issue/Issuable.java | 10 +- .../java/org/sonar/api/issue/IssueFilter.java | 4 +- 29 files changed, 526 insertions(+), 755 deletions(-) delete mode 100644 sonar-batch/src/main/java/org/sonar/batch/report/IssuesPublisher.java delete mode 100644 sonar-batch/src/test/java/org/sonar/batch/issue/DefaultIssuableTest.java delete mode 100644 sonar-batch/src/test/java/org/sonar/batch/report/IssuesPublisherTest.java diff --git a/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/BatchReportWriter.java b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/BatchReportWriter.java index bf0cdfcd736..8c68fa7fce5 100644 --- a/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/BatchReportWriter.java +++ b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/BatchReportWriter.java @@ -19,7 +19,11 @@ */ package org.sonar.batch.protocol.output; +import java.io.BufferedOutputStream; import java.io.File; +import java.io.FileOutputStream; +import java.io.OutputStream; +import org.sonar.core.util.ContextException; import org.sonar.core.util.Protobuf; public class BatchReportWriter { @@ -67,6 +71,15 @@ public class BatchReportWriter { return file; } + public void appendComponentIssue(int componentRef, BatchReport.Issue issue) { + File file = fileStructure.fileFor(FileStructure.Domain.ISSUES, componentRef); + try (OutputStream out = new BufferedOutputStream(new FileOutputStream(file, true))) { + issue.writeDelimitedTo(out); + } catch (Exception e) { + throw ContextException.of("Unable to write issue", e).addContext("file", file); + } + } + public File writeComponentMeasures(int componentRef, Iterable measures) { File file = fileStructure.fileFor(FileStructure.Domain.MEASURES, componentRef); Protobuf.writeStream(measures, file, false); diff --git a/sonar-batch/src/main/java/org/sonar/batch/issue/DefaultIssuable.java b/sonar-batch/src/main/java/org/sonar/batch/issue/DefaultIssuable.java index 76970b5c80f..c2639e7cfba 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/issue/DefaultIssuable.java +++ b/sonar-batch/src/main/java/org/sonar/batch/issue/DefaultIssuable.java @@ -19,7 +19,7 @@ */ package org.sonar.batch.issue; -import com.google.common.collect.Lists; +import java.util.Collections; import java.util.List; import org.sonar.api.batch.sensor.SensorContext; import org.sonar.api.batch.sensor.issue.internal.DefaultIssue; @@ -32,13 +32,11 @@ import org.sonar.batch.index.BatchComponent; */ public class DefaultIssuable implements Issuable { - private final IssueCache cache; private final BatchComponent component; private final SensorContext sensorContext; - DefaultIssuable(BatchComponent component, IssueCache cache, SensorContext sensorContext) { + DefaultIssuable(BatchComponent component, SensorContext sensorContext) { this.component = component; - this.cache = cache; this.sensorContext = sensorContext; } @@ -56,24 +54,12 @@ public class DefaultIssuable implements Issuable { @Override public List resolvedIssues() { - List result = Lists.newArrayList(); - for (org.sonar.core.issue.DefaultIssue issue : cache.byComponent(component.key())) { - if (issue.resolution() != null) { - result.add(issue); - } - } - return result; + return Collections.emptyList(); } @Override public List issues() { - List result = Lists.newArrayList(); - for (org.sonar.core.issue.DefaultIssue issue : cache.byComponent(component.key())) { - if (issue.resolution() == null) { - result.add(issue); - } - } - return result; + return Collections.emptyList(); } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/issue/IssuableFactory.java b/sonar-batch/src/main/java/org/sonar/batch/issue/IssuableFactory.java index 6425abaca60..62767bd49e2 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/issue/IssuableFactory.java +++ b/sonar-batch/src/main/java/org/sonar/batch/issue/IssuableFactory.java @@ -31,17 +31,15 @@ import org.sonar.batch.sensor.DefaultSensorContext; */ public class IssuableFactory extends PerspectiveBuilder { - private final IssueCache cache; private final SensorContext sensorContext; - public IssuableFactory(IssueCache cache, DefaultSensorContext sensorContext) { + public IssuableFactory(DefaultSensorContext sensorContext) { super(Issuable.class); - this.cache = cache; this.sensorContext = sensorContext; } @Override public Issuable loadPerspective(Class perspectiveClass, BatchComponent component) { - return new DefaultIssuable(component, cache, sensorContext); + return new DefaultIssuable(component, sensorContext); } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/issue/IssueFilters.java b/sonar-batch/src/main/java/org/sonar/batch/issue/IssueFilters.java index 70bd4d54d5b..203e495d01a 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/issue/IssueFilters.java +++ b/sonar-batch/src/main/java/org/sonar/batch/issue/IssueFilters.java @@ -20,8 +20,8 @@ package org.sonar.batch.issue; import org.sonar.api.batch.BatchSide; +import org.sonar.api.issue.Issue; import org.sonar.api.issue.batch.IssueFilter; -import org.sonar.core.issue.DefaultIssue; @BatchSide public class IssueFilters { @@ -46,7 +46,7 @@ public class IssueFilters { this(new org.sonar.api.issue.IssueFilter[0], new IssueFilter[0]); } - public boolean accept(DefaultIssue issue) { + public boolean accept(Issue issue) { if (new DefaultIssueFilterChain(filters).accept(issue)) { // Apply deprecated rules only if filter chain accepts the current issue for (org.sonar.api.issue.IssueFilter filter : exclusionFilters) { diff --git a/sonar-batch/src/main/java/org/sonar/batch/issue/ModuleIssues.java b/sonar-batch/src/main/java/org/sonar/batch/issue/ModuleIssues.java index a27b4c272a3..d74fef6dcb0 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/issue/ModuleIssues.java +++ b/sonar-batch/src/main/java/org/sonar/batch/issue/ModuleIssues.java @@ -21,13 +21,23 @@ package org.sonar.batch.issue; import com.google.common.base.Strings; import javax.annotation.Nullable; +import org.sonar.api.batch.fs.InputPath; +import org.sonar.api.batch.fs.TextRange; import org.sonar.api.batch.rule.ActiveRule; import org.sonar.api.batch.rule.ActiveRules; import org.sonar.api.batch.rule.Rule; import org.sonar.api.batch.rule.Rules; +import org.sonar.api.batch.rule.Severity; +import org.sonar.api.batch.sensor.issue.Issue; import org.sonar.api.resources.Project; import org.sonar.api.rule.RuleKey; +import org.sonar.api.utils.KeyValueFormat; import org.sonar.api.utils.MessageException; +import org.sonar.batch.index.BatchComponent; +import org.sonar.batch.index.BatchComponentCache; +import org.sonar.batch.protocol.Constants; +import org.sonar.batch.protocol.output.BatchReport; +import org.sonar.batch.report.ReportPublisher; import org.sonar.core.issue.DefaultIssue; /** @@ -37,35 +47,88 @@ public class ModuleIssues { private final ActiveRules activeRules; private final Rules rules; - private final IssueCache cache; private final Project project; private final IssueFilters filters; + private final ReportPublisher reportPublisher; + private final BatchComponentCache componentCache; + private final BatchReport.Issue.Builder builder = BatchReport.Issue.newBuilder(); - public ModuleIssues(ActiveRules activeRules, Rules rules, IssueCache cache, Project project, IssueFilters filters) { + public ModuleIssues(ActiveRules activeRules, Rules rules, Project project, IssueFilters filters, ReportPublisher reportPublisher, BatchComponentCache componentCache) { this.activeRules = activeRules; this.rules = rules; - this.cache = cache; this.project = project; this.filters = filters; + this.reportPublisher = reportPublisher; + this.componentCache = componentCache; } - public boolean initAndAddIssue(DefaultIssue issue) { - RuleKey ruleKey = issue.ruleKey(); + public boolean initAndAddIssue(Issue issue) { + BatchComponent component; + InputPath inputPath = issue.locations().get(0).inputPath(); + if (inputPath != null) { + component = componentCache.get(inputPath); + } else { + component = componentCache.get(project); + } + DefaultIssue defaultIssue = toDefaultIssue(project.getKey(), component.key(), issue); + RuleKey ruleKey = defaultIssue.ruleKey(); Rule rule = rules.find(ruleKey); - validateRule(issue, rule); + validateRule(defaultIssue, rule); ActiveRule activeRule = activeRules.find(ruleKey); if (activeRule == null) { // rule does not exist or is not enabled -> ignore the issue return false; } - updateIssue(issue, rule, activeRule); - if (filters.accept(issue)) { - cache.put(issue); + updateIssue(defaultIssue, rule, activeRule); + if (filters.accept(defaultIssue)) { + write(component, defaultIssue); return true; } return false; } + public void write(BatchComponent component, DefaultIssue issue) { + reportPublisher.getWriter().appendComponentIssue(component.batchId(), toReportIssue(builder, issue)); + } + + private static BatchReport.Issue toReportIssue(BatchReport.Issue.Builder builder, DefaultIssue issue) { + builder.clear(); + // non-null fields + builder.setSeverity(Constants.Severity.valueOf(issue.severity())); + builder.setRuleRepository(issue.ruleKey().repository()); + builder.setRuleKey(issue.ruleKey().rule()); + builder.setAttributes(KeyValueFormat.format(issue.attributes())); + + // nullable fields + Integer line = issue.line(); + if (line != null) { + builder.setLine(line); + } + String message = issue.message(); + if (message != null) { + builder.setMsg(message); + } + Double effortToFix = issue.effortToFix(); + if (effortToFix != null) { + builder.setEffortToFix(effortToFix); + } + return builder.build(); + } + + public static DefaultIssue toDefaultIssue(String projectKey, String componentKey, Issue issue) { + Severity overriddenSeverity = issue.overriddenSeverity(); + TextRange textRange = issue.locations().get(0).textRange(); + return new org.sonar.core.issue.DefaultIssueBuilder() + .componentKey(componentKey) + .projectKey(projectKey) + .ruleKey(RuleKey.of(issue.ruleKey().repository(), issue.ruleKey().rule())) + .effortToFix(issue.effortToFix()) + .line(textRange != null ? textRange.start().line() : null) + .message(issue.locations().get(0).message()) + .severity(overriddenSeverity != null ? overriddenSeverity.name() : null) + .build(); + } + private static void validateRule(DefaultIssue issue, @Nullable Rule rule) { RuleKey ruleKey = issue.ruleKey(); if (rule == null) { diff --git a/sonar-batch/src/main/java/org/sonar/batch/issue/tracking/IssueTracking.java b/sonar-batch/src/main/java/org/sonar/batch/issue/tracking/IssueTracking.java index ee089357320..b5a2dbd872b 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/issue/tracking/IssueTracking.java +++ b/sonar-batch/src/main/java/org/sonar/batch/issue/tracking/IssueTracking.java @@ -27,102 +27,92 @@ import com.google.common.collect.LinkedHashMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; -import org.sonar.api.batch.BatchSide; -import org.sonar.api.batch.InstantiationStrategy; -import org.sonar.core.issue.DefaultIssue; - -import javax.annotation.Nullable; - import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; +import javax.annotation.CheckForNull; +import javax.annotation.Nullable; +import org.sonar.api.batch.BatchSide; +import org.sonar.api.batch.InstantiationStrategy; +import org.sonar.api.rule.RuleKey; +import org.sonar.batch.protocol.output.BatchReport; @InstantiationStrategy(InstantiationStrategy.PER_BATCH) @BatchSide public class IssueTracking { + private SourceHashHolder sourceHashHolder; + /** * @param sourceHashHolder Null when working on resource that is not a file (directory/project) */ - public IssueTrackingResult track(@Nullable SourceHashHolder sourceHashHolder, Collection previousIssues, Collection newIssues) { + public IssueTrackingResult track(@Nullable SourceHashHolder sourceHashHolder, Collection previousIssues, Collection rawIssues) { + this.sourceHashHolder = sourceHashHolder; IssueTrackingResult result = new IssueTrackingResult(); - if (sourceHashHolder != null) { - setChecksumOnNewIssues(newIssues, sourceHashHolder); - } - // Map new issues with old ones - mapIssues(newIssues, previousIssues, sourceHashHolder, result); + mapIssues(rawIssues, previousIssues, sourceHashHolder, result); return result; } - private void setChecksumOnNewIssues(Collection issues, SourceHashHolder sourceHashHolder) { - if (issues.isEmpty()) { - return; - } + private String checksum(BatchReport.Issue rawIssue) { FileHashes hashedSource = sourceHashHolder.getHashedSource(); - for (DefaultIssue issue : issues) { - Integer line = issue.line(); - if (line != null) { - // Extra verification if some plugin managed to create issue on a wrong line - Preconditions.checkState(line <= hashedSource.length(), "Invalid line number for issue %s. File has only %s line(s)", issue, hashedSource.length()); - issue.setChecksum(hashedSource.getHash(line)); - } + if (rawIssue.hasLine()) { + // Extra verification if some plugin managed to create issue on a wrong line + Preconditions.checkState(rawIssue.getLine() <= hashedSource.length(), "Invalid line number for issue %s. File has only %s line(s)", rawIssue, hashedSource.length()); + return hashedSource.getHash(rawIssue.getLine()); } + return null; } @VisibleForTesting - void mapIssues(Collection newIssues, @Nullable Collection previousIssues, @Nullable SourceHashHolder sourceHashHolder, IssueTrackingResult result) { + void mapIssues(Collection rawIssues, @Nullable Collection previousIssues, @Nullable SourceHashHolder sourceHashHolder, + IssueTrackingResult result) { boolean hasLastScan = false; if (previousIssues != null) { hasLastScan = true; - mapLastIssues(newIssues, previousIssues, result); + mapLastIssues(rawIssues, previousIssues, result); } // If each new issue matches an old one we can stop the matching mechanism - if (result.matched().size() != newIssues.size()) { + if (result.matched().size() != rawIssues.size()) { if (sourceHashHolder != null && hasLastScan) { FileHashes hashedReference = sourceHashHolder.getHashedReference(); if (hashedReference != null) { - mapNewissues(hashedReference, sourceHashHolder.getHashedSource(), newIssues, result); + mapNewissues(hashedReference, sourceHashHolder.getHashedSource(), rawIssues, result); } } - mapIssuesOnSameRule(newIssues, result); + mapIssuesOnSameRule(rawIssues, result); } } - private void mapLastIssues(Collection newIssues, Collection previousIssues, IssueTrackingResult result) { + private void mapLastIssues(Collection rawIssues, Collection previousIssues, IssueTrackingResult result) { for (ServerIssue lastIssue : previousIssues) { result.addUnmatched(lastIssue); } - // Match the key of the issue. (For manual issues) - for (DefaultIssue newIssue : newIssues) { - mapIssue(newIssue, result.unmatchedByKeyForRule(newIssue.ruleKey()).get(newIssue.key()), result); - } - // Try first to match issues on same rule with same line and with same checksum (but not necessarily with same message) - for (DefaultIssue newIssue : newIssues) { - if (isNotAlreadyMapped(newIssue, result)) { + for (BatchReport.Issue rawIssue : rawIssues) { + if (isNotAlreadyMapped(rawIssue, result)) { mapIssue( - newIssue, - findLastIssueWithSameLineAndChecksum(newIssue, result), + rawIssue, + findLastIssueWithSameLineAndChecksum(rawIssue, result), result); } } } - private void mapNewissues(FileHashes hashedReference, FileHashes hashedSource, Collection newIssues, IssueTrackingResult result) { + private void mapNewissues(FileHashes hashedReference, FileHashes hashedSource, Collection rawIssues, IssueTrackingResult result) { IssueTrackingBlocksRecognizer rec = new IssueTrackingBlocksRecognizer(hashedReference, hashedSource); RollingFileHashes a = RollingFileHashes.create(hashedReference, 5); RollingFileHashes b = RollingFileHashes.create(hashedSource, 5); - Multimap newIssuesByLines = newIssuesByLines(newIssues, rec, result); + Multimap rawIssuesByLines = rawIssuesByLines(rawIssues, rec, result); Multimap lastIssuesByLines = lastIssuesByLines(result.unmatched(), rec); Map map = Maps.newHashMap(); @@ -141,7 +131,7 @@ public class IssueTracking { } } - for (Integer line : newIssuesByLines.keySet()) { + for (Integer line : rawIssuesByLines.keySet()) { int hash = b.getHash(line); HashOccurrence hashOccurrence = map.get(hash); if (hashOccurrence != null) { @@ -153,17 +143,17 @@ public class IssueTracking { for (HashOccurrence hashOccurrence : map.values()) { if (hashOccurrence.countA == 1 && hashOccurrence.countB == 1) { // Guaranteed that lineA has been moved to lineB, so we can map all issues on lineA to all issues on lineB - map(newIssuesByLines.get(hashOccurrence.lineB), lastIssuesByLines.get(hashOccurrence.lineA), result); + map(rawIssuesByLines.get(hashOccurrence.lineB), lastIssuesByLines.get(hashOccurrence.lineA), result); lastIssuesByLines.removeAll(hashOccurrence.lineA); - newIssuesByLines.removeAll(hashOccurrence.lineB); + rawIssuesByLines.removeAll(hashOccurrence.lineB); } } // Check if remaining number of lines exceeds threshold - if (lastIssuesByLines.keySet().size() * newIssuesByLines.keySet().size() < 250000) { + if (lastIssuesByLines.keySet().size() * rawIssuesByLines.keySet().size() < 250000) { List possibleLinePairs = Lists.newArrayList(); for (Integer oldLine : lastIssuesByLines.keySet()) { - for (Integer newLine : newIssuesByLines.keySet()) { + for (Integer newLine : rawIssuesByLines.keySet()) { int weight = rec.computeLengthOfMaximalBlock(oldLine, newLine); possibleLinePairs.add(new LinePair(oldLine, newLine, weight)); } @@ -171,50 +161,54 @@ public class IssueTracking { Collections.sort(possibleLinePairs, LINE_PAIR_COMPARATOR); for (LinePair linePair : possibleLinePairs) { // High probability that lineA has been moved to lineB, so we can map all Issues on lineA to all Issues on lineB - map(newIssuesByLines.get(linePair.lineB), lastIssuesByLines.get(linePair.lineA), result); + map(rawIssuesByLines.get(linePair.lineB), lastIssuesByLines.get(linePair.lineA), result); } } } - private void mapIssuesOnSameRule(Collection newIssues, IssueTrackingResult result) { + private void mapIssuesOnSameRule(Collection rawIssues, IssueTrackingResult result) { // Try then to match issues on same rule with same message and with same checksum - for (DefaultIssue newIssue : newIssues) { - if (isNotAlreadyMapped(newIssue, result)) { + for (BatchReport.Issue rawIssue : rawIssues) { + if (isNotAlreadyMapped(rawIssue, result)) { mapIssue( - newIssue, - findLastIssueWithSameChecksumAndMessage(newIssue, result.unmatchedByKeyForRule(newIssue.ruleKey()).values()), + rawIssue, + findLastIssueWithSameChecksumAndMessage(rawIssue, result.unmatchedByKeyForRule(ruleKey(rawIssue)).values()), result); } } // Try then to match issues on same rule with same line and with same message - for (DefaultIssue newIssue : newIssues) { - if (isNotAlreadyMapped(newIssue, result)) { + for (BatchReport.Issue rawIssue : rawIssues) { + if (isNotAlreadyMapped(rawIssue, result)) { mapIssue( - newIssue, - findLastIssueWithSameLineAndMessage(newIssue, result.unmatchedByKeyForRule(newIssue.ruleKey()).values()), + rawIssue, + findLastIssueWithSameLineAndMessage(rawIssue, result.unmatchedByKeyForRule(ruleKey(rawIssue)).values()), result); } } // Last check: match issue if same rule and same checksum but different line and different message // See SONAR-2812 - for (DefaultIssue newIssue : newIssues) { - if (isNotAlreadyMapped(newIssue, result)) { + for (BatchReport.Issue rawIssue : rawIssues) { + if (isNotAlreadyMapped(rawIssue, result)) { mapIssue( - newIssue, - findLastIssueWithSameChecksum(newIssue, result.unmatchedByKeyForRule(newIssue.ruleKey()).values()), + rawIssue, + findLastIssueWithSameChecksum(rawIssue, result.unmatchedByKeyForRule(ruleKey(rawIssue)).values()), result); } } } - private void map(Collection newIssues, Collection previousIssues, IssueTrackingResult result) { - for (DefaultIssue newIssue : newIssues) { - if (isNotAlreadyMapped(newIssue, result)) { + private RuleKey ruleKey(BatchReport.Issue rawIssue) { + return RuleKey.of(rawIssue.getRuleRepository(), rawIssue.getRuleKey()); + } + + private void map(Collection rawIssues, Collection previousIssues, IssueTrackingResult result) { + for (BatchReport.Issue rawIssue : rawIssues) { + if (isNotAlreadyMapped(rawIssue, result)) { for (ServerIssue previousIssue : previousIssues) { - if (isNotAlreadyMapped(previousIssue, result) && Objects.equal(newIssue.ruleKey(), previousIssue.ruleKey())) { - mapIssue(newIssue, previousIssue, result); + if (isNotAlreadyMapped(previousIssue, result) && Objects.equal(ruleKey(rawIssue), previousIssue.ruleKey())) { + mapIssue(rawIssue, previousIssue, result); break; } } @@ -222,14 +216,14 @@ public class IssueTracking { } } - private Multimap newIssuesByLines(Collection newIssues, IssueTrackingBlocksRecognizer rec, IssueTrackingResult result) { - Multimap newIssuesByLines = LinkedHashMultimap.create(); - for (DefaultIssue newIssue : newIssues) { - if (isNotAlreadyMapped(newIssue, result) && rec.isValidLineInSource(newIssue.line())) { - newIssuesByLines.put(newIssue.line(), newIssue); + private Multimap rawIssuesByLines(Collection rawIssues, IssueTrackingBlocksRecognizer rec, IssueTrackingResult result) { + Multimap rawIssuesByLines = LinkedHashMultimap.create(); + for (BatchReport.Issue rawIssue : rawIssues) { + if (isNotAlreadyMapped(rawIssue, result) && rawIssue.hasLine() && rec.isValidLineInSource(rawIssue.getLine())) { + rawIssuesByLines.put(rawIssue.getLine(), rawIssue); } } - return newIssuesByLines; + return rawIssuesByLines; } private Multimap lastIssuesByLines(Collection previousIssues, IssueTrackingBlocksRecognizer rec) { @@ -242,64 +236,74 @@ public class IssueTracking { return previousIssuesByLines; } - private ServerIssue findLastIssueWithSameChecksum(DefaultIssue newIssue, Collection previousIssues) { + private ServerIssue findLastIssueWithSameChecksum(BatchReport.Issue rawIssue, Collection previousIssues) { for (ServerIssue previousIssue : previousIssues) { - if (isSameChecksum(newIssue, previousIssue)) { + if (isSameChecksum(rawIssue, previousIssue)) { return previousIssue; } } return null; } - private ServerIssue findLastIssueWithSameLineAndMessage(DefaultIssue newIssue, Collection previousIssues) { + private ServerIssue findLastIssueWithSameLineAndMessage(BatchReport.Issue rawIssue, Collection previousIssues) { for (ServerIssue previousIssue : previousIssues) { - if (isSameLine(newIssue, previousIssue) && isSameMessage(newIssue, previousIssue)) { + if (isSameLine(rawIssue, previousIssue) && isSameMessage(rawIssue, previousIssue)) { return previousIssue; } } return null; } - private ServerIssue findLastIssueWithSameChecksumAndMessage(DefaultIssue newIssue, Collection previousIssues) { + private ServerIssue findLastIssueWithSameChecksumAndMessage(BatchReport.Issue rawIssue, Collection previousIssues) { for (ServerIssue previousIssue : previousIssues) { - if (isSameChecksum(newIssue, previousIssue) && isSameMessage(newIssue, previousIssue)) { + if (isSameChecksum(rawIssue, previousIssue) && isSameMessage(rawIssue, previousIssue)) { return previousIssue; } } return null; } - private ServerIssue findLastIssueWithSameLineAndChecksum(DefaultIssue newIssue, IssueTrackingResult result) { - Collection sameRuleAndSameLineAndSameChecksum = result.unmatchedForRuleAndForLineAndForChecksum(newIssue.ruleKey(), newIssue.line(), newIssue.checksum()); + private ServerIssue findLastIssueWithSameLineAndChecksum(BatchReport.Issue rawIssue, IssueTrackingResult result) { + Collection sameRuleAndSameLineAndSameChecksum = result.unmatchedForRuleAndForLineAndForChecksum(ruleKey(rawIssue), line(rawIssue), checksum(rawIssue)); if (!sameRuleAndSameLineAndSameChecksum.isEmpty()) { return sameRuleAndSameLineAndSameChecksum.iterator().next(); } return null; } + @CheckForNull + private Integer line(BatchReport.Issue rawIssue) { + return rawIssue.hasLine() ? rawIssue.getLine() : null; + } + private boolean isNotAlreadyMapped(ServerIssue previousIssue, IssueTrackingResult result) { return result.unmatched().contains(previousIssue); } - private boolean isNotAlreadyMapped(DefaultIssue newIssue, IssueTrackingResult result) { - return !result.isMatched(newIssue); + private boolean isNotAlreadyMapped(BatchReport.Issue rawIssue, IssueTrackingResult result) { + return !result.isMatched(rawIssue); + } + + private boolean isSameChecksum(BatchReport.Issue rawIssue, ServerIssue previousIssue) { + return Objects.equal(previousIssue.checksum(), checksum(rawIssue)); } - private boolean isSameChecksum(DefaultIssue newIssue, ServerIssue previousIssue) { - return Objects.equal(previousIssue.checksum(), newIssue.checksum()); + private boolean isSameLine(BatchReport.Issue rawIssue, ServerIssue previousIssue) { + return Objects.equal(previousIssue.line(), line(rawIssue)); } - private boolean isSameLine(DefaultIssue newIssue, ServerIssue previousIssue) { - return Objects.equal(previousIssue.line(), newIssue.line()); + private boolean isSameMessage(BatchReport.Issue rawIssue, ServerIssue previousIssue) { + return Objects.equal(message(rawIssue), previousIssue.message()); } - private boolean isSameMessage(DefaultIssue newIssue, ServerIssue previousIssue) { - return Objects.equal(newIssue.message(), previousIssue.message()); + @CheckForNull + private String message(BatchReport.Issue rawIssue) { + return rawIssue.hasMsg() ? rawIssue.getMsg() : null; } - private void mapIssue(DefaultIssue issue, @Nullable ServerIssue ref, IssueTrackingResult result) { + private void mapIssue(BatchReport.Issue rawIssue, @Nullable ServerIssue ref, IssueTrackingResult result) { if (ref != null) { - result.setMatch(issue, ref); + result.setMatch(rawIssue, ref); } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/issue/tracking/IssueTrackingResult.java b/sonar-batch/src/main/java/org/sonar/batch/issue/tracking/IssueTrackingResult.java index e04cdc240b4..e55ef46b03f 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/issue/tracking/IssueTrackingResult.java +++ b/sonar-batch/src/main/java/org/sonar/batch/issue/tracking/IssueTrackingResult.java @@ -22,22 +22,20 @@ package org.sonar.batch.issue.tracking; import com.google.common.collect.HashMultimap; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; -import org.apache.commons.lang.StringUtils; -import org.sonar.core.issue.DefaultIssue; -import org.sonar.api.rule.RuleKey; - -import javax.annotation.Nullable; - import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; +import javax.annotation.Nullable; +import org.apache.commons.lang.StringUtils; +import org.sonar.api.rule.RuleKey; +import org.sonar.batch.protocol.output.BatchReport; class IssueTrackingResult { private final Map unmatchedByKey = new HashMap<>(); private final Map> unmatchedByRuleAndKey = new HashMap<>(); private final Map>> unmatchedByRuleAndLineAndChecksum = new HashMap<>(); - private final Map matched = Maps.newIdentityHashMap(); + private final Map matched = Maps.newIdentityHashMap(); Collection unmatched() { return unmatchedByKey.values(); @@ -64,15 +62,15 @@ class IssueTrackingResult { return unmatchedForRuleAndLine.get(checksumNotNull); } - Collection matched() { + Collection matched() { return matched.keySet(); } - boolean isMatched(DefaultIssue issue) { + boolean isMatched(BatchReport.Issue issue) { return matched.containsKey(issue); } - ServerIssue matching(DefaultIssue issue) { + ServerIssue matching(BatchReport.Issue issue) { return matched.get(issue); } @@ -99,7 +97,7 @@ class IssueTrackingResult { return line != null ? line : 0; } - void setMatch(DefaultIssue issue, ServerIssue matching) { + void setMatch(BatchReport.Issue issue, ServerIssue matching) { matched.put(issue, matching); RuleKey ruleKey = matching.ruleKey(); unmatchedByRuleAndKey.get(ruleKey).remove(matching.key()); diff --git a/sonar-batch/src/main/java/org/sonar/batch/issue/tracking/LocalIssueTracking.java b/sonar-batch/src/main/java/org/sonar/batch/issue/tracking/LocalIssueTracking.java index 729e4d7cff1..ee316017c21 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/issue/tracking/LocalIssueTracking.java +++ b/sonar-batch/src/main/java/org/sonar/batch/issue/tracking/LocalIssueTracking.java @@ -21,33 +21,40 @@ package org.sonar.batch.issue.tracking; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Set; +import javax.annotation.CheckForNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.sonar.api.batch.BatchSide; import org.sonar.api.batch.AnalysisMode; +import org.sonar.api.batch.BatchSide; import org.sonar.api.batch.fs.internal.DefaultInputFile; import org.sonar.api.batch.rule.ActiveRule; import org.sonar.api.batch.rule.ActiveRules; import org.sonar.api.issue.Issue; -import org.sonar.core.issue.DefaultIssue; -import org.sonar.core.issue.IssueChangeContext; import org.sonar.api.resources.Project; import org.sonar.api.resources.ResourceUtils; import org.sonar.api.rule.RuleKey; +import org.sonar.api.utils.KeyValueFormat; import org.sonar.batch.index.BatchComponent; import org.sonar.batch.index.BatchComponentCache; import org.sonar.batch.issue.IssueCache; import org.sonar.batch.protocol.input.ProjectRepositories; +import org.sonar.batch.protocol.output.BatchReport; +import org.sonar.batch.protocol.output.BatchReportReader; +import org.sonar.batch.report.ReportPublisher; import org.sonar.batch.scan.filesystem.InputPathCache; import org.sonar.core.component.ComponentKeys; +import org.sonar.core.issue.DefaultIssue; +import org.sonar.core.issue.IssueChangeContext; import org.sonar.core.issue.IssueUpdater; import org.sonar.core.issue.workflow.IssueWorkflow; - -import javax.annotation.CheckForNull; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; +import org.sonar.core.util.CloseableIterator; @BatchSide public class LocalIssueTracking { @@ -62,16 +69,18 @@ public class LocalIssueTracking { private final IssueChangeContext changeContext; private final ActiveRules activeRules; private final InputPathCache inputPathCache; - private final BatchComponentCache resourceCache; + private final BatchComponentCache componentCache; private final ServerIssueRepository serverIssueRepository; private final ProjectRepositories projectRepositories; private final AnalysisMode analysisMode; + private final ReportPublisher reportPublisher; + private final Date analysisDate; public LocalIssueTracking(BatchComponentCache resourceCache, IssueCache issueCache, IssueTracking tracking, ServerLineHashesLoader lastLineHashes, IssueWorkflow workflow, IssueUpdater updater, ActiveRules activeRules, InputPathCache inputPathCache, ServerIssueRepository serverIssueRepository, - ProjectRepositories projectRepositories, AnalysisMode analysisMode) { - this.resourceCache = resourceCache; + ProjectRepositories projectRepositories, AnalysisMode analysisMode, ReportPublisher reportPublisher) { + this.componentCache = resourceCache; this.issueCache = issueCache; this.tracking = tracking; this.lastLineHashes = lastLineHashes; @@ -81,7 +90,9 @@ public class LocalIssueTracking { this.serverIssueRepository = serverIssueRepository; this.projectRepositories = projectRepositories; this.analysisMode = analysisMode; - this.changeContext = IssueChangeContext.createScan(((Project) resourceCache.getRoot().resource()).getAnalysisDate()); + this.reportPublisher = reportPublisher; + this.analysisDate = ((Project) resourceCache.getRoot().resource()).getAnalysisDate(); + this.changeContext = IssueChangeContext.createScan(analysisDate); this.activeRules = activeRules; } @@ -92,49 +103,82 @@ public class LocalIssueTracking { } serverIssueRepository.load(); + BatchReportReader reader = new BatchReportReader(reportPublisher.getReportDir()); - for (BatchComponent component : resourceCache.all()) { - trackIssues(component); + for (BatchComponent component : componentCache.all()) { + trackIssues(reader, component); } } - public void trackIssues(BatchComponent component) { - - Collection issues = Lists.newArrayList(); - for (Issue issue : issueCache.byComponent(component.resource().getEffectiveKey())) { - issues.add((DefaultIssue) issue); - } - issueCache.clear(component.resource().getEffectiveKey()); - // issues = all the issues created by rule engines during this module scan and not excluded by filters + public void trackIssues(BatchReportReader reader, BatchComponent component) { if (analysisMode.isIncremental() && !component.isFile()) { // No need to report issues on project or directories in preview mode since it is likely to be wrong anyway return; } + // raw issues = all the issues created by rule engines during this module scan and not excluded by filters + Set rawIssues = Sets.newIdentityHashSet(); + try (CloseableIterator it = reader.readComponentIssues(component.batchId())) { + while (it.hasNext()) { + rawIssues.add(it.next()); + } + } catch (Exception e) { + throw new IllegalStateException("Can't read issues for " + component.key(), e); + } + // all the issues that are not closed in db before starting this module scan, including manual issues Collection serverIssues = loadServerIssues(component); SourceHashHolder sourceHashHolder = loadSourceHashes(component); - IssueTrackingResult trackingResult = tracking.track(sourceHashHolder, serverIssues, issues); + IssueTrackingResult trackingResult = tracking.track(sourceHashHolder, serverIssues, rawIssues); - // unmatched = issues that have been resolved + issues on disabled/removed rules + manual issues - addUnmatched(trackingResult.unmatched(), sourceHashHolder, issues); + List trackedIssues = Lists.newArrayList(); + // unmatched from server = issues that have been resolved + issues on disabled/removed rules + manual issues + addUnmatchedFromServer(trackingResult.unmatched(), sourceHashHolder, trackedIssues); - mergeMatched(trackingResult); + mergeMatched(component, trackingResult, trackedIssues, rawIssues); + + // Unmatched raw issues = new issues + addUnmatchedRawIssues(component, rawIssues, trackedIssues); if (ResourceUtils.isRootProject(component.resource())) { // issues that relate to deleted components - addIssuesOnDeletedComponents(issues); + addIssuesOnDeletedComponents(trackedIssues); } - for (DefaultIssue issue : issues) { + for (DefaultIssue issue : trackedIssues) { workflow.doAutomaticTransition(issue, changeContext); issueCache.put(issue); } } + private void addUnmatchedRawIssues(BatchComponent component, Set rawIssues, List trackedIssues) { + for (BatchReport.Issue rawIssue : rawIssues) { + + DefaultIssue tracked = toTracked(component, rawIssue); + tracked.setNew(true); + tracked.setCreationDate(analysisDate); + + trackedIssues.add(tracked); + } + } + + private DefaultIssue toTracked(BatchComponent component, BatchReport.Issue rawIssue) { + DefaultIssue trackedIssue = new org.sonar.core.issue.DefaultIssueBuilder() + .componentKey(component.key()) + .projectKey("unused") + .ruleKey(RuleKey.of(rawIssue.getRuleRepository(), rawIssue.getRuleKey())) + .effortToFix(rawIssue.hasEffortToFix() ? rawIssue.getEffortToFix() : null) + .line(rawIssue.hasLine() ? rawIssue.getLine() : null) + .message(rawIssue.hasMsg() ? rawIssue.getMsg() : null) + .severity(rawIssue.getSeverity().name()) + .build(); + trackedIssue.setAttributes(rawIssue.hasAttributes() ? KeyValueFormat.parse(rawIssue.getAttributes()) : Collections.emptyMap()); + return trackedIssue; + } + @CheckForNull private SourceHashHolder loadSourceHashes(BatchComponent component) { SourceHashHolder sourceHashHolder = null; @@ -157,32 +201,36 @@ public class LocalIssueTracking { } @VisibleForTesting - protected void mergeMatched(IssueTrackingResult result) { - for (DefaultIssue issue : result.matched()) { - org.sonar.batch.protocol.input.BatchInput.ServerIssue ref = ((ServerIssueFromWs) result.matching(issue)).getDto(); + protected void mergeMatched(BatchComponent component, IssueTrackingResult result, List trackedIssues, Collection rawIssues) { + for (BatchReport.Issue rawIssue : result.matched()) { + rawIssues.remove(rawIssue); + org.sonar.batch.protocol.input.BatchInput.ServerIssue ref = ((ServerIssueFromWs) result.matching(rawIssue)).getDto(); + + DefaultIssue tracked = toTracked(component, rawIssue); // invariant fields - issue.setKey(ref.getKey()); + tracked.setKey(ref.getKey()); // non-persisted fields - issue.setNew(false); - issue.setBeingClosed(false); - issue.setOnDisabledRule(false); + tracked.setNew(false); + tracked.setBeingClosed(false); + tracked.setOnDisabledRule(false); // fields to update with old values - issue.setResolution(ref.hasResolution() ? ref.getResolution() : null); - issue.setStatus(ref.getStatus()); - issue.setAssignee(ref.hasAssigneeLogin() ? ref.getAssigneeLogin() : null); - issue.setCreationDate(new Date(ref.getCreationDate())); + tracked.setResolution(ref.hasResolution() ? ref.getResolution() : null); + tracked.setStatus(ref.getStatus()); + tracked.setAssignee(ref.hasAssigneeLogin() ? ref.getAssigneeLogin() : null); + tracked.setCreationDate(new Date(ref.getCreationDate())); if (ref.getManualSeverity()) { // Severity overriden by user - issue.setSeverity(ref.getSeverity().name()); + tracked.setSeverity(ref.getSeverity().name()); } + trackedIssues.add(tracked); } } - private void addUnmatched(Collection unmatchedIssues, SourceHashHolder sourceHashHolder, Collection issues) { + private void addUnmatchedFromServer(Collection unmatchedIssues, SourceHashHolder sourceHashHolder, Collection issues) { for (ServerIssue unmatchedIssue : unmatchedIssues) { org.sonar.batch.protocol.input.BatchInput.ServerIssue unmatchedPreviousIssue = ((ServerIssueFromWs) unmatchedIssue).getDto(); DefaultIssue unmatched = toUnmatchedIssue(unmatchedPreviousIssue); diff --git a/sonar-batch/src/main/java/org/sonar/batch/mediumtest/TaskResult.java b/sonar-batch/src/main/java/org/sonar/batch/mediumtest/TaskResult.java index 10341e8dcbe..1b02c9090d5 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/mediumtest/TaskResult.java +++ b/sonar-batch/src/main/java/org/sonar/batch/mediumtest/TaskResult.java @@ -36,8 +36,10 @@ import org.slf4j.LoggerFactory; import org.sonar.api.batch.AnalysisMode; import org.sonar.api.batch.fs.InputDir; import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.fs.InputPath; import org.sonar.api.batch.fs.TextPointer; import org.sonar.api.batch.fs.TextRange; +import org.sonar.api.batch.fs.internal.DefaultInputDir; import org.sonar.api.batch.fs.internal.DefaultInputFile; import org.sonar.api.batch.sensor.duplication.Duplication; import org.sonar.api.batch.sensor.highlighting.TypeOfText; @@ -121,10 +123,27 @@ public class TaskResult implements org.sonar.batch.mediumtest.ScanTaskObserver { } } - public List issues() { + public List trackedIssues() { return issues; } + public List issuesFor(InputPath inputPath) { + List result = Lists.newArrayList(); + int ref = reportComponents.get(key(inputPath)).getRef(); + try (CloseableIterator it = reader.readComponentIssues(ref)) { + while (it.hasNext()) { + result.add(it.next()); + } + } catch (Exception e) { + throw new IllegalStateException("Can't read issues for " + inputPath.absolutePath(), e); + } + return result; + } + + private String key(InputPath inputPath) { + return inputPath instanceof InputFile ? ((DefaultInputFile) inputPath).key() : ((DefaultInputDir) inputPath).key(); + } + public Collection inputFiles() { return inputFiles.values(); } diff --git a/sonar-batch/src/main/java/org/sonar/batch/report/IssuesPublisher.java b/sonar-batch/src/main/java/org/sonar/batch/report/IssuesPublisher.java deleted file mode 100644 index 24e1a95abc7..00000000000 --- a/sonar-batch/src/main/java/org/sonar/batch/report/IssuesPublisher.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * 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.Iterables; -import org.sonar.api.utils.KeyValueFormat; -import org.sonar.batch.index.BatchComponent; -import org.sonar.batch.index.BatchComponentCache; -import org.sonar.batch.issue.IssueCache; -import org.sonar.batch.protocol.Constants; -import org.sonar.batch.protocol.output.BatchReport; -import org.sonar.batch.protocol.output.BatchReportWriter; -import org.sonar.core.issue.DefaultIssue; - -public class IssuesPublisher implements ReportPublisherStep { - - private final BatchComponentCache componentCache; - private final IssueCache issueCache; - - public IssuesPublisher(BatchComponentCache componentCache, IssueCache issueCache) { - this.componentCache = componentCache; - this.issueCache = issueCache; - - } - - @Override - public void publish(BatchReportWriter writer) { - for (BatchComponent resource : componentCache.all()) { - String componentKey = resource.resource().getEffectiveKey(); - Iterable issues = issueCache.byComponent(componentKey); - writer.writeComponentIssues(resource.batchId(), Iterables.transform(issues, new Function() { - private BatchReport.Issue.Builder builder = BatchReport.Issue.newBuilder(); - - @Override - public BatchReport.Issue apply(DefaultIssue input) { - return toReportIssue(builder, input); - } - })); - } - } - - private BatchReport.Issue toReportIssue(BatchReport.Issue.Builder builder, DefaultIssue issue) { - builder.clear(); - // non-null fields - builder.setSeverity(Constants.Severity.valueOf(issue.severity())); - builder.setRuleRepository(issue.ruleKey().repository()); - builder.setRuleKey(issue.ruleKey().rule()); - builder.setAttributes(KeyValueFormat.format(issue.attributes())); - - // nullable fields - Integer line = issue.line(); - if (line != null) { - builder.setLine(line); - } - String message = issue.message(); - if (message != null) { - builder.setMsg(message); - } - Double effortToFix = issue.effortToFix(); - if (effortToFix != null) { - builder.setEffortToFix(effortToFix); - } - return builder.build(); - } - -} diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java index ea086f5a068..28367ee042c 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java @@ -59,7 +59,6 @@ import org.sonar.batch.report.ActiveRulesPublisher; import org.sonar.batch.report.ComponentsPublisher; import org.sonar.batch.report.CoveragePublisher; import org.sonar.batch.report.DuplicationsPublisher; -import org.sonar.batch.report.IssuesPublisher; import org.sonar.batch.report.MeasuresPublisher; import org.sonar.batch.report.MetadataPublisher; import org.sonar.batch.report.ReportPublisher; @@ -189,7 +188,6 @@ public class ProjectScanContainer extends ComponentContainer { MetadataPublisher.class, ActiveRulesPublisher.class, ComponentsPublisher.class, - IssuesPublisher.class, MeasuresPublisher.class, DuplicationsPublisher.class, CoveragePublisher.class, diff --git a/sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorStorage.java b/sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorStorage.java index 1ab8482079a..adacbb99546 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorStorage.java +++ b/sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorStorage.java @@ -30,12 +30,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonar.api.batch.fs.FileSystem; import org.sonar.api.batch.fs.InputFile; -import org.sonar.api.batch.fs.InputPath; import org.sonar.api.batch.fs.TextRange; import org.sonar.api.batch.fs.internal.DefaultInputFile; import org.sonar.api.batch.measure.MetricFinder; import org.sonar.api.batch.rule.ActiveRules; -import org.sonar.api.batch.rule.Severity; import org.sonar.api.batch.sensor.coverage.CoverageType; import org.sonar.api.batch.sensor.coverage.internal.DefaultCoverage; import org.sonar.api.batch.sensor.duplication.Duplication; @@ -52,7 +50,6 @@ import org.sonar.api.measures.Metric; import org.sonar.api.resources.File; import org.sonar.api.resources.Project; import org.sonar.api.resources.Resource; -import org.sonar.api.rule.RuleKey; import org.sonar.api.source.Symbol; import org.sonar.api.utils.KeyValueFormat; import org.sonar.api.utils.SonarException; @@ -67,8 +64,6 @@ import org.sonar.batch.report.ReportPublisher; import org.sonar.batch.scan.measure.MeasureCache; import org.sonar.batch.sensor.coverage.CoverageExclusions; import org.sonar.batch.source.DefaultSymbol; -import org.sonar.core.component.ComponentKeys; -import org.sonar.core.issue.DefaultIssue; public class DefaultSensorStorage implements SensorStorage { @@ -194,28 +189,7 @@ public class DefaultSensorStorage implements SensorStorage { @Override public void store(Issue issue) { - String componentKey; - InputPath inputPath = issue.locations().get(0).inputPath(); - if (inputPath != null) { - componentKey = ComponentKeys.createEffectiveKey(project.getKey(), inputPath); - } else { - componentKey = project.getKey(); - } - moduleIssues.initAndAddIssue(toDefaultIssue(project.getKey(), componentKey, issue)); - } - - public static DefaultIssue toDefaultIssue(String projectKey, String componentKey, Issue issue) { - Severity overriddenSeverity = issue.overriddenSeverity(); - TextRange textRange = issue.locations().get(0).textRange(); - return new org.sonar.core.issue.DefaultIssueBuilder() - .componentKey(componentKey) - .projectKey(projectKey) - .ruleKey(RuleKey.of(issue.ruleKey().repository(), issue.ruleKey().rule())) - .effortToFix(issue.effortToFix()) - .line(textRange != null ? textRange.start().line() : null) - .message(issue.locations().get(0).message()) - .severity(overriddenSeverity != null ? overriddenSeverity.name() : null) - .build(); + moduleIssues.initAndAddIssue(issue); } private File getFile(InputFile file) { diff --git a/sonar-batch/src/test/java/org/sonar/batch/issue/DefaultIssuableTest.java b/sonar-batch/src/test/java/org/sonar/batch/issue/DefaultIssuableTest.java deleted file mode 100644 index 5df84297370..00000000000 --- a/sonar-batch/src/test/java/org/sonar/batch/issue/DefaultIssuableTest.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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.issue; - -import java.util.Arrays; -import java.util.List; -import org.junit.Test; -import org.sonar.api.batch.sensor.SensorContext; -import org.sonar.api.issue.Issue; -import org.sonar.batch.index.BatchComponent; -import org.sonar.core.issue.DefaultIssue; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class DefaultIssuableTest { - - IssueCache cache = mock(IssueCache.class); - BatchComponent component = mock(BatchComponent.class); - - @Test - public void test_unresolved_issues() throws Exception { - when(component.key()).thenReturn("struts:org.apache.Action"); - DefaultIssue resolved = new DefaultIssue().setResolution(Issue.RESOLUTION_FALSE_POSITIVE); - DefaultIssue unresolved = new DefaultIssue(); - when(cache.byComponent("struts:org.apache.Action")).thenReturn(Arrays.asList(resolved, unresolved)); - - DefaultIssuable perspective = new DefaultIssuable(component, cache, mock(SensorContext.class)); - - List issues = perspective.issues(); - assertThat(issues).containsOnly(unresolved); - } - - @Test - public void test_resolved_issues() throws Exception { - when(component.key()).thenReturn("struts:org.apache.Action"); - DefaultIssue resolved = new DefaultIssue().setResolution(Issue.RESOLUTION_FALSE_POSITIVE); - DefaultIssue unresolved = new DefaultIssue(); - when(cache.byComponent("struts:org.apache.Action")).thenReturn(Arrays.asList(resolved, unresolved)); - - DefaultIssuable perspective = new DefaultIssuable(component, cache, mock(SensorContext.class)); - - List issues = perspective.resolvedIssues(); - assertThat(issues).containsOnly(resolved); - } -} diff --git a/sonar-batch/src/test/java/org/sonar/batch/issue/IssuableFactoryTest.java b/sonar-batch/src/test/java/org/sonar/batch/issue/IssuableFactoryTest.java index ddabedba240..5525d4ea049 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/issue/IssuableFactoryTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/issue/IssuableFactoryTest.java @@ -20,7 +20,6 @@ package org.sonar.batch.issue; import org.junit.Test; -import org.mockito.Mockito; import org.sonar.api.issue.Issuable; import org.sonar.api.resources.File; import org.sonar.api.resources.Project; @@ -34,12 +33,11 @@ import static org.mockito.Mockito.mock; public class IssuableFactoryTest { ModuleIssues moduleIssues = mock(ModuleIssues.class); - IssueCache cache = mock(IssueCache.class, Mockito.RETURNS_MOCKS); DefaultProjectTree projectTree = mock(DefaultProjectTree.class); @Test public void file_should_be_issuable() { - IssuableFactory factory = new IssuableFactory(cache, mock(DefaultSensorContext.class)); + IssuableFactory factory = new IssuableFactory(mock(DefaultSensorContext.class)); BatchComponent component = new BatchComponent(1, File.create("foo/bar.c").setEffectiveKey("foo/bar.c"), null); Issuable issuable = factory.loadPerspective(Issuable.class, component); @@ -49,7 +47,7 @@ public class IssuableFactoryTest { @Test public void project_should_be_issuable() { - IssuableFactory factory = new IssuableFactory(cache, mock(DefaultSensorContext.class)); + IssuableFactory factory = new IssuableFactory(mock(DefaultSensorContext.class)); BatchComponent component = new BatchComponent(1, new Project("Foo").setEffectiveKey("foo"), null); Issuable issuable = factory.loadPerspective(Issuable.class, component); diff --git a/sonar-batch/src/test/java/org/sonar/batch/issue/ModuleIssuesTest.java b/sonar-batch/src/test/java/org/sonar/batch/issue/ModuleIssuesTest.java index a602f1f6549..fb9cf921e2f 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/issue/ModuleIssuesTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/issue/ModuleIssuesTest.java @@ -19,25 +19,36 @@ */ package org.sonar.batch.issue; -import java.util.Calendar; +import java.io.StringReader; import java.util.Date; -import org.apache.commons.lang.time.DateUtils; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; +import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.fs.internal.DefaultInputFile; +import org.sonar.api.batch.fs.internal.FileMetadata; import org.sonar.api.batch.rule.internal.ActiveRulesBuilder; import org.sonar.api.batch.rule.internal.RulesBuilder; +import org.sonar.api.batch.sensor.issue.internal.DefaultIssue; +import org.sonar.api.batch.sensor.issue.internal.DefaultIssueLocation; +import org.sonar.api.resources.File; import org.sonar.api.resources.Project; import org.sonar.api.rule.RuleKey; import org.sonar.api.rule.Severity; import org.sonar.api.utils.MessageException; -import org.sonar.core.issue.DefaultIssue; +import org.sonar.batch.index.BatchComponentCache; +import org.sonar.batch.protocol.output.BatchReport; +import org.sonar.batch.report.ReportPublisher; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.RETURNS_DEEP_STUBS; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; @@ -48,11 +59,7 @@ public class ModuleIssuesTest { static final RuleKey SQUID_RULE_KEY = RuleKey.of("squid", "AvoidCycle"); static final String SQUID_RULE_NAME = "Avoid Cycle"; - @Mock - IssueCache cache; - - @Mock - Project project; + Project project = new Project("foo").setAnalysisDate(new Date()); @Mock IssueFilters filters; @@ -62,18 +69,21 @@ public class ModuleIssuesTest { ModuleIssues moduleIssues; + BatchComponentCache componentCache = new BatchComponentCache(); + InputFile file = new DefaultInputFile("foo", "src/Foo.php").initMetadata(new FileMetadata().readMetadata(new StringReader("Foo\nBar\nBiz\n"))); + ReportPublisher reportPublisher = mock(ReportPublisher.class, RETURNS_DEEP_STUBS); + @Before - public void setUp() { - when(project.getAnalysisDate()).thenReturn(new Date()); - when(project.getEffectiveKey()).thenReturn("org.apache:struts-core"); - when(project.getRoot()).thenReturn(project); + public void prepare() { + componentCache.add(File.create("src/Foo.php").setEffectiveKey("foo:src/Foo.php"), null).setInputPath(file); } @Test public void fail_on_unknown_rule() { initModuleIssues(); - DefaultIssue issue = new DefaultIssue().setRuleKey(SQUID_RULE_KEY); - + DefaultIssue issue = new DefaultIssue() + .addLocation(new DefaultIssueLocation().onFile(file).at(file.selectLine(3)).message("Foo")) + .forRule(SQUID_RULE_KEY); try { moduleIssues.initAndAddIssue(issue); fail(); @@ -81,15 +91,16 @@ public class ModuleIssuesTest { assertThat(e).isInstanceOf(MessageException.class); } - verifyZeroInteractions(cache); + verifyZeroInteractions(reportPublisher); } @Test public void fail_if_rule_has_no_name_and_issue_has_no_message() { ruleBuilder.add(SQUID_RULE_KEY).setInternalKey(SQUID_RULE_KEY.rule()); initModuleIssues(); - DefaultIssue issue = new DefaultIssue().setRuleKey(SQUID_RULE_KEY).setMessage(""); - + DefaultIssue issue = new DefaultIssue() + .addLocation(new DefaultIssueLocation().onFile(file).at(file.selectLine(3)).message("")) + .forRule(SQUID_RULE_KEY); try { moduleIssues.initAndAddIssue(issue); fail(); @@ -97,19 +108,20 @@ public class ModuleIssuesTest { assertThat(e).isInstanceOf(MessageException.class); } - verifyZeroInteractions(cache); + verifyZeroInteractions(reportPublisher); } @Test public void ignore_null_active_rule() { ruleBuilder.add(SQUID_RULE_KEY).setName(SQUID_RULE_NAME); initModuleIssues(); - - DefaultIssue issue = new DefaultIssue().setRuleKey(SQUID_RULE_KEY); + DefaultIssue issue = new DefaultIssue() + .addLocation(new DefaultIssueLocation().onFile(file).at(file.selectLine(3)).message("Foo")) + .forRule(SQUID_RULE_KEY); boolean added = moduleIssues.initAndAddIssue(issue); assertThat(added).isFalse(); - verifyZeroInteractions(cache); + verifyZeroInteractions(reportPublisher); } @Test @@ -118,11 +130,13 @@ public class ModuleIssuesTest { activeRulesBuilder.create(SQUID_RULE_KEY).activate(); initModuleIssues(); - DefaultIssue issue = new DefaultIssue().setRuleKey(SQUID_RULE_KEY); + DefaultIssue issue = new DefaultIssue() + .addLocation(new DefaultIssueLocation().onFile(file).at(file.selectLine(3)).message("Foo")) + .forRule(SQUID_RULE_KEY); boolean added = moduleIssues.initAndAddIssue(issue); assertThat(added).isFalse(); - verifyZeroInteractions(cache); + verifyZeroInteractions(reportPublisher); } @Test @@ -131,22 +145,19 @@ public class ModuleIssuesTest { activeRulesBuilder.create(SQUID_RULE_KEY).setSeverity(Severity.INFO).activate(); initModuleIssues(); - Date analysisDate = new Date(); - when(project.getAnalysisDate()).thenReturn(analysisDate); - DefaultIssue issue = new DefaultIssue() - .setKey("ABCDE") - .setRuleKey(SQUID_RULE_KEY) - .setSeverity(Severity.CRITICAL); - when(filters.accept(issue)).thenReturn(true); + .addLocation(new DefaultIssueLocation().onFile(file).at(file.selectLine(3)).message("Foo")) + .forRule(SQUID_RULE_KEY) + .overrideSeverity(org.sonar.api.batch.rule.Severity.CRITICAL); + + when(filters.accept(any(org.sonar.core.issue.DefaultIssue.class))).thenReturn(true); boolean added = moduleIssues.initAndAddIssue(issue); assertThat(added).isTrue(); - ArgumentCaptor argument = ArgumentCaptor.forClass(DefaultIssue.class); - verify(cache).put(argument.capture()); - assertThat(argument.getValue().severity()).isEqualTo(Severity.CRITICAL); - assertThat(argument.getValue().creationDate()).isEqualTo(DateUtils.truncate(analysisDate, Calendar.SECOND)); + ArgumentCaptor argument = ArgumentCaptor.forClass(BatchReport.Issue.class); + verify(reportPublisher.getWriter()).appendComponentIssue(eq(1), argument.capture()); + assertThat(argument.getValue().getSeverity()).isEqualTo(org.sonar.batch.protocol.Constants.Severity.CRITICAL); } @Test @@ -155,17 +166,15 @@ public class ModuleIssuesTest { activeRulesBuilder.create(SQUID_RULE_KEY).setSeverity(Severity.INFO).activate(); initModuleIssues(); - Date analysisDate = new Date(); - when(project.getAnalysisDate()).thenReturn(analysisDate); - - DefaultIssue issue = new DefaultIssue().setRuleKey(SQUID_RULE_KEY).setSeverity(null); - when(filters.accept(issue)).thenReturn(true); + DefaultIssue issue = new DefaultIssue() + .addLocation(new DefaultIssueLocation().onFile(file).at(file.selectLine(3)).message("Foo")) + .forRule(SQUID_RULE_KEY); + when(filters.accept(any(org.sonar.core.issue.DefaultIssue.class))).thenReturn(true); moduleIssues.initAndAddIssue(issue); - ArgumentCaptor argument = ArgumentCaptor.forClass(DefaultIssue.class); - verify(cache).put(argument.capture()); - assertThat(argument.getValue().severity()).isEqualTo(Severity.INFO); - assertThat(argument.getValue().creationDate()).isEqualTo(DateUtils.truncate(analysisDate, Calendar.SECOND)); + ArgumentCaptor argument = ArgumentCaptor.forClass(BatchReport.Issue.class); + verify(reportPublisher.getWriter()).appendComponentIssue(eq(1), argument.capture()); + assertThat(argument.getValue().getSeverity()).isEqualTo(org.sonar.batch.protocol.Constants.Severity.INFO); } @Test @@ -174,22 +183,17 @@ public class ModuleIssuesTest { activeRulesBuilder.create(SQUID_RULE_KEY).setSeverity(Severity.INFO).setName(SQUID_RULE_NAME).activate(); initModuleIssues(); - Date analysisDate = new Date(); - when(project.getAnalysisDate()).thenReturn(analysisDate); - DefaultIssue issue = new DefaultIssue() - .setKey("ABCDE") - .setRuleKey(SQUID_RULE_KEY) - .setSeverity(Severity.CRITICAL) - .setMessage(""); - when(filters.accept(issue)).thenReturn(true); + .addLocation(new DefaultIssueLocation().onFile(file).at(file.selectLine(3)).message("")) + .forRule(SQUID_RULE_KEY); + when(filters.accept(any(org.sonar.core.issue.DefaultIssue.class))).thenReturn(true); boolean added = moduleIssues.initAndAddIssue(issue); assertThat(added).isTrue(); - ArgumentCaptor argument = ArgumentCaptor.forClass(DefaultIssue.class); - verify(cache).put(argument.capture()); - assertThat(argument.getValue().message()).isEqualTo("Avoid Cycle"); + ArgumentCaptor argument = ArgumentCaptor.forClass(BatchReport.Issue.class); + verify(reportPublisher.getWriter()).appendComponentIssue(eq(1), argument.capture()); + assertThat(argument.getValue().getMsg()).isEqualTo("Avoid Cycle"); } @Test @@ -199,23 +203,22 @@ public class ModuleIssuesTest { initModuleIssues(); DefaultIssue issue = new DefaultIssue() - .setKey("ABCDE") - .setRuleKey(SQUID_RULE_KEY) - .setSeverity(Severity.CRITICAL); + .addLocation(new DefaultIssueLocation().onFile(file).at(file.selectLine(3)).message("")) + .forRule(SQUID_RULE_KEY); - when(filters.accept(issue)).thenReturn(false); + when(filters.accept(any(org.sonar.core.issue.DefaultIssue.class))).thenReturn(false); boolean added = moduleIssues.initAndAddIssue(issue); assertThat(added).isFalse(); - verifyZeroInteractions(cache); + verifyZeroInteractions(reportPublisher); } /** * Every rules and active rules has to be added in builders before creating ModuleIssues */ private void initModuleIssues() { - moduleIssues = new ModuleIssues(activeRulesBuilder.build(), ruleBuilder.build(), cache, project, filters); + moduleIssues = new ModuleIssues(activeRulesBuilder.build(), ruleBuilder.build(), project, filters, reportPublisher, componentCache); } } diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/deprecated/DeprecatedApiMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/deprecated/DeprecatedApiMediumTest.java index f73d1c60f46..660b861bece 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/deprecated/DeprecatedApiMediumTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/deprecated/DeprecatedApiMediumTest.java @@ -19,8 +19,6 @@ */ package org.sonar.batch.mediumtest.deprecated; -import org.sonar.xoo.rule.XooRulesDefinition; - import com.google.common.collect.ImmutableMap; import java.io.File; import java.io.IOException; @@ -33,6 +31,7 @@ import org.sonar.batch.mediumtest.BatchMediumTester; import org.sonar.batch.mediumtest.TaskResult; import org.sonar.batch.protocol.input.ActiveRule; import org.sonar.xoo.XooPlugin; +import org.sonar.xoo.rule.XooRulesDefinition; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.groups.Tuple.tuple; @@ -84,13 +83,16 @@ public class DeprecatedApiMediumTest { .build()) .start(); - assertThat(result.issues()).extracting("componentKey", "message", "line").containsOnly( - tuple("com.foo.project:src/sample.xoo", "Issue created using deprecated API", null), - tuple("com.foo.project:src/sample.xoo", "Issue created using deprecated API", 1), - tuple("com.foo.project:src/package/sample.xoo", "Issue created using deprecated API", null), - tuple("com.foo.project:src/package/sample.xoo", "Issue created using deprecated API", 1), - tuple("com.foo.project:src", "Issue created using deprecated API", null), - tuple("com.foo.project:src/package", "Issue created using deprecated API", null)); + assertThat(result.issuesFor(result.inputFile("src/sample.xoo"))).extracting("msg", "line").containsOnly( + tuple("Issue created using deprecated API", 0), + tuple("Issue created using deprecated API", 1)); + assertThat(result.issuesFor(result.inputFile("src/package/sample.xoo"))).extracting("msg", "line").containsOnly( + tuple("Issue created using deprecated API", 0), + tuple("Issue created using deprecated API", 1)); + assertThat(result.issuesFor(result.inputDir("src"))).extracting("msg", "line").containsOnly( + tuple("Issue created using deprecated API", 0)); + assertThat(result.issuesFor(result.inputDir("src/package"))).extracting("msg", "line").containsOnly( + tuple("Issue created using deprecated API", 0)); } diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/fs/ProjectBuilderMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/fs/ProjectBuilderMediumTest.java index 2beb8f133b5..42ef0b87433 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/fs/ProjectBuilderMediumTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/fs/ProjectBuilderMediumTest.java @@ -19,23 +19,22 @@ */ package org.sonar.batch.mediumtest.fs; -import org.sonar.xoo.rule.XooRulesDefinition; - import com.google.common.collect.ImmutableMap; +import java.io.File; +import java.io.IOException; +import java.util.Date; +import java.util.List; import org.apache.commons.io.FileUtils; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.rules.TemporaryFolder; -import org.sonar.api.CoreProperties; import org.sonar.batch.mediumtest.BatchMediumTester; import org.sonar.batch.mediumtest.TaskResult; import org.sonar.batch.protocol.input.ActiveRule; +import org.sonar.batch.protocol.output.BatchReport.Issue; import org.sonar.xoo.XooPlugin; - -import java.io.File; -import java.io.IOException; -import java.util.Date; +import org.sonar.xoo.rule.XooRulesDefinition; import static org.assertj.core.api.Assertions.assertThat; @@ -48,7 +47,6 @@ public class ProjectBuilderMediumTest { .registerPlugin("xoo", new XooPlugin()) .addRules(new XooRulesDefinition()) .addDefaultQProfile("xoo", "Sonar Way") - .bootstrapProperties(ImmutableMap.of(CoreProperties.ANALYSIS_MODE, CoreProperties.ANALYSIS_MODE_PREVIEW)) .setPreviousAnalysisDate(new Date()) .activateRule(new ActiveRule("xoo", "OneIssuePerLine", null, "One issue per line", "MAJOR", "OneIssuePerLine.internal", "xoo")) .build(); @@ -88,19 +86,19 @@ public class ProjectBuilderMediumTest { .put("sonar.xoo.enableProjectBuilder", "true") .build()) .start(); - - assertThat(result.issues()).hasSize(10); + List issues = result.issuesFor(result.inputFile("src/sample.xoo")); + assertThat(issues).hasSize(10); boolean foundIssueAtLine1 = false; - for (org.sonar.api.issue.Issue issue : result.issues()) { - if (issue.line() == 1) { + for (Issue issue : issues) { + if (issue.getLine() == 1) { foundIssueAtLine1 = true; - assertThat(issue.componentKey()).isEqualTo("com.foo.project:module1:src/sample.xoo"); - assertThat(issue.message()).isEqualTo("This issue is generated on each line"); - assertThat(issue.effortToFix()).isNull(); + assertThat(issue.getMsg()).isEqualTo("This issue is generated on each line"); + assertThat(issue.hasEffortToFix()).isFalse(); } } assertThat(foundIssueAtLine1).isTrue(); + } @Test @@ -130,15 +128,15 @@ public class ProjectBuilderMediumTest { .build()) .start(); - assertThat(result.issues()).hasSize(10); + List issues = result.issuesFor(result.inputFile("src/sample.xoo")); + assertThat(issues).hasSize(10); boolean foundIssueAtLine1 = false; - for (org.sonar.api.issue.Issue issue : result.issues()) { - if (issue.line() == 1) { + for (Issue issue : issues) { + if (issue.getLine() == 1) { foundIssueAtLine1 = true; - assertThat(issue.componentKey()).isEqualTo("com.foo.project:module1:my-branch:src/sample.xoo"); - assertThat(issue.message()).isEqualTo("This issue is generated on each line"); - assertThat(issue.effortToFix()).isNull(); + assertThat(issue.getMsg()).isEqualTo("This issue is generated on each line"); + assertThat(issue.hasEffortToFix()).isFalse(); } } assertThat(foundIssueAtLine1).isTrue(); diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/fs/RandomFsAccessMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/fs/RandomFsAccessMediumTest.java index f27f72c5769..cfbd881e224 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/fs/RandomFsAccessMediumTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/fs/RandomFsAccessMediumTest.java @@ -19,9 +19,11 @@ */ package org.sonar.batch.mediumtest.fs; -import org.sonar.xoo.rule.XooRulesDefinition; - import com.google.common.collect.ImmutableMap; +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.List; import org.apache.commons.io.FileUtils; import org.junit.After; import org.junit.Before; @@ -32,11 +34,9 @@ import org.sonar.batch.mediumtest.BatchMediumTester; import org.sonar.batch.mediumtest.Benchmark; import org.sonar.batch.mediumtest.TaskResult; import org.sonar.batch.protocol.input.ActiveRule; +import org.sonar.batch.protocol.output.BatchReport.Issue; import org.sonar.xoo.XooPlugin; - -import java.io.File; -import java.io.IOException; -import java.nio.charset.StandardCharsets; +import org.sonar.xoo.rule.XooRulesDefinition; import static org.assertj.core.api.Assertions.assertThat; @@ -92,7 +92,8 @@ public class RandomFsAccessMediumTest { .build()) .start(); - assertThat(result.issues()).hasSize(ISSUE_COUNT); + List issues = result.issuesFor(result.inputFile("src/sample1.xoo")); + assertThat(issues).hasSize(10); bench.expectLessThanOrEqualTo("Time to create " + ISSUE_COUNT + " issues on random files using FileSystem query", System.currentTimeMillis() - start, 2000); } @@ -121,7 +122,8 @@ public class RandomFsAccessMediumTest { .build()) .start(); - assertThat(result.issues()).hasSize(ISSUE_COUNT); + List issues = result.issuesFor(result.inputFile("src/sample1.xoo")); + assertThat(issues).hasSize(10); } diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/ChecksMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/ChecksMediumTest.java index d5bd3b44c9a..fe31dbe7d25 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/ChecksMediumTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/ChecksMediumTest.java @@ -19,10 +19,10 @@ */ package org.sonar.batch.mediumtest.issues; -import org.sonar.batch.protocol.input.Rule; - -import org.sonar.xoo.rule.XooRulesDefinition; import com.google.common.collect.ImmutableMap; +import java.io.File; +import java.io.IOException; +import java.util.List; import org.apache.commons.io.FileUtils; import org.junit.After; import org.junit.Before; @@ -31,10 +31,10 @@ import org.junit.rules.TemporaryFolder; import org.sonar.batch.mediumtest.BatchMediumTester; import org.sonar.batch.mediumtest.TaskResult; import org.sonar.batch.protocol.input.ActiveRule; +import org.sonar.batch.protocol.input.Rule; +import org.sonar.batch.protocol.output.BatchReport.Issue; import org.sonar.xoo.XooPlugin; - -import java.io.File; -import java.io.IOException; +import org.sonar.xoo.rule.XooRulesDefinition; import static org.assertj.core.api.Assertions.assertThat; @@ -85,20 +85,19 @@ public class ChecksMediumTest { .build()) .start(); - assertThat(result.issues()).hasSize(2); + List issues = result.issuesFor(result.inputFile("src/sample.xoo")); + assertThat(issues).hasSize(2); boolean foundIssueAtLine1 = false; boolean foundIssueAtLine2 = false; - for (org.sonar.api.issue.Issue issue : result.issues()) { - if (issue.line() == 1) { + for (Issue issue : issues) { + if (issue.getLine() == 1) { foundIssueAtLine1 = true; - assertThat(issue.componentKey()).isEqualTo("com.foo.project:src/sample.xoo"); - assertThat(issue.message()).isEqualTo("A template rule"); + assertThat(issue.getMsg()).isEqualTo("A template rule"); } - if (issue.line() == 2) { + if (issue.getLine() == 2) { foundIssueAtLine2 = true; - assertThat(issue.componentKey()).isEqualTo("com.foo.project:src/sample.xoo"); - assertThat(issue.message()).isEqualTo("Another template rule"); + assertThat(issue.getMsg()).isEqualTo("Another template rule"); } } assertThat(foundIssueAtLine1).isTrue(); diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/IssuesMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/IssuesMediumTest.java index 1399a135f72..6979b4e6e2c 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/IssuesMediumTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/IssuesMediumTest.java @@ -19,25 +19,23 @@ */ package org.sonar.batch.mediumtest.issues; -import org.sonar.api.issue.Issue; -import org.sonar.batch.bootstrapper.IssueListener; -import org.sonar.xoo.rule.XooRulesDefinition; import com.google.common.collect.ImmutableMap; +import java.io.File; +import java.io.IOException; +import java.util.LinkedList; +import java.util.List; import org.apache.commons.io.FileUtils; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.rules.TemporaryFolder; -import org.sonar.api.batch.rule.Severity; +import org.sonar.batch.bootstrapper.IssueListener; import org.sonar.batch.mediumtest.BatchMediumTester; import org.sonar.batch.mediumtest.TaskResult; import org.sonar.batch.protocol.input.ActiveRule; +import org.sonar.batch.protocol.output.BatchReport.Issue; import org.sonar.xoo.XooPlugin; - -import java.io.File; -import java.io.IOException; -import java.util.LinkedList; -import java.util.List; +import org.sonar.xoo.rule.XooRulesDefinition; import static org.assertj.core.api.Assertions.assertThat; @@ -52,44 +50,15 @@ public class IssuesMediumTest { .addRules(new XooRulesDefinition()) .activateRule(new ActiveRule("xoo", "OneIssuePerLine", null, "One issue per line", "MAJOR", "OneIssuePerLine.internal", "xoo")) .build(); - - public BatchMediumTester testerPreview = BatchMediumTester.builder() - .registerPlugin("xoo", new XooPlugin()) - .addDefaultQProfile("xoo", "Sonar Way") - .bootstrapProperties(ImmutableMap.of("sonar.analysis.mode", "preview")) - .addRules(new XooRulesDefinition()) - .activateRule(new ActiveRule("xoo", "OneIssuePerLine", null, "One issue per line", "MAJOR", "OneIssuePerLine.internal", "xoo")) - .build(); @Before public void prepare() { tester.start(); - testerPreview.start(); } @After public void stop() { tester.stop(); - testerPreview.stop(); - } - - @Test - public void testIssueCallback() throws Exception { - File projectDir = new File(IssuesMediumTest.class.getResource("/mediumtest/xoo/sample").toURI()); - File tmpDir = temp.newFolder(); - FileUtils.copyDirectory(projectDir, tmpDir); - IssueRecorder issueListener = new IssueRecorder(); - - TaskResult result = testerPreview - .newScanTask(new File(tmpDir, "sonar-project.properties")) - .setIssueListener(issueListener) - .property("sonar.analysis.mode", "preview") - .start(); - - assertThat(result.issues()).hasSize(14); - assertThat(issueListener.issueList).hasSize(14); - - assertThat(result.issues()).containsExactlyElementsOf(issueListener.issueList); } @Test @@ -104,7 +73,7 @@ public class IssuesMediumTest { .setIssueListener(issueListener) .start(); - assertThat(result.issues()).hasSize(14); + assertThat(result.issuesFor(result.inputFile("xources/hello/HelloJava.xoo"))).hasSize(8); assertThat(issueListener.issueList).hasSize(0); } @@ -118,7 +87,8 @@ public class IssuesMediumTest { .newScanTask(new File(tmpDir, "sonar-project.properties")) .start(); - assertThat(result.issues()).hasSize(14); + List issues = result.issuesFor(result.inputFile("xources/hello/HelloJava.xoo")); + assertThat(issues).hasSize(8 /* lines */); } @Test @@ -132,7 +102,8 @@ public class IssuesMediumTest { .property("sonar.xoo.internalKey", "OneIssuePerLine.internal") .start(); - assertThat(result.issues()).hasSize(14 /* 8 + 6 lines */+ 2 /* 2 files */); + List issues = result.issuesFor(result.inputFile("xources/hello/HelloJava.xoo")); + assertThat(issues).hasSize(8 /* lines */ + 1 /* file */); } @Test @@ -146,7 +117,8 @@ public class IssuesMediumTest { .property("sonar.oneIssuePerLine.forceSeverity", "CRITICAL") .start(); - assertThat(result.issues().iterator().next().severity()).isEqualTo(Severity.CRITICAL.name()); + List issues = result.issuesFor(result.inputFile("xources/hello/HelloJava.xoo")); + assertThat(issues.get(0).getSeverity()).isEqualTo(org.sonar.batch.protocol.Constants.Severity.CRITICAL); } @Test @@ -161,7 +133,8 @@ public class IssuesMediumTest { .property("sonar.issue.ignore.allfile.1.fileRegexp", "object") .start(); - assertThat(result.issues()).hasSize(8); + assertThat(result.issuesFor(result.inputFile("xources/hello/HelloJava.xoo"))).hasSize(8 /* lines */); + assertThat(result.issuesFor(result.inputFile("xources/hello/helloscala.xoo"))).isEmpty(); } @Test @@ -186,25 +159,25 @@ public class IssuesMediumTest { .build()) .start(); - assertThat(result.issues()).hasSize(10); + List issues = result.issuesFor(result.inputFile("src/sample.xoo")); + assertThat(issues).hasSize(10); boolean foundIssueAtLine1 = false; - for (org.sonar.api.issue.Issue issue : result.issues()) { - if (issue.line() == 1) { + for (Issue issue : issues) { + if (issue.getLine() == 1) { foundIssueAtLine1 = true; - assertThat(issue.componentKey()).isEqualTo("com.foo.project:src/sample.xoo"); - assertThat(issue.message()).isEqualTo("This issue is generated on each line"); - assertThat(issue.effortToFix()).isNull(); + assertThat(issue.getMsg()).isEqualTo("This issue is generated on each line"); + assertThat(issue.hasEffortToFix()).isFalse(); } } assertThat(foundIssueAtLine1).isTrue(); } private class IssueRecorder implements IssueListener { - List issueList = new LinkedList<>(); + List issueList = new LinkedList<>(); @Override - public void handle(Issue issue) { + public void handle(org.sonar.api.issue.Issue issue) { issueList.add(issue); } } diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/IssuesOnDirMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/IssuesOnDirMediumTest.java index 2d389a5d8cf..d181918a16b 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/IssuesOnDirMediumTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/IssuesOnDirMediumTest.java @@ -19,9 +19,9 @@ */ package org.sonar.batch.mediumtest.issues; -import org.sonar.xoo.rule.XooRulesDefinition; - import com.google.common.collect.ImmutableMap; +import java.io.File; +import java.io.IOException; import org.apache.commons.io.FileUtils; import org.junit.After; import org.junit.Before; @@ -31,9 +31,7 @@ import org.sonar.batch.mediumtest.BatchMediumTester; import org.sonar.batch.mediumtest.TaskResult; import org.sonar.batch.protocol.input.ActiveRule; import org.sonar.xoo.XooPlugin; - -import java.io.File; -import java.io.IOException; +import org.sonar.xoo.rule.XooRulesDefinition; import static org.assertj.core.api.Assertions.assertThat; @@ -84,9 +82,7 @@ public class IssuesOnDirMediumTest { .build()) .start(); - assertThat(result.issues()).hasSize(2); - assertThat(result.issues().iterator().next().componentKey()).isEqualTo("com.foo.project:src"); - + assertThat(result.issuesFor(result.inputDir("src"))).hasSize(2); } } diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/MultilineIssuesMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/MultilineIssuesMediumTest.java index 02b61ca0cdb..a9c1317b014 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/MultilineIssuesMediumTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/MultilineIssuesMediumTest.java @@ -19,12 +19,7 @@ */ package org.sonar.batch.mediumtest.issues; -import org.sonar.xoo.rule.XooRulesDefinition; - -import org.sonar.batch.protocol.input.Rule; - import java.io.File; - import org.apache.commons.io.FileUtils; import org.junit.After; import org.junit.Before; @@ -33,7 +28,10 @@ import org.junit.rules.TemporaryFolder; import org.sonar.batch.mediumtest.BatchMediumTester; import org.sonar.batch.mediumtest.TaskResult; import org.sonar.batch.protocol.input.ActiveRule; +import org.sonar.batch.protocol.input.Rule; import org.sonar.xoo.XooPlugin; +import org.sonar.xoo.rule.XooRulesDefinition; + import static org.assertj.core.api.Assertions.assertThat; public class MultilineIssuesMediumTest { @@ -69,7 +67,7 @@ public class MultilineIssuesMediumTest { .newScanTask(new File(tmpDir, "sonar-project.properties")) .start(); - assertThat(result.issues()).hasSize(1); + assertThat(result.issuesFor(result.inputFile("xources/hello/HelloJava.xoo"))).hasSize(1); } diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/preview/EmptyFileTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/preview/EmptyFileTest.java index 3f7be697caf..37cb1fd994d 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/preview/EmptyFileTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/preview/EmptyFileTest.java @@ -75,7 +75,7 @@ public class EmptyFileTest { .property("sonar.xoo.internalKey", "my/internal/key") .start(); - assertThat(result.issues()).hasSize(11); + assertThat(result.trackedIssues()).hasSize(11); } } diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/preview/IncrementalModeMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/preview/IncrementalModeMediumTest.java index 86697dcea42..6d1685a3d1f 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/preview/IncrementalModeMediumTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/preview/IncrementalModeMediumTest.java @@ -19,9 +19,11 @@ */ package org.sonar.batch.mediumtest.preview; -import org.sonar.xoo.rule.XooRulesDefinition; - import com.google.common.collect.ImmutableMap; +import java.io.File; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.io.FileUtils; import org.junit.After; @@ -29,20 +31,17 @@ import org.junit.Before; import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.sonar.api.CoreProperties; -import org.sonar.api.issue.Issue; +import org.sonar.api.rule.RuleKey; import org.sonar.batch.mediumtest.BatchMediumTester; import org.sonar.batch.mediumtest.TaskResult; import org.sonar.batch.protocol.Constants.Severity; import org.sonar.batch.protocol.input.ActiveRule; import org.sonar.batch.protocol.input.FileData; import org.sonar.xoo.XooPlugin; - -import java.io.File; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; +import org.sonar.xoo.rule.XooRulesDefinition; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.groups.Tuple.tuple; public class IncrementalModeMediumTest { @@ -143,21 +142,14 @@ public class IncrementalModeMediumTest { .build()) .start(); - int newIssues = 0; - int openIssues = 0; - int resolvedIssue = 0; - for (Issue issue : result.issues()) { - if (issue.isNew()) { - newIssues++; - } else if (issue.resolution() != null) { - resolvedIssue++; - } else { - openIssues++; - } - } - assertThat(newIssues).isEqualTo(4); - assertThat(openIssues).isEqualTo(2); - assertThat(resolvedIssue).isEqualTo(1); + assertThat(result.trackedIssues()).extracting("ruleKey", "line", "message", "status", "resolution", "new").containsOnly( + tuple(RuleKey.of("xoo", "OneIssuePerLine"), 1, "This issue is generated on each line", "OPEN", null, false), + tuple(RuleKey.of("xoo", "OneIssuePerLine"), 2, "This issue is generated on each line", "OPEN", null, true), + tuple(RuleKey.of("xoo", "OneIssuePerLine"), 3, "This issue is generated on each line", "OPEN", null, true), + tuple(RuleKey.of("xoo", "OneIssuePerLine"), 4, "This issue is generated on each line", "OPEN", null, true), + tuple(RuleKey.of("xoo", "OneIssuePerLine"), 5, "This issue is generated on each line", "OPEN", null, true), + tuple(RuleKey.of("manual", "MyManualIssue"), 4, null, "OPEN", null, false), + tuple(RuleKey.of("xoo", "OneIssuePerFile"), null, "An issue that is no more detected", "CLOSED", "REMOVED", false)); } } diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/preview/PreviewAndReportsMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/preview/PreviewAndReportsMediumTest.java index e09631ac9fd..3ba49c04107 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/preview/PreviewAndReportsMediumTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/preview/PreviewAndReportsMediumTest.java @@ -19,12 +19,16 @@ */ package org.sonar.batch.mediumtest.preview; -import org.sonar.batch.protocol.input.Rule; - -import org.sonar.xoo.rule.XooRulesDefinition; import com.google.common.collect.ImmutableMap; +import java.io.File; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.io.FileUtils; +import org.apache.commons.io.filefilter.FileFilterUtils; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -32,17 +36,16 @@ import org.junit.rules.TemporaryFolder; import org.sonar.api.CoreProperties; import org.sonar.api.issue.Issue; import org.sonar.api.utils.log.LogTester; +import org.sonar.batch.bootstrapper.IssueListener; import org.sonar.batch.mediumtest.BatchMediumTester; import org.sonar.batch.mediumtest.TaskResult; +import org.sonar.batch.mediumtest.issues.IssuesMediumTest; import org.sonar.batch.protocol.Constants.Severity; import org.sonar.batch.protocol.input.ActiveRule; +import org.sonar.batch.protocol.input.Rule; import org.sonar.batch.scan.report.ConsoleReport; import org.sonar.xoo.XooPlugin; - -import java.io.File; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; +import org.sonar.xoo.rule.XooRulesDefinition; import static org.assertj.core.api.Assertions.assertThat; @@ -131,9 +134,16 @@ public class PreviewAndReportsMediumTest { tester.stop(); } + private File copyProject(String path) throws Exception { + File projectDir = temp.newFolder(); + File originalProjectDir = new File(PreviewAndReportsMediumTest.class.getResource(path).toURI()); + FileUtils.copyDirectory(originalProjectDir, projectDir, FileFilterUtils.notFileFilter(FileFilterUtils.nameFileFilter(".sonar"))); + return projectDir; + } + @Test public void testIssueTracking() throws Exception { - File projectDir = new File(PreviewAndReportsMediumTest.class.getResource("/mediumtest/xoo/sample").toURI()); + File projectDir = copyProject("/mediumtest/xoo/sample"); TaskResult result = tester .newScanTask(new File(projectDir, "sonar-project.properties")) @@ -142,7 +152,7 @@ public class PreviewAndReportsMediumTest { int newIssues = 0; int openIssues = 0; int resolvedIssue = 0; - for (Issue issue : result.issues()) { + for (Issue issue : result.trackedIssues()) { if (issue.isNew()) { newIssues++; } else if (issue.resolution() != null) { @@ -158,7 +168,7 @@ public class PreviewAndReportsMediumTest { @Test public void testConsoleReport() throws Exception { - File projectDir = new File(PreviewAndReportsMediumTest.class.getResource("/mediumtest/xoo/sample").toURI()); + File projectDir = copyProject("/mediumtest/xoo/sample"); tester .newScanTask(new File(projectDir, "sonar-project.properties")) @@ -170,7 +180,7 @@ public class PreviewAndReportsMediumTest { @Test public void testPostJob() throws Exception { - File projectDir = new File(PreviewAndReportsMediumTest.class.getResource("/mediumtest/xoo/sample").toURI()); + File projectDir = copyProject("/mediumtest/xoo/sample"); tester .newScanTask(new File(projectDir, "sonar-project.properties")) @@ -191,7 +201,7 @@ public class PreviewAndReportsMediumTest { @Test public void testHtmlReport() throws Exception { - File projectDir = new File(PreviewAndReportsMediumTest.class.getResource("/mediumtest/xoo/sample").toURI()); + File projectDir = copyProject("/mediumtest/xoo/sample"); tester .newScanTask(new File(projectDir, "sonar-project.properties")) @@ -225,4 +235,30 @@ public class PreviewAndReportsMediumTest { assertThat(FileUtils.readFileToString(new File(baseDir, ".sonar/issues-report/issues-report-light.html"))).contains("No file analyzed"); } + @Test + public void testIssueCallback() throws Exception { + File projectDir = new File(IssuesMediumTest.class.getResource("/mediumtest/xoo/sample").toURI()); + File tmpDir = temp.newFolder(); + FileUtils.copyDirectory(projectDir, tmpDir); + IssueRecorder issueListener = new IssueRecorder(); + + TaskResult result = tester + .newScanTask(new File(tmpDir, "sonar-project.properties")) + .setIssueListener(issueListener) + .start(); + + assertThat(result.trackedIssues()).hasSize(14); + assertThat(issueListener.issueList).hasSize(14); + assertThat(result.trackedIssues()).containsExactlyElementsOf(issueListener.issueList); + } + + private class IssueRecorder implements IssueListener { + List issueList = new LinkedList<>(); + + @Override + public void handle(org.sonar.api.issue.Issue issue) { + issueList.add(issue); + } + } + } diff --git a/sonar-batch/src/test/java/org/sonar/batch/report/IssuesPublisherTest.java b/sonar-batch/src/test/java/org/sonar/batch/report/IssuesPublisherTest.java deleted file mode 100644 index 3e0f79030bf..00000000000 --- a/sonar-batch/src/test/java/org/sonar/batch/report/IssuesPublisherTest.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * 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 java.util.Collections; -import java.util.Date; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.sonar.api.batch.bootstrap.ProjectDefinition; -import org.sonar.api.resources.Project; -import org.sonar.api.rule.RuleKey; -import org.sonar.batch.index.BatchComponentCache; -import org.sonar.batch.issue.IssueCache; -import org.sonar.batch.protocol.output.BatchReportReader; -import org.sonar.batch.protocol.output.BatchReportWriter; -import org.sonar.core.issue.DefaultIssue; -import org.sonar.core.issue.FieldDiffs; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class IssuesPublisherTest { - - @Rule - public TemporaryFolder temp = new TemporaryFolder(); - - IssueCache issueCache; - ProjectDefinition projectDef; - Project project; - - IssuesPublisher underTest; - - @Before - public void prepare() { - projectDef = ProjectDefinition.create().setKey("foo"); - project = new Project("foo").setAnalysisDate(new Date(1234567L)); - BatchComponentCache componentCache = new BatchComponentCache(); - 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); - issueCache = mock(IssueCache.class); - when(issueCache.byComponent(anyString())).thenReturn(Collections.emptyList()); - underTest = new IssuesPublisher(componentCache, issueCache); - } - - @Test - public void write_issues() throws Exception { - DefaultIssue issue1 = new DefaultIssue(); - issue1.setKey("uuid"); - issue1.setSeverity("MAJOR"); - issue1.setRuleKey(RuleKey.of("repo", "rule")); - DefaultIssue issue2 = new DefaultIssue(); - issue2.setKey("uuid2"); - issue2.setSeverity("MAJOR"); - issue2.setRuleKey(RuleKey.of("repo", "rule")); - issue2.setLine(2); - issue2.setMessage("msg"); - issue2.setEffortToFix(2d); - issue2.setResolution("FIXED"); - issue2.setStatus("RESOLVED"); - issue2.setChecksum("checksum"); - issue2.setReporter("reporter"); - issue2.setAssignee("assignee"); - issue2.setActionPlanKey("action"); - issue2.setAuthorLogin("author"); - issue2.setCurrentChange(new FieldDiffs().setUserLogin("foo")); - issue2.setCreationDate(new Date()); - issue2.setUpdateDate(new Date()); - issue2.setCloseDate(new Date()); - issue2.setSelectedAt(1234L); - when(issueCache.byComponent("foo:src/Foo.php")).thenReturn(Arrays.asList(issue1, issue2)); - - File outputDir = temp.newFolder(); - BatchReportWriter writer = new BatchReportWriter(outputDir); - - underTest.publish(writer); - - BatchReportReader reader = new BatchReportReader(outputDir); - assertThat(reader.readComponentIssues(1)).hasSize(0); - assertThat(reader.readComponentIssues(2)).hasSize(2); - } - -} diff --git a/sonar-batch/src/test/java/org/sonar/batch/sensor/DefaultSensorStorageTest.java b/sonar-batch/src/test/java/org/sonar/batch/sensor/DefaultSensorStorageTest.java index aa2e32f96e6..5d8a9a5cdf3 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/sensor/DefaultSensorStorageTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/sensor/DefaultSensorStorageTest.java @@ -19,25 +19,18 @@ */ package org.sonar.batch.sensor; -import java.io.StringReader; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.rules.TemporaryFolder; import org.mockito.ArgumentCaptor; -import org.sonar.api.batch.fs.InputDir; import org.sonar.api.batch.fs.InputFile; import org.sonar.api.batch.fs.internal.DefaultFileSystem; -import org.sonar.api.batch.fs.internal.DefaultInputDir; import org.sonar.api.batch.fs.internal.DefaultInputFile; -import org.sonar.api.batch.fs.internal.FileMetadata; import org.sonar.api.batch.measure.MetricFinder; 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.sensor.issue.internal.DefaultIssue; -import org.sonar.api.batch.sensor.issue.internal.DefaultIssueLocation; import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; import org.sonar.api.config.Settings; import org.sonar.api.measures.CoreMetrics; @@ -45,7 +38,6 @@ import org.sonar.api.measures.Measure; import org.sonar.api.resources.File; import org.sonar.api.resources.Project; import org.sonar.api.resources.Resource; -import org.sonar.api.rule.RuleKey; import org.sonar.batch.duplication.DuplicationCache; import org.sonar.batch.index.BatchComponentCache; import org.sonar.batch.issue.ModuleIssues; @@ -57,7 +49,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; public class DefaultSensorStorageTest { @@ -143,66 +134,4 @@ public class DefaultSensorStorageTest { assertThat(m.getMetric()).isEqualTo(CoreMetrics.NCLOC); } - @Test - public void shouldAddIssueOnFile() { - InputFile file = new DefaultInputFile("foo", "src/Foo.php").initMetadata(new FileMetadata().readMetadata(new StringReader("Foo\nBar\nBiz\n"))); - - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(org.sonar.core.issue.DefaultIssue.class); - - sensorStorage.store(new DefaultIssue() - .addLocation(new DefaultIssueLocation().onFile(file).at(file.selectLine(3)).message("Foo")) - .forRule(RuleKey.of("foo", "bar")) - .effortToFix(10.0)); - - verify(moduleIssues).initAndAddIssue(argumentCaptor.capture()); - - org.sonar.core.issue.DefaultIssue issue = argumentCaptor.getValue(); - assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("foo", "bar")); - assertThat(issue.message()).isEqualTo("Foo"); - assertThat(issue.line()).isEqualTo(3); - assertThat(issue.severity()).isNull(); - assertThat(issue.effortToFix()).isEqualTo(10.0); - } - - @Test - public void shouldAddIssueOnDirectory() { - InputDir dir = new DefaultInputDir("foo", "src"); - - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(org.sonar.core.issue.DefaultIssue.class); - - sensorStorage.store(new DefaultIssue() - .addLocation(new DefaultIssueLocation().onDir(dir).message("Foo")) - .forRule(RuleKey.of("foo", "bar")) - .effortToFix(10.0)); - - verify(moduleIssues).initAndAddIssue(argumentCaptor.capture()); - - org.sonar.core.issue.DefaultIssue issue = argumentCaptor.getValue(); - assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("foo", "bar")); - assertThat(issue.message()).isEqualTo("Foo"); - assertThat(issue.line()).isNull(); - assertThat(issue.severity()).isNull(); - assertThat(issue.effortToFix()).isEqualTo(10.0); - } - - @Test - public void shouldAddIssueOnProject() { - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(org.sonar.core.issue.DefaultIssue.class); - - sensorStorage.store(new DefaultIssue() - .addLocation(new DefaultIssueLocation().onProject().message("Foo")) - .forRule(RuleKey.of("foo", "bar")) - .overrideSeverity(Severity.BLOCKER) - .effortToFix(10.0)); - - verify(moduleIssues).initAndAddIssue(argumentCaptor.capture()); - - org.sonar.core.issue.DefaultIssue issue = argumentCaptor.getValue(); - assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("foo", "bar")); - assertThat(issue.message()).isEqualTo("Foo"); - assertThat(issue.line()).isNull(); - assertThat(issue.severity()).isEqualTo("BLOCKER"); - assertThat(issue.effortToFix()).isEqualTo(10.0); - } - } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/issue/Issuable.java b/sonar-plugin-api/src/main/java/org/sonar/api/issue/Issuable.java index 428d49d56f0..7cf03cb0579 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/issue/Issuable.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/issue/Issuable.java @@ -133,16 +133,14 @@ public interface Issuable extends Perspective { boolean addIssue(Issue issue); /** - * Unresolved issues, including the issues reported by end-users. - *

- * {@link org.sonar.api.batch.Decorator}s calling this method must be annotated with {@code @DependsUpon(DecoratorBarriers.ISSUES_TRACKED)}. + * @deprecated since 5.2 no more decorators on batch side */ + @Deprecated List issues(); /** - * Issues marked as resolved during this scan. - *

- * {@link org.sonar.api.batch.Decorator}s calling this method must be annotated with {@code @DependsUpon(DecoratorBarriers.ISSUES_TRACKED)}. + * @deprecated since 5.2 no more decorators on batch side */ + @Deprecated List resolvedIssues(); } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/issue/IssueFilter.java b/sonar-plugin-api/src/main/java/org/sonar/api/issue/IssueFilter.java index a1fda4b1671..654d40e3a31 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/issue/IssueFilter.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/issue/IssueFilter.java @@ -19,12 +19,12 @@ */ package org.sonar.api.issue; -import org.sonar.api.batch.BatchSide; import org.sonar.api.ExtensionPoint; +import org.sonar.api.batch.BatchSide; /** * @since 3.6 - * @deprecated since 4.0 + * @deprecated since 4.0 use {@link org.sonar.api.issue.batch.IssueFilter} */ @Deprecated @BatchSide -- 2.39.5