diff options
author | Simon Brandhof <simon.brandhof@gmail.com> | 2013-05-28 14:08:36 +0200 |
---|---|---|
committer | Simon Brandhof <simon.brandhof@gmail.com> | 2013-05-28 14:08:44 +0200 |
commit | 0eddfffce1b680964cc0917cc0bdc5d505a7a167 (patch) | |
tree | 479dd529846ebd49699f559349cc2e77e3db74aa /sonar-batch/src | |
parent | 4c203b53eefd8fdef5d114f1720fbfaf5b84fb1d (diff) | |
download | sonarqube-0eddfffce1b680964cc0917cc0bdc5d505a7a167.tar.gz sonarqube-0eddfffce1b680964cc0917cc0bdc5d505a7a167.zip |
SONAR-4316 implement IssueFilter and support ViolationFilter
Diffstat (limited to 'sonar-batch/src')
16 files changed, 511 insertions, 181 deletions
diff --git a/sonar-batch/src/main/java/org/sonar/batch/ViolationFilters.java b/sonar-batch/src/main/java/org/sonar/batch/ViolationFilters.java index d6edcfc5092..3df35ee05b6 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/ViolationFilters.java +++ b/sonar-batch/src/main/java/org/sonar/batch/ViolationFilters.java @@ -31,15 +31,15 @@ public class ViolationFilters { private ViolationFilter[] filters; public ViolationFilters(ViolationFilter[] filters) { - this.filters = (filters==null ? new ViolationFilter[0] : filters); + this.filters = filters; } public ViolationFilters() { - this(null); + this(new ViolationFilter[0]); } - public ViolationFilter[] getFilters() { - return filters; + public boolean isEmpty() { + return filters.length==0; } /** diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/Bucket.java b/sonar-batch/src/main/java/org/sonar/batch/index/Bucket.java index 50e43abb197..6c253dd7e19 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/index/Bucket.java +++ b/sonar-batch/src/main/java/org/sonar/batch/index/Bucket.java @@ -37,7 +37,6 @@ public final class Bucket { private Resource resource; private ListMultimap<String, Measure> measuresByMetric = ArrayListMultimap.create(); - private List<Violation> violations = Lists.newLinkedList(); private Bucket parent; private List<Bucket> children; @@ -80,14 +79,6 @@ public final class Bucket { return parent; } - public void addViolation(Violation violation) { - violations.add(violation); - } - - public List<Violation> getViolations() { - return violations; - } - public void addMeasure(Measure measure) { List<Measure> metricMeasures = measuresByMetric.get(measure.getMetric().getKey()); @@ -109,7 +100,6 @@ public final class Bucket { public void clear() { measuresByMetric = null; - violations = null; children = null; if (parent != null) { parent.removeChild(this); diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java b/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java index 3a51f38ff0d..cef707b9799 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java +++ b/sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.java @@ -32,19 +32,16 @@ import org.sonar.api.database.model.ResourceModel; import org.sonar.api.database.model.Snapshot; import org.sonar.api.design.Dependency; import org.sonar.api.measures.*; -import org.sonar.api.profiles.RulesProfile; import org.sonar.api.resources.*; -import org.sonar.api.rules.ActiveRule; import org.sonar.api.rules.Rule; -import org.sonar.api.rules.RuleFinder; import org.sonar.api.rules.Violation; import org.sonar.api.utils.SonarException; import org.sonar.api.violations.ViolationQuery; import org.sonar.batch.DefaultResourceCreationLock; import org.sonar.batch.ProjectTree; import org.sonar.batch.ResourceFilters; -import org.sonar.batch.ViolationFilters; import org.sonar.batch.issue.DeprecatedViolations; +import org.sonar.batch.issue.ScanIssues; import org.sonar.core.component.ScanGraph; import java.util.*; @@ -53,16 +50,14 @@ public class DefaultIndex extends SonarIndex { private static final Logger LOG = LoggerFactory.getLogger(DefaultIndex.class); - private RulesProfile profile; private PersistenceManager persistence; private DefaultResourceCreationLock lock; private MetricFinder metricFinder; - private RuleFinder ruleFinder; - private ScanGraph graph; - private SnapshotCache snapshotCache; + private final ScanGraph graph; + private final SnapshotCache snapshotCache; + private final ResourceCache resourceCache; // filters - private ViolationFilters violationFilters; private ResourceFilters resourceFilters; // caches @@ -73,17 +68,18 @@ public class DefaultIndex extends SonarIndex { private Map<Resource, Map<Resource, Dependency>> incomingDependenciesByResource = Maps.newHashMap(); private ProjectTree projectTree; private final DeprecatedViolations deprecatedViolations; + private ScanIssues scanIssues; public DefaultIndex(PersistenceManager persistence, DefaultResourceCreationLock lock, ProjectTree projectTree, MetricFinder metricFinder, - RuleFinder ruleFinder, ScanGraph graph, DeprecatedViolations deprecatedViolations, SnapshotCache snapshotCache) { + ScanGraph graph, SnapshotCache snapshotCache, ResourceCache resourceCache, DeprecatedViolations deprecatedViolations) { this.persistence = persistence; this.lock = lock; this.projectTree = projectTree; this.metricFinder = metricFinder; - this.ruleFinder = ruleFinder; this.graph = graph; - this.deprecatedViolations = deprecatedViolations; this.snapshotCache = snapshotCache; + this.resourceCache = resourceCache; + this.deprecatedViolations = deprecatedViolations; } public void start() { @@ -116,13 +112,12 @@ public class DefaultIndex extends SonarIndex { return currentProject; } - public void setCurrentProject(Project project, ResourceFilters resourceFilters, ViolationFilters violationFilters, RulesProfile profile) { + public void setCurrentProject(Project project, ResourceFilters resourceFilters, ScanIssues scanIssues) { this.currentProject = project; - // the following components depend on the current project, so they need to be reloaded. + // the following components depend on the current module, so they need to be reloaded. this.resourceFilters = resourceFilters; - this.violationFilters = violationFilters; - this.profile = profile; + this.scanIssues = scanIssues; } /** @@ -321,10 +316,13 @@ public class DefaultIndex extends SonarIndex { return Collections.emptyList(); } + List<Violation> violations = deprecatedViolations.get(bucket.getResource().getEffectiveKey()); + if (violationQuery.getSwitchMode() == ViolationQuery.SwitchMode.BOTH) { + return violations; + } List<Violation> filteredViolations = Lists.newArrayList(); - ViolationQuery.SwitchMode mode = violationQuery.getSwitchMode(); - for (Violation violation : bucket.getViolations()) { - if (isFiltered(violation, mode)) { + for (Violation violation : violations) { + if (isFiltered(violation, violationQuery.getSwitchMode())) { filteredViolations.add(violation); } } @@ -352,47 +350,13 @@ public class DefaultIndex extends SonarIndex { return; } - if (rule.getId() == null) { - Rule persistedRule = ruleFinder.findByKey(rule.getRepositoryKey(), rule.getKey()); - if (persistedRule == null) { - LOG.warn("Rule does not exist. Ignoring violation {}", violation); - return; - } - violation.setRule(persistedRule); - } - Bucket bucket = checkIndexed(resource); if (bucket == null || bucket.isExcluded()) { return; } violation.setResource(bucket.getResource()); - if (addViolation(violation, bucket, force)) { - deprecatedViolations.add(violation, currentProject.getAnalysisDate()); - } - } - - private boolean addViolation(Violation violation, Bucket bucket, boolean force) { - boolean isIgnored = !force && violationFilters != null && violationFilters.isIgnored(violation); - if (isIgnored) { - return false; - } - - // TODO this code is not the responsibility of this index. It should be moved somewhere else. - if (!violation.isManual()) { - ActiveRule activeRule = profile.getActiveRule(violation.getRule()); - if (activeRule != null) { - violation.setSeverity(activeRule.getSeverity()); - } else if (currentProject.getReuseExistingRulesConfig()) { - violation.setSeverity(violation.getRule().getSeverity()); - } else { - LoggerFactory.getLogger(getClass()).debug("Rule is not activated, ignoring violation {}", violation); - return false; - } - } - - bucket.addViolation(violation); - return true; + scanIssues.initAndAddViolation(violation); } @@ -569,6 +533,7 @@ public class DefaultIndex extends SonarIndex { if (ResourceUtils.isPersistable(resource) && !Qualifiers.LIBRARY.equals(resource.getQualifier())) { graph.addComponent(resource, snapshot); snapshotCache.put(resource.getEffectiveKey(), snapshot); + resourceCache.add(resource); } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/ResourceCache.java b/sonar-batch/src/main/java/org/sonar/batch/index/ResourceCache.java new file mode 100644 index 00000000000..a6879fd751f --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/index/ResourceCache.java @@ -0,0 +1,48 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 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.index; + +import com.google.common.base.Preconditions; +import com.google.common.base.Strings; +import com.google.common.collect.Maps; +import org.sonar.api.BatchComponent; +import org.sonar.api.resources.Resource; + +import java.util.Map; + +/** + * @since 3.6 + */ +public class ResourceCache implements BatchComponent { + // resource by component key + private final Map<String, Resource> resources = Maps.newHashMap(); + + public Resource get(String componentKey) { + return resources.get(componentKey); + } + + public ResourceCache add(Resource resource) { + String componentKey = resource.getEffectiveKey(); + Preconditions.checkState(!Strings.isNullOrEmpty(componentKey), "Missing resource effective key"); + Preconditions.checkState(!resources.containsKey(componentKey), "Resource is already registered: " + componentKey); + resources.put(componentKey, resource); + return this; + } +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/issue/DeprecatedViolations.java b/sonar-batch/src/main/java/org/sonar/batch/issue/DeprecatedViolations.java index adb81f8967b..936165eae69 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/issue/DeprecatedViolations.java +++ b/sonar-batch/src/main/java/org/sonar/batch/issue/DeprecatedViolations.java @@ -19,43 +19,58 @@ */ package org.sonar.batch.issue; +import com.google.common.collect.Lists; import org.sonar.api.BatchComponent; +import org.sonar.api.issue.Issue; import org.sonar.api.resources.Resource; -import org.sonar.api.rule.RuleKey; -import org.sonar.api.rule.Severity; +import org.sonar.api.rules.Rule; +import org.sonar.api.rules.RuleFinder; +import org.sonar.api.rules.RulePriority; import org.sonar.api.rules.Violation; +import org.sonar.batch.index.ResourceCache; import org.sonar.core.issue.DefaultIssue; -import org.sonar.core.issue.DefaultIssueBuilder; import java.util.Collection; -import java.util.Date; +import java.util.List; +/** + * Bridge with violations, that have been deprecated in 3.6. + * @since 3.6 + */ public class DeprecatedViolations implements BatchComponent { - private final IssueCache cache; - - public DeprecatedViolations(IssueCache cache) { - this.cache = cache; - } + private final IssueCache issueCache; + private final RuleFinder ruleFinder; + private final ResourceCache resourceCache; - public void add(Violation violation, Date creationDate) { - DefaultIssue issue = toIssue(violation, creationDate); - cache.put(issue); + public DeprecatedViolations(IssueCache issueCache, RuleFinder ruleFinder, ResourceCache resourceCache) { + this.issueCache = issueCache; + this.ruleFinder = ruleFinder; + this.resourceCache = resourceCache; } - public Collection<Violation> get(Resource resource) { - throw new UnsupportedOperationException("TODO"); + public List<Violation> get(String componentKey) { + Collection<DefaultIssue> issues = issueCache.byComponent(componentKey); + List<Violation> violations = Lists.newArrayList(); + for (DefaultIssue issue : issues) { + violations.add(toViolation(issue)); + } + return violations; } - DefaultIssue toIssue(Violation violation, Date creationDate) { - return (DefaultIssue) new DefaultIssueBuilder() - .createdDate(creationDate) - .componentKey(violation.getResource().getEffectiveKey()) - .ruleKey(RuleKey.of(violation.getRule().getRepositoryKey(), violation.getRule().getKey())) - .effortToFix(violation.getCost()) - .line(violation.getLineId()) - .message(violation.getMessage()) - .severity(violation.getSeverity() != null ? violation.getSeverity().name() : Severity.MAJOR) - .build(); + public Violation toViolation(DefaultIssue issue) { + Rule rule = ruleFinder.findByKey(issue.ruleKey()); + Resource resource = resourceCache.get(issue.componentKey()); + Violation violation = new Violation(rule, resource); + violation.setNew(issue.isNew()); + violation.setChecksum(issue.checksum()); + violation.setMessage(issue.message()); + violation.setCost(issue.effortToFix()); + violation.setLineId(issue.line()); + violation.setCreatedAt(issue.creationDate()); + violation.setManual(issue.reporter() != null); + violation.setSeverity(RulePriority.valueOf(issue.severity())); + violation.setSwitchedOff(Issue.RESOLUTION_FALSE_POSITIVE.equals(issue.resolution())); + return violation; } } 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 new file mode 100644 index 00000000000..0488c432aed --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/issue/IssueFilters.java @@ -0,0 +1,59 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 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 org.sonar.api.BatchExtension; +import org.sonar.api.issue.Issue; +import org.sonar.api.issue.IssueFilter; +import org.sonar.api.rules.Violation; +import org.sonar.batch.ViolationFilters; +import org.sonar.core.issue.DefaultIssue; + +import javax.annotation.Nullable; + +public class IssueFilters implements BatchExtension { + + private final ViolationFilters deprecatedFilters; + private final DeprecatedViolations deprecatedViolations; + private final IssueFilter[] filters; + + public IssueFilters(ViolationFilters deprecatedFilters, DeprecatedViolations deprecatedViolations, IssueFilter[] filters) { + this.deprecatedFilters = deprecatedFilters; + this.deprecatedViolations = deprecatedViolations; + this.filters = filters; + } + + public IssueFilters(ViolationFilters deprecatedFilters, DeprecatedViolations deprecatedViolations) { + this(deprecatedFilters, deprecatedViolations, new IssueFilter[0]); + } + + public boolean accept(DefaultIssue issue, @Nullable Violation violation) { + for (IssueFilter filter : filters) { + if (!filter.accept(issue)) { + return false; + } + } + if (!deprecatedFilters.isEmpty()) { + Violation v = (violation != null ? violation : deprecatedViolations.toViolation(issue)); + return !deprecatedFilters.isIgnored(v); + } + return true; + } +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/issue/ScanIssues.java b/sonar-batch/src/main/java/org/sonar/batch/issue/ScanIssues.java index ab06a7f9cca..4d0e5863023 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/issue/ScanIssues.java +++ b/sonar-batch/src/main/java/org/sonar/batch/issue/ScanIssues.java @@ -22,25 +22,54 @@ package org.sonar.batch.issue; import org.sonar.api.BatchComponent; import org.sonar.api.profiles.RulesProfile; import org.sonar.api.resources.Project; +import org.sonar.api.rule.RuleKey; import org.sonar.api.rules.ActiveRule; +import org.sonar.api.rules.Violation; import org.sonar.core.issue.DefaultIssue; +import org.sonar.core.issue.DefaultIssueBuilder; + +import javax.annotation.Nullable; /** - * Central component to manage issues + * Initialize the issues raised during scan. */ public class ScanIssues implements BatchComponent { private final RulesProfile qProfile; private final IssueCache cache; private final Project project; + private final IssueFilters filters; - public ScanIssues(RulesProfile qProfile, IssueCache cache, Project project) { + public ScanIssues(RulesProfile qProfile, IssueCache cache, Project project, IssueFilters filters) { this.qProfile = qProfile; this.cache = cache; this.project = project; + this.filters = filters; } public boolean initAndAddIssue(DefaultIssue issue) { + return initAndAddIssue(issue, null); + } + + public boolean initAndAddViolation(Violation violation) { + DefaultIssue issue = newIssue(violation); + return initAndAddIssue(issue, violation); + } + + private DefaultIssue newIssue(Violation violation) { + return (DefaultIssue) new DefaultIssueBuilder() + .componentKey(violation.getResource().getEffectiveKey()) + .ruleKey(RuleKey.of(violation.getRule().getRepositoryKey(), violation.getRule().getKey())) + .effortToFix(violation.getCost()) + .line(violation.getLineId()) + .message(violation.getMessage()) + .severity(violation.getSeverity() != null ? violation.getSeverity().name() : null) + .build(); + } + + private boolean initAndAddIssue(DefaultIssue issue, @Nullable Violation violation) { + // TODO fail fast : if rule does not exist + ActiveRule activeRule = qProfile.getActiveRule(issue.ruleKey().repository(), issue.ruleKey().rule()); if (activeRule == null || activeRule.getRule() == null) { // rule does not exist or is not enabled -> ignore the issue @@ -52,8 +81,12 @@ public class ScanIssues implements BatchComponent { if (issue.severity() == null) { issue.setSeverity(activeRule.getSeverity().name()); } - cache.put(issue); - return true; + + if (filters.accept(issue, violation)) { + cache.put(issue); + return true; + } + return false; } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java b/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java index c40edc06c85..23a087ce155 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java @@ -25,7 +25,6 @@ import org.sonar.api.BatchExtension; import org.sonar.api.batch.InstantiationStrategy; import org.sonar.api.batch.bootstrap.ProjectDefinition; import org.sonar.api.platform.ComponentContainer; -import org.sonar.api.profiles.RulesProfile; import org.sonar.api.resources.Languages; import org.sonar.api.resources.Project; import org.sonar.api.scan.filesystem.FileExclusions; @@ -40,6 +39,7 @@ import org.sonar.batch.events.EventBus; import org.sonar.batch.index.DefaultIndex; import org.sonar.batch.index.ResourcePersister; import org.sonar.batch.issue.IssuableFactory; +import org.sonar.batch.issue.IssueFilters; import org.sonar.batch.issue.ScanIssues; import org.sonar.batch.phases.PhaseExecutor; import org.sonar.batch.phases.PhasesTimeProfiler; @@ -103,6 +103,7 @@ public class ModuleScanContainer extends ComponentContainer { BatchExtensionDictionnary.class, DefaultTimeMachine.class, ViolationFilters.class, + IssueFilters.class, ResourceFilters.class, DeprecatedJsonReport.class, JsonReport.class, @@ -136,8 +137,7 @@ public class ModuleScanContainer extends ComponentContainer { DefaultIndex index = getComponentByType(DefaultIndex.class); index.setCurrentProject(module, getComponentByType(ResourceFilters.class), - getComponentByType(ViolationFilters.class), - getComponentByType(RulesProfile.class)); + getComponentByType(ScanIssues.class)); getComponentByType(PhaseExecutor.class).execute(module); } 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 ae0bab858c4..857ffb174ab 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 @@ -89,6 +89,7 @@ public class ProjectScanContainer extends ComponentContainer { LastSnapshots.class, Caches.class, SnapshotCache.class, + ResourceCache.class, ComponentDataCache.class, ComponentDataPersister.class, diff --git a/sonar-batch/src/test/java/org/sonar/batch/index/BucketTest.java b/sonar-batch/src/test/java/org/sonar/batch/index/BucketTest.java index a61acdcbd09..89f0ddd43a8 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/index/BucketTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/index/BucketTest.java @@ -36,9 +36,9 @@ import static org.junit.internal.matchers.IsCollectionContaining.hasItem; public class BucketTest { - private JavaPackage javaPackage = new JavaPackage("org.foo"); - private JavaFile javaFile = new JavaFile("org.foo.Bar"); - private Metric ncloc = new Metric("ncloc"); + JavaPackage javaPackage = new JavaPackage("org.foo"); + JavaFile javaFile = new JavaFile("org.foo.Bar"); + Metric ncloc = new Metric("ncloc"); @Test public void shouldManageRelationships() { @@ -52,15 +52,6 @@ public class BucketTest { } @Test - public void shouldCacheViolations() { - Bucket fileBucket = new Bucket(javaFile); - Violation violation = Violation.create(Rule.create("checkstyle", "rule1", "Rule one"), javaFile); - fileBucket.addViolation(violation); - assertThat(fileBucket.getViolations().size(), is(1)); - assertThat(fileBucket.getViolations(), hasItem(violation)); - } - - @Test public void shouldAddNewMeasure() { Bucket fileBucket = new Bucket(javaFile); Measure measure = new Measure(ncloc).setValue(1200.0); diff --git a/sonar-batch/src/test/java/org/sonar/batch/index/DefaultIndexTest.java b/sonar-batch/src/test/java/org/sonar/batch/index/DefaultIndexTest.java index c23a85bdd2f..598b73750ae 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/index/DefaultIndexTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/index/DefaultIndexTest.java @@ -20,7 +20,6 @@ package org.sonar.batch.index; import org.apache.commons.lang.StringUtils; -import org.hamcrest.Matchers; import org.junit.Before; import org.junit.Test; import org.sonar.api.batch.ResourceFilter; @@ -30,15 +29,7 @@ import org.sonar.api.measures.Measure; import org.sonar.api.measures.MeasuresFilters; import org.sonar.api.measures.MetricFinder; import org.sonar.api.profiles.RulesProfile; -import org.sonar.api.resources.Directory; -import org.sonar.api.resources.File; -import org.sonar.api.resources.Java; -import org.sonar.api.resources.JavaPackage; -import org.sonar.api.resources.Language; -import org.sonar.api.resources.Library; -import org.sonar.api.resources.Project; -import org.sonar.api.resources.Qualifiers; -import org.sonar.api.resources.Resource; +import org.sonar.api.resources.*; import org.sonar.api.rules.Rule; import org.sonar.api.rules.RuleFinder; import org.sonar.api.rules.Violation; @@ -47,12 +38,10 @@ import org.sonar.api.violations.ViolationQuery; import org.sonar.batch.DefaultResourceCreationLock; import org.sonar.batch.ProjectTree; import org.sonar.batch.ResourceFilters; -import org.sonar.batch.ViolationFilters; import org.sonar.batch.issue.DeprecatedViolations; +import org.sonar.batch.issue.ScanIssues; import org.sonar.core.component.ScanGraph; -import java.util.List; - import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertThat; @@ -73,7 +62,8 @@ public class DefaultIndexTest { when(metricFinder.findByKey("ncloc")).thenReturn(CoreMetrics.NCLOC); ruleFinder = mock(RuleFinder.class); - index = new DefaultIndex(mock(PersistenceManager.class), lock, mock(ProjectTree.class), metricFinder, ruleFinder, mock(ScanGraph.class), mock(DeprecatedViolations.class), mock(SnapshotCache.class)); + index = new DefaultIndex(mock(PersistenceManager.class), lock, mock(ProjectTree.class), metricFinder, mock(ScanGraph.class), + mock(SnapshotCache.class), mock(ResourceCache.class), mock(DeprecatedViolations.class)); Project project = new Project("project"); ResourceFilter filter = new ResourceFilter() { @@ -86,7 +76,7 @@ public class DefaultIndexTest { rule = Rule.create("repoKey", "ruleKey", "Rule"); rule.setId(1); rulesProfile.activateRule(rule, null); - index.setCurrentProject(project, new ResourceFilters(new ResourceFilter[]{filter}), new ViolationFilters(), rulesProfile); + index.setCurrentProject(project, new ResourceFilters(new ResourceFilter[]{filter}), mock(ScanIssues.class)); index.doStart(project); } @@ -214,25 +204,6 @@ public class DefaultIndexTest { * See https://jira.codehaus.org/browse/SONAR-3583 */ @Test - public void should_support_violations_with_missing_rule_id() { - Rule ruleWithoutId = Rule.create("repoKey", "ruleKey", "Rule"); - Rule ruleWithId = Rule.create("repoKey", "ruleKey", "Rule"); - ruleWithId.setId(123); - when(ruleFinder.findByKey("repoKey", "ruleKey")).thenReturn(ruleWithId); - - File file = new File("org/foo/Bar.java"); - Violation violation = Violation.create(ruleWithoutId, file); - index.addViolation(violation); - - List<Violation> violations = index.getViolations(file); - assertThat(violations.size(), is(1)); - assertThat(violations.get(0).getRule().getId(), Matchers.is(123)); - } - - /** - * See https://jira.codehaus.org/browse/SONAR-3583 - */ - @Test public void should_ignore_violation_on_unknown_rules() { Rule ruleWithoutID = Rule.create("repoKey", "ruleKey", "Rule"); @@ -243,36 +214,6 @@ public class DefaultIndexTest { assertThat(index.getViolations(file).size(), is(0)); } - @Test - public void testGetViolations() { - File file = new File("org/foo/Bar.java"); - Violation violation1 = Violation.create(rule, file); - index.addViolation(violation1); - Violation violation2 = Violation.create(rule, file); - violation2.setSwitchedOff(true); - index.addViolation(violation2); - Violation violation3 = Violation.create(rule, file); - violation3.setSwitchedOff(true); - index.addViolation(violation3); - - assertThat(index.getViolations(file).size(), is(1)); - } - - @Test - public void testGetViolationsWithQuery() { - File file = new File("org/foo/Bar.java"); - Violation violation1 = Violation.create(rule, file); - index.addViolation(violation1); - Violation violation2 = Violation.create(rule, file); - violation2.setSwitchedOff(true); - index.addViolation(violation2); - Violation violation3 = Violation.create(rule, file); - violation3.setSwitchedOff(true); - index.addViolation(violation3); - - assertThat(index.getViolations(ViolationQuery.create().forResource(file).setSwitchedOff(true)).size(), is(2)); - } - @Test(expected = IllegalArgumentException.class) public void testGetViolationsWithQueryWithNoResource() { index.getViolations(ViolationQuery.create()); diff --git a/sonar-batch/src/test/java/org/sonar/batch/index/ResourceCacheTest.java b/sonar-batch/src/test/java/org/sonar/batch/index/ResourceCacheTest.java new file mode 100644 index 00000000000..ad16edcb02f --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/index/ResourceCacheTest.java @@ -0,0 +1,68 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 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.index; + +import org.junit.Test; +import org.sonar.api.resources.JavaFile; +import org.sonar.api.resources.Resource; + +import static org.fest.assertions.Assertions.assertThat; +import static org.fest.assertions.Fail.fail; + +public class ResourceCacheTest { + @Test + public void should_cache_resource() throws Exception { + ResourceCache cache = new ResourceCache(); + String componentKey = "struts:org.struts.Action"; + Resource resource = new JavaFile("org.struts.Action").setEffectiveKey(componentKey); + cache.add(resource); + + assertThat(cache.get(componentKey)).isSameAs(resource); + assertThat(cache.get("other")).isNull(); + } + + @Test + public void should_fail_if_add_twice() throws Exception { + ResourceCache cache = new ResourceCache(); + String componentKey = "struts:org.struts.Action"; + Resource resource = new JavaFile("org.struts.Action").setEffectiveKey(componentKey); + cache.add(resource); + try { + cache.add(resource); + fail(); + } catch (IllegalStateException e) { + // success + assertThat(e).hasMessage("Resource is already registered: struts:org.struts.Action"); + } + } + + @Test + public void should_fail_if_missing_component_key() throws Exception { + ResourceCache cache = new ResourceCache(); + Resource resource = new JavaFile("org.struts.Action").setEffectiveKey(null); + try { + cache.add(resource); + fail(); + } catch (IllegalStateException e) { + // success + assertThat(e).hasMessage("Missing resource effective key"); + } + } +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/index/SnapshotCacheTest.java b/sonar-batch/src/test/java/org/sonar/batch/index/SnapshotCacheTest.java index 81776a93518..29df021f0c8 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/index/SnapshotCacheTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/index/SnapshotCacheTest.java @@ -28,7 +28,7 @@ import static org.mockito.Mockito.mock; public class SnapshotCacheTest { - private Snapshot snapshot = mock(Snapshot.class); + Snapshot snapshot = mock(Snapshot.class); @Test public void should_cache_snapshots() throws Exception { @@ -49,6 +49,7 @@ public class SnapshotCacheTest { fail(); } catch (IllegalStateException e) { // success + assertThat(e).hasMessage("Component is already registered: org.apache.struts:struts-core"); } } } diff --git a/sonar-batch/src/test/java/org/sonar/batch/issue/DeprecatedViolationsTest.java b/sonar-batch/src/test/java/org/sonar/batch/issue/DeprecatedViolationsTest.java new file mode 100644 index 00000000000..bff9ae4e2d0 --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/issue/DeprecatedViolationsTest.java @@ -0,0 +1,88 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 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 org.junit.Test; +import org.sonar.api.resources.JavaFile; +import org.sonar.api.resources.Project; +import org.sonar.api.rule.RuleKey; +import org.sonar.api.rule.Severity; +import org.sonar.api.rules.Rule; +import org.sonar.api.rules.RuleFinder; +import org.sonar.api.rules.RulePriority; +import org.sonar.api.rules.Violation; +import org.sonar.batch.index.ResourceCache; +import org.sonar.core.issue.DefaultIssue; + +import java.util.Arrays; +import java.util.List; + +import static org.fest.assertions.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class DeprecatedViolationsTest { + + IssueCache issueCache = mock(IssueCache.class); + RuleFinder ruleFinder = mock(RuleFinder.class); + ResourceCache resourceCache = mock(ResourceCache.class); + DeprecatedViolations deprecatedViolations = new DeprecatedViolations(issueCache, ruleFinder, resourceCache); + + @Test + public void test_toViolation() throws Exception { + RuleKey ruleKey = RuleKey.of("squid", "AvoidCycles"); + when(ruleFinder.findByKey(ruleKey)).thenReturn(new Rule("squid", "AvoidCycles")); + when(resourceCache.get("org.apache:struts")).thenReturn(new Project("org.apache:struts")); + + DefaultIssue issue = newIssue(ruleKey); + + Violation violation = deprecatedViolations.toViolation(issue); + assertThat(violation.getLineId()).isEqualTo(42); + assertThat(violation.getSeverity()).isEqualTo(RulePriority.BLOCKER); + assertThat(violation.isManual()).isTrue(); + assertThat(violation.getRule().getRepositoryKey()).isEqualTo("squid"); + assertThat(violation.getRule().getKey()).isEqualTo("AvoidCycles"); + assertThat(violation.getResource()).isNotNull(); + } + + private DefaultIssue newIssue(RuleKey ruleKey) { + DefaultIssue issue = new DefaultIssue(); + issue.setKey("ABCDE"); + issue.setRuleKey(ruleKey); + issue.setComponentKey("org.apache:struts"); + issue.setLine(42); + issue.setEffortToFix(3.14); + issue.setReporter("leon"); + issue.setSeverity(Severity.BLOCKER); + return issue; + } + + @Test + public void test_get() throws Exception { + RuleKey ruleKey = RuleKey.of("squid", "AvoidCycles"); + when(ruleFinder.findByKey(ruleKey)).thenReturn(new Rule("squid", "AvoidCycles")); + when(resourceCache.get("org.apache:struts")).thenReturn(new Project("org.apache:struts")); + when(issueCache.byComponent("org.apache:struts")).thenReturn(Arrays.asList(newIssue(ruleKey))); + + List<Violation> violations = deprecatedViolations.get("org.apache:struts"); + + assertThat(violations).hasSize(1); + } +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/issue/IssueFiltersTest.java b/sonar-batch/src/test/java/org/sonar/batch/issue/IssueFiltersTest.java new file mode 100644 index 00000000000..731c78d536f --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/issue/IssueFiltersTest.java @@ -0,0 +1,73 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 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 org.junit.Test; +import org.sonar.api.issue.Issue; +import org.sonar.api.issue.IssueFilter; +import org.sonar.api.rules.Violation; +import org.sonar.batch.ViolationFilters; +import org.sonar.core.issue.DefaultIssue; + +import static org.fest.assertions.Assertions.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class IssueFiltersTest { + + DeprecatedViolations deprecatedViolations = mock(DeprecatedViolations.class); + ViolationFilters deprecatedFilters = mock(ViolationFilters.class); + + @Test + public void accept() throws Exception { + IssueFilter ok = mock(IssueFilter.class); + when(ok.accept(any(Issue.class))).thenReturn(true); + + IssueFilter ko = mock(IssueFilter.class); + when(ko.accept(any(Issue.class))).thenReturn(false); + + when(deprecatedFilters.isEmpty()).thenReturn(true); + IssueFilters filters = new IssueFilters(deprecatedFilters, deprecatedViolations, new IssueFilter[]{ok, ko}); + assertThat(filters.accept(new DefaultIssue(), null)).isFalse(); + + filters = new IssueFilters(deprecatedFilters, deprecatedViolations, new IssueFilter[]{ok}); + assertThat(filters.accept(new DefaultIssue(), null)).isTrue(); + + filters = new IssueFilters(deprecatedFilters, deprecatedViolations, new IssueFilter[]{ko}); + assertThat(filters.accept(new DefaultIssue(), null)).isFalse(); + } + + @Test + public void should_always_accept_if_no_filters() { + when(deprecatedFilters.isEmpty()).thenReturn(true); + IssueFilters filters = new IssueFilters(deprecatedFilters, deprecatedViolations); + assertThat(filters.accept(new DefaultIssue(), null)).isTrue(); + } + + @Test + public void should_check_deprecated_violation_filters() throws Exception { + when(deprecatedFilters.isEmpty()).thenReturn(false); + when(deprecatedFilters.isIgnored(any(Violation.class))).thenReturn(true); + IssueFilters filters = new IssueFilters(deprecatedFilters, deprecatedViolations, new IssueFilter[0]); + assertThat(filters.accept(new DefaultIssue(), null)).isFalse(); + + } +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/issue/ScanIssuesTest.java b/sonar-batch/src/test/java/org/sonar/batch/issue/ScanIssuesTest.java index 730a0508faf..a41a12657a8 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/issue/ScanIssuesTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/issue/ScanIssuesTest.java @@ -22,12 +22,15 @@ package org.sonar.batch.issue; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.sonar.api.profiles.RulesProfile; +import org.sonar.api.resources.JavaFile; import org.sonar.api.resources.Project; +import org.sonar.api.resources.Resource; import org.sonar.api.rule.RuleKey; import org.sonar.api.rule.Severity; import org.sonar.api.rules.ActiveRule; import org.sonar.api.rules.Rule; import org.sonar.api.rules.RulePriority; +import org.sonar.api.rules.Violation; import org.sonar.core.issue.DefaultIssue; import java.util.Date; @@ -40,7 +43,8 @@ public class ScanIssuesTest { IssueCache cache = mock(IssueCache.class); RulesProfile qProfile = mock(RulesProfile.class); Project project = mock(Project.class); - ScanIssues scanIssues = new ScanIssues(qProfile, cache, project); + IssueFilters filters = mock(IssueFilters.class); + ScanIssues scanIssues = new ScanIssues(qProfile, cache, project, filters); @Test public void should_ignore_null_active_rule() throws Exception { @@ -68,11 +72,11 @@ public class ScanIssuesTest { @Test public void should_add_issue_to_cache() throws Exception { - Rule rule = Rule.create("repoKey", "ruleKey"); + Rule rule = Rule.create("squid", "AvoidCycle"); ActiveRule activeRule = mock(ActiveRule.class); when(activeRule.getRule()).thenReturn(rule); when(activeRule.getSeverity()).thenReturn(RulePriority.INFO); - when(qProfile.getActiveRule(anyString(), anyString())).thenReturn(activeRule); + when(qProfile.getActiveRule("squid", "AvoidCycle")).thenReturn(activeRule); Date analysisDate = new Date(); when(project.getAnalysisDate()).thenReturn(analysisDate); @@ -81,6 +85,8 @@ public class ScanIssuesTest { .setKey("ABCDE") .setRuleKey(RuleKey.of("squid", "AvoidCycle")) .setSeverity(Severity.CRITICAL); + when(filters.accept(issue, null)).thenReturn(true); + boolean added = scanIssues.initAndAddIssue(issue); assertThat(added).isTrue(); @@ -92,16 +98,17 @@ public class ScanIssuesTest { @Test public void should_use_severity_from_active_rule_if_no_severity() throws Exception { - Rule rule = Rule.create("repoKey", "ruleKey"); + Rule rule = Rule.create("squid", "AvoidCycle"); ActiveRule activeRule = mock(ActiveRule.class); when(activeRule.getRule()).thenReturn(rule); when(activeRule.getSeverity()).thenReturn(RulePriority.INFO); - when(qProfile.getActiveRule(anyString(), anyString())).thenReturn(activeRule); + when(qProfile.getActiveRule("squid", "AvoidCycle")).thenReturn(activeRule); Date analysisDate = new Date(); when(project.getAnalysisDate()).thenReturn(analysisDate); DefaultIssue issue = new DefaultIssue().setRuleKey(RuleKey.of("squid", "AvoidCycle")).setSeverity(null); + when(filters.accept(issue, null)).thenReturn(true); scanIssues.initAndAddIssue(issue); ArgumentCaptor<DefaultIssue> argument = ArgumentCaptor.forClass(DefaultIssue.class); @@ -109,4 +116,54 @@ public class ScanIssuesTest { assertThat(argument.getValue().severity()).isEqualTo(Severity.INFO); assertThat(argument.getValue().creationDate()).isEqualTo(analysisDate); } + + @Test + public void should_add_deprecated_violation() throws Exception { + Rule rule = Rule.create("squid", "AvoidCycle"); + Resource resource = new JavaFile("org.struts.Action").setEffectiveKey("struts:org.struts.Action"); + Violation violation = new Violation(rule, resource); + violation.setLineId(42); + violation.setSeverity(RulePriority.CRITICAL); + violation.setMessage("the message"); + + ActiveRule activeRule = mock(ActiveRule.class); + when(activeRule.getRule()).thenReturn(rule); + when(activeRule.getSeverity()).thenReturn(RulePriority.INFO); + when(qProfile.getActiveRule("squid", "AvoidCycle")).thenReturn(activeRule); + when(filters.accept(any(DefaultIssue.class), eq(violation))).thenReturn(true); + + boolean added = scanIssues.initAndAddViolation(violation); + assertThat(added).isTrue(); + + ArgumentCaptor<DefaultIssue> argument = ArgumentCaptor.forClass(DefaultIssue.class); + verify(cache).put(argument.capture()); + DefaultIssue issue = argument.getValue(); + assertThat(issue.severity()).isEqualTo(Severity.CRITICAL); + assertThat(issue.line()).isEqualTo(42); + assertThat(issue.message()).isEqualTo("the message"); + assertThat(issue.key()).isNotEmpty(); + assertThat(issue.ruleKey().toString()).isEqualTo("squid:AvoidCycle"); + assertThat(issue.componentKey().toString()).isEqualTo("struts:org.struts.Action"); + } + + @Test + public void should_filter_issue() throws Exception { + Rule rule = Rule.create("squid", "AvoidCycle"); + ActiveRule activeRule = mock(ActiveRule.class); + when(activeRule.getRule()).thenReturn(rule); + when(activeRule.getSeverity()).thenReturn(RulePriority.INFO); + when(qProfile.getActiveRule("squid", "AvoidCycle")).thenReturn(activeRule); + + DefaultIssue issue = new DefaultIssue() + .setKey("ABCDE") + .setRuleKey(RuleKey.of("squid", "AvoidCycle")) + .setSeverity(Severity.CRITICAL); + + when(filters.accept(issue, null)).thenReturn(false); + + boolean added = scanIssues.initAndAddIssue(issue); + + assertThat(added).isFalse(); + verifyZeroInteractions(cache); + } } |