diff options
author | Duarte Meneses <duarte.meneses@sonarsource.com> | 2021-03-11 17:04:42 -0600 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2021-03-17 20:08:34 +0000 |
commit | 398550aef256c12cd680795699890038af2dbf8d (patch) | |
tree | a0043bb86c3a3bfcf9357e8d5dbdb3ac68fd5859 /sonar-scanner-engine | |
parent | 4e76eae61a9cc708dde1e71d1895dfbb810f63ce (diff) | |
download | sonarqube-398550aef256c12cd680795699890038af2dbf8d.tar.gz sonarqube-398550aef256c12cd680795699890038af2dbf8d.zip |
SONAR-14192 Deprecating rule keys may break users' exclusion settings
Diffstat (limited to 'sonar-scanner-engine')
12 files changed, 188 insertions, 79 deletions
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/EnforceIssuesFilter.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/EnforceIssuesFilter.java index ea5ab87d891..d29a993985b 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/EnforceIssuesFilter.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/EnforceIssuesFilter.java @@ -21,16 +21,20 @@ package org.sonar.scanner.issue.ignore; import java.util.ArrayList; import java.util.Collections; +import java.util.LinkedHashSet; import java.util.List; +import java.util.Set; import javax.annotation.concurrent.ThreadSafe; import org.sonar.api.batch.fs.InputComponent; +import org.sonar.api.batch.fs.internal.DefaultInputFile; +import org.sonar.api.batch.rule.internal.DefaultActiveRules; import org.sonar.api.notifications.AnalysisWarnings; +import org.sonar.api.rule.RuleKey; import org.sonar.api.scan.issue.filter.FilterableIssue; import org.sonar.api.scan.issue.filter.IssueFilter; import org.sonar.api.scan.issue.filter.IssueFilterChain; import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Loggers; -import org.sonar.api.batch.fs.internal.DefaultInputFile; import org.sonar.scanner.issue.DefaultFilterableIssue; import org.sonar.scanner.issue.ignore.pattern.IssueInclusionPatternInitializer; import org.sonar.scanner.issue.ignore.pattern.IssuePattern; @@ -41,12 +45,15 @@ public class EnforceIssuesFilter implements IssueFilter { private final List<IssuePattern> multicriteriaPatterns; private final AnalysisWarnings analysisWarnings; + private final DefaultActiveRules activeRules; + private final Set<RuleKey> warnedDeprecatedRuleKeys = new LinkedHashSet<>(); private boolean warnDeprecatedIssuePatternAlreadyLogged; - public EnforceIssuesFilter(IssueInclusionPatternInitializer patternInitializer, AnalysisWarnings analysisWarnings) { + public EnforceIssuesFilter(IssueInclusionPatternInitializer patternInitializer, AnalysisWarnings analysisWarnings, DefaultActiveRules activeRules) { this.multicriteriaPatterns = Collections.unmodifiableList(new ArrayList<>(patternInitializer.getMulticriteriaPatterns())); this.analysisWarnings = analysisWarnings; + this.activeRules = activeRules; } @Override @@ -56,7 +63,7 @@ public class EnforceIssuesFilter implements IssueFilter { IssuePattern matchingPattern = null; for (IssuePattern pattern : multicriteriaPatterns) { - if (pattern.matchRule(issue.ruleKey())) { + if (ruleMatches(pattern, issue.ruleKey())) { atLeastOneRuleMatched = true; InputComponent component = ((DefaultFilterableIssue) issue).getComponent(); if (component.isFile()) { @@ -78,7 +85,7 @@ public class EnforceIssuesFilter implements IssueFilter { if (atLeastOneRuleMatched) { if (atLeastOnePatternFullyMatched) { - LOG.debug("Issue {} enforced by pattern {}", issue, matchingPattern); + LOG.debug("Issue '{}' enforced by pattern '{}'", issue, matchingPattern); } return atLeastOnePatternFullyMatched; } else { @@ -86,6 +93,19 @@ public class EnforceIssuesFilter implements IssueFilter { } } + private boolean ruleMatches(IssuePattern pattern, RuleKey ruleKey) { + if (activeRules.matchesDeprecatedKeys(ruleKey, pattern.getRulePattern())) { + String msg = String.format("The issue multicriteria pattern '%s' matches a rule key that has been changed. The pattern should be updated to '%s'", + pattern.getRulePattern(), ruleKey); + analysisWarnings.addUnique(msg); + if (warnedDeprecatedRuleKeys.add(ruleKey)) { + LOG.warn(msg); + } + return true; + } + return pattern.matchRule(ruleKey); + } + private void warnOnceDeprecatedIssuePattern(String msg) { if (!warnDeprecatedIssuePatternAlreadyLogged) { LOG.warn(msg); diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/IgnoreIssuesFilter.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/IgnoreIssuesFilter.java index 7c6e8db2596..23aeea36e18 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/IgnoreIssuesFilter.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/IgnoreIssuesFilter.java @@ -21,11 +21,16 @@ package org.sonar.scanner.issue.ignore; import java.util.Collections; import java.util.HashMap; +import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Set; import org.sonar.api.batch.fs.InputComponent; import org.sonar.api.batch.fs.internal.DefaultInputFile; +import org.sonar.api.batch.rule.internal.DefaultActiveRules; +import org.sonar.api.notifications.AnalysisWarnings; +import org.sonar.api.rule.RuleKey; import org.sonar.api.scan.issue.filter.FilterableIssue; import org.sonar.api.scan.issue.filter.IssueFilter; import org.sonar.api.scan.issue.filter.IssueFilterChain; @@ -36,10 +41,17 @@ import org.sonar.scanner.issue.DefaultFilterableIssue; public class IgnoreIssuesFilter implements IssueFilter { - private Map<InputComponent, List<WildcardPattern>> rulePatternByComponent = new HashMap<>(); - + private final DefaultActiveRules activeRules; + private final AnalysisWarnings analysisWarnings; + private final Map<InputComponent, List<WildcardPattern>> rulePatternByComponent = new HashMap<>(); + private final Set<RuleKey> warnedDeprecatedRuleKeys = new LinkedHashSet<>(); private static final Logger LOG = Loggers.get(IgnoreIssuesFilter.class); + public IgnoreIssuesFilter(DefaultActiveRules activeRules, AnalysisWarnings analysisWarnings) { + this.activeRules = activeRules; + this.analysisWarnings = analysisWarnings; + } + @Override public boolean accept(FilterableIssue issue, IssueFilterChain chain) { InputComponent component = ((DefaultFilterableIssue) issue).getComponent(); @@ -73,7 +85,18 @@ public class IgnoreIssuesFilter implements IssueFilter { private boolean hasRuleMatchFor(InputComponent component, FilterableIssue issue) { for (WildcardPattern pattern : rulePatternByComponent.getOrDefault(component, Collections.emptyList())) { if (pattern.match(issue.ruleKey().toString())) { - LOG.debug("Issue {} ignored by exclusion pattern {}", issue, pattern); + LOG.debug("Issue '{}' ignored by exclusion pattern '{}'", issue, pattern); + return true; + } + + RuleKey ruleKey = issue.ruleKey(); + if (activeRules.matchesDeprecatedKeys(ruleKey, pattern)) { + String msg = String.format("The issue multicriteria pattern '%s' matches a rule key that has been changed. The pattern should be updated to '%s'", pattern, ruleKey); + analysisWarnings.addUnique(msg); + if (warnedDeprecatedRuleKeys.add(ruleKey)) { + LOG.warn(msg); + } + LOG.debug("Issue '{}' ignored by exclusion pattern '{}' matching a deprecated rule key", issue, pattern); return true; } } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/AbstractPatternInitializer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/AbstractPatternInitializer.java index cd106fd45b7..3ad758dcc45 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/AbstractPatternInitializer.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/AbstractPatternInitializer.java @@ -26,7 +26,7 @@ import org.sonar.api.config.Configuration; import org.sonar.api.utils.MessageException; public abstract class AbstractPatternInitializer { - private Configuration settings; + private final Configuration settings; private List<IssuePattern> multicriteriaPatterns; protected AbstractPatternInitializer(Configuration config) { @@ -63,7 +63,7 @@ public abstract class AbstractPatternInitializer { if (StringUtils.isBlank(ruleKeyPattern)) { throw MessageException.of("Issue exclusions are misconfigured. Rule key pattern is mandatory for each entry of '" + getMulticriteriaConfigurationKey() + "'"); } - IssuePattern pattern = new IssuePattern(filePathPattern != null ? filePathPattern : "*", ruleKeyPattern != null ? ruleKeyPattern : "*"); + IssuePattern pattern = new IssuePattern(filePathPattern, ruleKeyPattern); multicriteriaPatterns.add(pattern); } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssuePattern.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssuePattern.java index 095b429969a..03bf6a5d78b 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssuePattern.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/ignore/pattern/IssuePattern.java @@ -19,6 +19,7 @@ */ package org.sonar.scanner.issue.ignore.pattern; +import com.google.common.base.MoreObjects; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; import org.sonar.api.rule.RuleKey; @@ -47,4 +48,12 @@ public class IssuePattern { return filePath != null && filePattern.match(filePath); } + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("filePattern", filePattern) + .add("rulePattern", rulePattern) + .toString(); + } + } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/ActiveRulesProvider.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/ActiveRulesProvider.java index 848dc68a252..935498f209a 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/ActiveRulesProvider.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/rule/ActiveRulesProvider.java @@ -26,9 +26,9 @@ import java.util.List; import java.util.Map; import java.util.Set; import org.picocontainer.injectors.ProviderAdapter; -import org.sonar.api.batch.rule.ActiveRules; -import org.sonar.api.batch.rule.internal.ActiveRulesBuilder; import org.sonar.api.batch.rule.LoadedActiveRule; +import org.sonar.api.batch.rule.internal.ActiveRulesBuilder; +import org.sonar.api.batch.rule.internal.DefaultActiveRules; import org.sonar.api.batch.rule.internal.NewActiveRule; import org.sonar.api.rule.RuleKey; import org.sonar.api.utils.log.Logger; @@ -42,9 +42,9 @@ import org.sonar.api.utils.log.Profiler; public class ActiveRulesProvider extends ProviderAdapter { private static final Logger LOG = Loggers.get(ActiveRulesProvider.class); private static final String LOG_MSG = "Load active rules"; - private ActiveRules singleton = null; + private DefaultActiveRules singleton = null; - public ActiveRules provide(ActiveRulesLoader loader, QualityProfiles qProfiles) { + public DefaultActiveRules provide(ActiveRulesLoader loader, QualityProfiles qProfiles) { if (singleton == null) { Profiler profiler = Profiler.create(LOG).startInfo(LOG_MSG); singleton = load(loader, qProfiles); @@ -53,7 +53,7 @@ public class ActiveRulesProvider extends ProviderAdapter { return singleton; } - private static ActiveRules load(ActiveRulesLoader loader, QualityProfiles qProfiles) { + private static DefaultActiveRules load(ActiveRulesLoader loader, QualityProfiles qProfiles) { Collection<String> qProfileKeys = getKeys(qProfiles); Set<RuleKey> loadedRulesKey = new HashSet<>(); @@ -65,7 +65,7 @@ public class ActiveRulesProvider extends ProviderAdapter { for (LoadedActiveRule r : qProfileRules) { if (!loadedRulesKey.contains(r.getRuleKey())) { loadedRulesKey.add(r.getRuleKey()); - builder.addRule(transform(r, qProfileKey)); + builder.addRule(transform(r, qProfileKey, r.getDeprecatedKeys())); } } } @@ -73,7 +73,7 @@ public class ActiveRulesProvider extends ProviderAdapter { return builder.build(); } - private static NewActiveRule transform(LoadedActiveRule activeRule, String qProfileKey) { + private static NewActiveRule transform(LoadedActiveRule activeRule, String qProfileKey, Set<RuleKey> deprecatedKeys) { NewActiveRule.Builder builder = new NewActiveRule.Builder(); builder .setRuleKey(activeRule.getRuleKey()) @@ -84,7 +84,8 @@ public class ActiveRulesProvider extends ProviderAdapter { .setLanguage(activeRule.getLanguage()) .setInternalKey(activeRule.getInternalKey()) .setTemplateRuleKey(activeRule.getTemplateRuleKey()) - .setQProfileKey(qProfileKey); + .setQProfileKey(qProfileKey) + .setDeprecatedKeys(deprecatedKeys); // load parameters if (activeRule.getParams() != null) { for (Map.Entry<String, String> params : activeRule.getParams().entrySet()) { diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/EnforceIssuesFilterTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/EnforceIssuesFilterTest.java index 5391760024d..c28628d5b51 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/EnforceIssuesFilterTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/EnforceIssuesFilterTest.java @@ -20,6 +20,7 @@ package org.sonar.scanner.issue.ignore; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; import java.io.IOException; import org.junit.Before; import org.junit.Rule; @@ -27,6 +28,8 @@ import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.sonar.api.batch.fs.InputComponent; import org.sonar.api.batch.fs.internal.TestInputFileBuilder; +import org.sonar.api.batch.rule.internal.DefaultActiveRules; +import org.sonar.api.batch.rule.internal.NewActiveRule; import org.sonar.api.notifications.AnalysisWarnings; import org.sonar.api.rule.RuleKey; import org.sonar.api.scan.issue.filter.IssueFilterChain; @@ -34,10 +37,11 @@ import org.sonar.scanner.issue.DefaultFilterableIssue; import org.sonar.scanner.issue.ignore.pattern.IssueInclusionPatternInitializer; import org.sonar.scanner.issue.ignore.pattern.IssuePattern; +import static java.util.Collections.singleton; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; public class EnforceIssuesFilterTest { @@ -45,59 +49,74 @@ public class EnforceIssuesFilterTest { @Rule public TemporaryFolder tempFolder = new TemporaryFolder(); - private IssueInclusionPatternInitializer exclusionPatternInitializer; + private final IssueInclusionPatternInitializer exclusionPatternInitializer = mock(IssueInclusionPatternInitializer.class); + private final DefaultFilterableIssue issue = mock(DefaultFilterableIssue.class); + private final IssueFilterChain chain = mock(IssueFilterChain.class); + private final AnalysisWarnings analysisWarnings = mock(AnalysisWarnings.class); private EnforceIssuesFilter ignoreFilter; - private DefaultFilterableIssue issue; - private IssueFilterChain chain; @Before public void init() { - exclusionPatternInitializer = mock(IssueInclusionPatternInitializer.class); - issue = mock(DefaultFilterableIssue.class); - chain = mock(IssueFilterChain.class); when(chain.accept(issue)).thenReturn(true); } @Test public void shouldPassToChainIfNoConfiguredPatterns() { - ignoreFilter = new EnforceIssuesFilter(exclusionPatternInitializer, mock(AnalysisWarnings.class)); + DefaultActiveRules activeRules = new DefaultActiveRules(ImmutableSet.of()); + ignoreFilter = new EnforceIssuesFilter(exclusionPatternInitializer, analysisWarnings, activeRules); assertThat(ignoreFilter.accept(issue, chain)).isTrue(); verify(chain).accept(issue); } @Test public void shouldPassToChainIfRuleDoesNotMatch() { - String rule = "rule"; - RuleKey ruleKey = mock(RuleKey.class); - when(ruleKey.toString()).thenReturn(rule); + DefaultActiveRules activeRules = new DefaultActiveRules(ImmutableSet.of()); + RuleKey ruleKey = RuleKey.of("repo", "rule"); when(issue.ruleKey()).thenReturn(ruleKey); - IssuePattern matching = mock(IssuePattern.class); - when(matching.matchRule(ruleKey)).thenReturn(false); + IssuePattern matching = new IssuePattern("**", "unknown"); when(exclusionPatternInitializer.getMulticriteriaPatterns()).thenReturn(ImmutableList.of(matching)); - ignoreFilter = new EnforceIssuesFilter(exclusionPatternInitializer, mock(AnalysisWarnings.class)); + ignoreFilter = new EnforceIssuesFilter(exclusionPatternInitializer, analysisWarnings, activeRules); assertThat(ignoreFilter.accept(issue, chain)).isTrue(); verify(chain).accept(issue); } @Test public void shouldAcceptIssueIfFullyMatched() { - String rule = "rule"; + DefaultActiveRules activeRules = new DefaultActiveRules(ImmutableSet.of()); String path = "org/sonar/api/Issue.java"; - RuleKey ruleKey = mock(RuleKey.class); - when(ruleKey.toString()).thenReturn(rule); + RuleKey ruleKey = RuleKey.of("repo", "rule"); when(issue.ruleKey()).thenReturn(ruleKey); - IssuePattern matching = mock(IssuePattern.class); - when(matching.matchRule(ruleKey)).thenReturn(true); - when(matching.matchFile(path)).thenReturn(true); + IssuePattern matching = new IssuePattern(path, ruleKey.toString()); when(exclusionPatternInitializer.getMulticriteriaPatterns()).thenReturn(ImmutableList.of(matching)); when(issue.getComponent()).thenReturn(createComponentWithPath(path)); - ignoreFilter = new EnforceIssuesFilter(exclusionPatternInitializer, mock(AnalysisWarnings.class)); + ignoreFilter = new EnforceIssuesFilter(exclusionPatternInitializer, analysisWarnings, activeRules); assertThat(ignoreFilter.accept(issue, chain)).isTrue(); - verifyZeroInteractions(chain); + verifyNoInteractions(chain); + } + + @Test + public void shouldAcceptIssueIfMatchesDeprecatedRuleKey() { + RuleKey ruleKey = RuleKey.of("repo", "rule"); + DefaultActiveRules activeRules = new DefaultActiveRules(ImmutableSet.of(new NewActiveRule.Builder() + .setRuleKey(ruleKey) + .setDeprecatedKeys(singleton(RuleKey.of("repo2", "deprecated"))) + .build())); + String path = "org/sonar/api/Issue.java"; + when(issue.ruleKey()).thenReturn(ruleKey); + + IssuePattern matching = new IssuePattern("org/**", "repo2:deprecated"); + when(exclusionPatternInitializer.getMulticriteriaPatterns()).thenReturn(ImmutableList.of(matching)); + when(issue.getComponent()).thenReturn(createComponentWithPath(path)); + + ignoreFilter = new EnforceIssuesFilter(exclusionPatternInitializer, analysisWarnings, activeRules); + assertThat(ignoreFilter.accept(issue, chain)).isTrue(); + verify(analysisWarnings) + .addUnique("The issue multicriteria pattern 'repo2:deprecated' matches a rule key that has been changed. The pattern should be updated to 'repo:rule'"); + verifyNoInteractions(chain); } private InputComponent createComponentWithPath(String path) { @@ -106,42 +125,35 @@ public class EnforceIssuesFilterTest { @Test public void shouldRefuseIssueIfRuleMatchesButNotPath() { - String rule = "rule"; + DefaultActiveRules activeRules = new DefaultActiveRules(ImmutableSet.of()); String path = "org/sonar/api/Issue.java"; String componentKey = "org.sonar.api.Issue"; - RuleKey ruleKey = mock(RuleKey.class); - when(ruleKey.toString()).thenReturn(rule); + RuleKey ruleKey = RuleKey.of("repo", "rule"); when(issue.ruleKey()).thenReturn(ruleKey); when(issue.componentKey()).thenReturn(componentKey); - IssuePattern matching = mock(IssuePattern.class); - when(matching.matchRule(ruleKey)).thenReturn(true); - when(matching.matchFile(path)).thenReturn(false); + IssuePattern matching = new IssuePattern("no match", "repo:rule"); when(exclusionPatternInitializer.getMulticriteriaPatterns()).thenReturn(ImmutableList.of(matching)); when(issue.getComponent()).thenReturn(createComponentWithPath(path)); - ignoreFilter = new EnforceIssuesFilter(exclusionPatternInitializer, mock(AnalysisWarnings.class)); + ignoreFilter = new EnforceIssuesFilter(exclusionPatternInitializer, analysisWarnings, activeRules); assertThat(ignoreFilter.accept(issue, chain)).isFalse(); - verifyZeroInteractions(chain); + verifyNoInteractions(chain, analysisWarnings); } @Test public void shouldRefuseIssueIfRuleMatchesAndNotFile() throws IOException { - String rule = "rule"; + DefaultActiveRules activeRules = new DefaultActiveRules(ImmutableSet.of()); String path = "org/sonar/api/Issue.java"; - String componentKey = "org.sonar.api.Issue"; - RuleKey ruleKey = mock(RuleKey.class); - when(ruleKey.toString()).thenReturn(rule); + RuleKey ruleKey = RuleKey.of("repo", "key"); when(issue.ruleKey()).thenReturn(ruleKey); - IssuePattern matching = mock(IssuePattern.class); - when(matching.matchRule(ruleKey)).thenReturn(true); - when(matching.matchFile(path)).thenReturn(true); + IssuePattern matching = new IssuePattern(path, ruleKey.toString()); when(exclusionPatternInitializer.getMulticriteriaPatterns()).thenReturn(ImmutableList.of(matching)); when(issue.getComponent()).thenReturn(TestInputFileBuilder.newDefaultInputProject("foo", tempFolder.newFolder())); - ignoreFilter = new EnforceIssuesFilter(exclusionPatternInitializer, mock(AnalysisWarnings.class)); + ignoreFilter = new EnforceIssuesFilter(exclusionPatternInitializer, analysisWarnings, activeRules); assertThat(ignoreFilter.accept(issue, chain)).isFalse(); - verifyZeroInteractions(chain); + verifyNoInteractions(chain, analysisWarnings); } } diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/IgnoreIssuesFilterTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/IgnoreIssuesFilterTest.java index 3e10340146f..1db66e55f5d 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/IgnoreIssuesFilterTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/IgnoreIssuesFilterTest.java @@ -19,27 +19,38 @@ */ package org.sonar.scanner.issue.ignore; +import com.google.common.collect.ImmutableSet; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.sonar.api.batch.fs.internal.DefaultInputFile; +import org.sonar.api.batch.rule.internal.DefaultActiveRules; +import org.sonar.api.batch.rule.internal.NewActiveRule; +import org.sonar.api.notifications.AnalysisWarnings; import org.sonar.api.rule.RuleKey; import org.sonar.api.scan.issue.filter.IssueFilterChain; import org.sonar.api.utils.WildcardPattern; -import org.sonar.api.batch.fs.internal.DefaultInputFile; +import org.sonar.api.utils.log.LogTester; import org.sonar.scanner.issue.DefaultFilterableIssue; +import static java.util.Collections.singleton; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; public class IgnoreIssuesFilterTest { + @Rule + public LogTester logTester = new LogTester(); + + private final DefaultFilterableIssue issue = mock(DefaultFilterableIssue.class); + private final IssueFilterChain chain = mock(IssueFilterChain.class); + private final AnalysisWarnings analysisWarnings = mock(AnalysisWarnings.class); + private final RuleKey ruleKey = RuleKey.of("foo", "bar"); - private DefaultFilterableIssue issue = mock(DefaultFilterableIssue.class); - private IssueFilterChain chain = mock(IssueFilterChain.class); - private IgnoreIssuesFilter underTest = new IgnoreIssuesFilter(); private DefaultInputFile component; - private RuleKey ruleKey = RuleKey.of("foo", "bar"); @Before public void prepare() { @@ -50,6 +61,9 @@ public class IgnoreIssuesFilterTest { @Test public void shouldPassToChainIfMatcherHasNoPatternForIssue() { + DefaultActiveRules activeRules = new DefaultActiveRules(ImmutableSet.of()); + IgnoreIssuesFilter underTest = new IgnoreIssuesFilter(activeRules, analysisWarnings); + when(chain.accept(issue)).thenReturn(true); assertThat(underTest.accept(issue, chain)).isTrue(); verify(chain).accept(any()); @@ -57,15 +71,39 @@ public class IgnoreIssuesFilterTest { @Test public void shouldRejectIfRulePatternMatches() { + DefaultActiveRules activeRules = new DefaultActiveRules(ImmutableSet.of()); + IgnoreIssuesFilter underTest = new IgnoreIssuesFilter(activeRules, analysisWarnings); + WildcardPattern pattern = mock(WildcardPattern.class); when(pattern.match(ruleKey.toString())).thenReturn(true); underTest.addRuleExclusionPatternForComponent(component, pattern); assertThat(underTest.accept(issue, chain)).isFalse(); + verifyNoInteractions(analysisWarnings); + } + + @Test + public void shouldRejectIfRulePatternMatchesDeprecatedRule() { + DefaultActiveRules activeRules = new DefaultActiveRules(ImmutableSet.of(new NewActiveRule.Builder() + .setRuleKey(ruleKey) + .setDeprecatedKeys(singleton(RuleKey.of("repo", "rule"))) + .build())); + IgnoreIssuesFilter underTest = new IgnoreIssuesFilter(activeRules, analysisWarnings); + + WildcardPattern pattern = WildcardPattern.create("repo:rule"); + underTest.addRuleExclusionPatternForComponent(component, pattern); + assertThat(underTest.accept(issue, chain)).isFalse(); + + verify(analysisWarnings).addUnique("The issue multicriteria pattern 'repo:rule' matches a rule key that has been changed. The pattern should be updated to 'foo:bar'"); + assertThat(logTester.logs()) + .contains("The issue multicriteria pattern 'repo:rule' matches a rule key that has been changed. The pattern should be updated to 'foo:bar'"); } @Test public void shouldAcceptIfRulePatternDoesNotMatch() { + DefaultActiveRules activeRules = new DefaultActiveRules(ImmutableSet.of()); + IgnoreIssuesFilter underTest = new IgnoreIssuesFilter(activeRules, analysisWarnings); + WildcardPattern pattern = mock(WildcardPattern.class); when(pattern.match(ruleKey.toString())).thenReturn(false); underTest.addRuleExclusionPatternForComponent(component, pattern); diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/IssuePatternTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/IssuePatternTest.java index c9cd8be9833..7e9e3bcab41 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/IssuePatternTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/issue/ignore/pattern/IssuePatternTest.java @@ -57,4 +57,9 @@ public class IssuePatternTest { assertThat(new IssuePattern("*", "*:Foo*IllegalRegexp").matchRule(rule)).isFalse(); } + @Test + public void toString_should_include_all_fields() { + assertThat(new IssuePattern("*", "*:Foo*IllegalRegexp").toString()).isEqualTo("IssuePattern{filePattern=*, rulePattern=*:Foo*IllegalRegexp}"); + } + } diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/ScannerMediumTester.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/ScannerMediumTester.java index d70abb58dcc..2cdab7cea2c 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/ScannerMediumTester.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/ScannerMediumTester.java @@ -79,6 +79,8 @@ import org.sonarqube.ws.NewCodePeriods; import org.sonarqube.ws.Qualityprofiles.SearchWsResponse.QualityProfile; import org.sonarqube.ws.Rules.ListResponse.Rule; +import static java.util.Collections.emptySet; + /** * Main utility class for writing scanner medium tests. */ @@ -209,6 +211,7 @@ public class ScannerMediumTester extends ExternalResource { r.setTemplateRuleKey(templateRuleKey); r.setLanguage(language); r.setSeverity(severity); + r.setDeprecatedKeys(emptySet()); activeRules.addActiveRule(r); return this; diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/issues/ChecksMediumTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/issues/ChecksMediumTest.java index bc65e15d45f..591286dd5e6 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/issues/ChecksMediumTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/issues/ChecksMediumTest.java @@ -30,14 +30,15 @@ import org.apache.commons.io.FileUtils; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; +import org.sonar.api.batch.rule.LoadedActiveRule; import org.sonar.api.rule.RuleKey; -import org.sonar.scanner.mediumtest.ScannerMediumTester; import org.sonar.scanner.mediumtest.AnalysisResult; +import org.sonar.scanner.mediumtest.ScannerMediumTester; import org.sonar.scanner.protocol.output.ScannerReport.Issue; -import org.sonar.api.batch.rule.LoadedActiveRule; import org.sonar.xoo.XooPlugin; import org.sonar.xoo.rule.XooRulesDefinition; +import static java.util.Collections.emptySet; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.tuple; @@ -98,6 +99,7 @@ public class ChecksMediumTest { r.setTemplateRuleKey(templateRuleKey); r.setLanguage(languag); r.setSeverity(severity); + r.setDeprecatedKeys(emptySet()); Map<String, String> params = new HashMap<>(); params.put(paramKey, paramValue); diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/issues/IssuesMediumTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/issues/IssuesMediumTest.java index f27fd55be55..5a584bd275d 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/issues/IssuesMediumTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/issues/IssuesMediumTest.java @@ -28,19 +28,20 @@ import org.apache.commons.io.FileUtils; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; +import org.sonar.api.batch.rule.LoadedActiveRule; import org.sonar.api.rule.RuleKey; import org.sonar.api.utils.log.LogTester; import org.sonar.api.utils.log.LoggerLevel; -import org.sonar.scanner.mediumtest.ScannerMediumTester; import org.sonar.scanner.mediumtest.AnalysisResult; +import org.sonar.scanner.mediumtest.ScannerMediumTester; import org.sonar.scanner.protocol.output.ScannerReport.ExternalIssue; import org.sonar.scanner.protocol.output.ScannerReport.Issue; -import org.sonar.api.batch.rule.LoadedActiveRule; import org.sonar.xoo.XooPlugin; import org.sonar.xoo.rule.HasTagSensor; import org.sonar.xoo.rule.OneExternalIssuePerLineSensor; import org.sonar.xoo.rule.XooRulesDefinition; +import static java.util.Collections.emptySet; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.tuple; @@ -385,6 +386,8 @@ public class IssuesMediumTest { r.setName("TODO"); r.setLanguage("xoo"); r.setSeverity("MAJOR"); + r.setDeprecatedKeys(emptySet() + ); r.setParams(ImmutableMap.of("tag", "TODO")); tester.activateRule(r); } diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/rule/ActiveRulesProviderTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/rule/ActiveRulesProviderTest.java index 0f1aef9124d..6d5c502e447 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/rule/ActiveRulesProviderTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/rule/ActiveRulesProviderTest.java @@ -26,33 +26,24 @@ import java.util.Date; import java.util.LinkedList; import java.util.List; import org.assertj.core.groups.Tuple; -import org.junit.Before; import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; import org.sonar.api.batch.rule.ActiveRules; import org.sonar.api.batch.rule.LoadedActiveRule; +import org.sonar.api.batch.rule.internal.DefaultActiveRules; import org.sonar.api.rule.RuleKey; import org.sonar.api.utils.DateUtils; import org.sonarqube.ws.Qualityprofiles.SearchWsResponse.QualityProfile; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; public class ActiveRulesProviderTest { - private ActiveRulesProvider provider; - - @Mock - private DefaultActiveRulesLoader loader; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - provider = new ActiveRulesProvider(); - } + private final ActiveRulesProvider provider = new ActiveRulesProvider(); + private final DefaultActiveRulesLoader loader = mock(DefaultActiveRulesLoader.class); @Test public void testCombinationOfRules() { @@ -69,7 +60,7 @@ public class ActiveRulesProviderTest { when(loader.load(eq("qp3"))).thenReturn(qp3Rules); QualityProfiles profiles = mockProfiles("qp1", "qp2", "qp3"); - ActiveRules activeRules = provider.provide(loader, profiles); + DefaultActiveRules activeRules = provider.provide(loader, profiles); assertThat(activeRules.findAll()).hasSize(3); assertThat(activeRules.findAll()).extracting("ruleKey").containsOnly( @@ -78,6 +69,8 @@ public class ActiveRulesProviderTest { verify(loader).load(eq("qp1")); verify(loader).load(eq("qp2")); verify(loader).load(eq("qp3")); + + assertThat(activeRules.getDeprecatedRuleKeys(RuleKey.of("rule1", "rule1"))).containsOnly("rule1old:rule1old"); verifyNoMoreInteractions(loader); } |