diff options
author | Pierre Guillot <pierre.guillot@sonarsource.com> | 2024-12-10 15:29:09 +0100 |
---|---|---|
committer | Steve Marion <steve.marion@sonarsource.com> | 2024-12-18 11:13:21 +0100 |
commit | d639a965bce7acafb004906cd07a8f0b5f7af993 (patch) | |
tree | 647cd646abddb12dfeeef7e637aa33b4658f1049 /sonar-scanner-engine/src/test/java | |
parent | 451c1c2e4856ec3df87f86189fcdb25b31794027 (diff) | |
download | sonarqube-d639a965bce7acafb004906cd07a8f0b5f7af993.tar.gz sonarqube-d639a965bce7acafb004906cd07a8f0b5f7af993.zip |
SONAR-22998 fetch active rules with a dedicated endpoint
Co-authored-by: Julien HENRY <julien.henry@sonarsource.com>
Diffstat (limited to 'sonar-scanner-engine/src/test/java')
2 files changed, 160 insertions, 117 deletions
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 4072d462f92..c5f3fceedbc 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 @@ -19,13 +19,12 @@ */ package org.sonar.scanner.rule; -import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; -import java.util.Date; -import java.util.LinkedList; +import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.function.Consumer; import java.util.stream.Collectors; import org.assertj.core.groups.Tuple; import org.junit.Test; @@ -36,16 +35,17 @@ import org.sonar.api.batch.rule.internal.DefaultActiveRules; import org.sonar.api.issue.impact.Severity; import org.sonar.api.issue.impact.SoftwareQuality; import org.sonar.api.rule.RuleKey; -import org.sonar.api.utils.DateUtils; -import org.sonarqube.ws.Qualityprofiles.SearchWsResponse.QualityProfile; +import org.sonar.scanner.bootstrap.ScannerProperties; 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.verifyNoMoreInteractions; import static org.mockito.Mockito.when; +import static org.sonar.api.CoreProperties.PROJECT_KEY_PROPERTY; public class ActiveRulesProviderTest { + public static final String PROJECT_KEY = "my-awesome-project"; private final ActiveRulesProvider provider = new ActiveRulesProvider(); private final DefaultActiveRulesLoader loader = mock(DefaultActiveRulesLoader.class); @@ -57,21 +57,19 @@ public class ActiveRulesProviderTest { r1.setImpacts(Map.of(SoftwareQuality.MAINTAINABILITY, Severity.HIGH)); - List<LoadedActiveRule> qp1Rules = ImmutableList.of(r1, r2); - List<LoadedActiveRule> qp2Rules = ImmutableList.of(r2, r3); - List<LoadedActiveRule> qp3Rules = ImmutableList.of(r1, r3); + when(loader.load(PROJECT_KEY)).thenReturn(List.of(r1, r2, r3)); - when(loader.load("qp1")).thenReturn(qp1Rules); - when(loader.load("qp2")).thenReturn(qp2Rules); - when(loader.load("qp3")).thenReturn(qp3Rules); - - QualityProfiles profiles = mockProfiles("qp1", "qp2", "qp3"); - DefaultActiveRules activeRules = provider.provide(loader, profiles); + HashMap<String, String> propertiesMap = new HashMap<>(); + propertiesMap.put(PROJECT_KEY_PROPERTY, PROJECT_KEY); + ScannerProperties scannerProperties = new ScannerProperties(propertiesMap); + DefaultActiveRules activeRules = provider.provide(loader, scannerProperties); assertThat(activeRules.findAll()).hasSize(3); assertThat(activeRules.findAll()).extracting("ruleKey").containsOnly( RuleKey.of("rule1", "rule1"), RuleKey.of("rule2", "rule2"), RuleKey.of("rule3", "rule3")); + verify(loader).load(PROJECT_KEY); + Map<String, ActiveRule> activeRuleByKey = activeRules.findAll().stream().collect(Collectors.toMap(e -> e.ruleKey().rule(), e -> e)); assertThat(((DefaultActiveRule) activeRuleByKey.get("rule1")).impacts()) .containsExactlyInAnyOrderEntriesOf(Map.of(SoftwareQuality.MAINTAINABILITY, Severity.HIGH)); @@ -79,10 +77,6 @@ public class ActiveRulesProviderTest { assertThat(((DefaultActiveRule) activeRuleByKey.get("rule2")).impacts()).isEmpty(); assertThat(((DefaultActiveRule) activeRuleByKey.get("rule3")).impacts()).isEmpty(); - verify(loader).load("qp1"); - verify(loader).load("qp2"); - verify(loader).load("qp3"); - assertThat(activeRules.getDeprecatedRuleKeys(RuleKey.of("rule1", "rule1"))).containsOnly("rule1old:rule1old"); verifyNoMoreInteractions(loader); } @@ -90,40 +84,33 @@ public class ActiveRulesProviderTest { @Test public void testParamsAreTransformed() { LoadedActiveRule r1 = mockRule("rule1"); - LoadedActiveRule r2 = mockRule("rule2"); - r2.setParams(ImmutableMap.of("foo1", "bar1", "foo2", "bar2")); + LoadedActiveRule r2 = mockRule("rule2", b -> b.setParams(Map.of("foo1", "bar1", "foo2", "bar2"))); - List<LoadedActiveRule> qpRules = ImmutableList.of(r1, r2); - when(loader.load("qp")).thenReturn(qpRules); + when(loader.load(PROJECT_KEY)).thenReturn(List.of(r1, r2)); - QualityProfiles profiles = mockProfiles("qp"); - ActiveRules activeRules = provider.provide(loader, profiles); + HashMap<String, String> propertiesMap = new HashMap<>(); + propertiesMap.put(PROJECT_KEY_PROPERTY, PROJECT_KEY); + ScannerProperties scannerProperties = new ScannerProperties(propertiesMap); + ActiveRules activeRules = provider.provide(loader, scannerProperties); assertThat(activeRules.findAll()).hasSize(2); assertThat(activeRules.findAll()).extracting("ruleKey", "params").containsOnly( Tuple.tuple(RuleKey.of("rule1", "rule1"), ImmutableMap.of()), Tuple.tuple(RuleKey.of("rule2", "rule2"), ImmutableMap.of("foo1", "bar1", "foo2", "bar2"))); - verify(loader).load("qp"); + verify(loader).load(PROJECT_KEY); verifyNoMoreInteractions(loader); } - private static QualityProfiles mockProfiles(String... keys) { - List<QualityProfile> profiles = new LinkedList<>(); - - for (String k : keys) { - QualityProfile p = QualityProfile.newBuilder().setKey(k).setLanguage(k).setRulesUpdatedAt(DateUtils.formatDateTime(new Date())).build(); - profiles.add(p); + @SafeVarargs + private static LoadedActiveRule mockRule(String name, Consumer<LoadedActiveRule>... consumers) { + LoadedActiveRule rule = new LoadedActiveRule(); + rule.setName(name); + rule.setRuleKey(RuleKey.of(name, name)); + rule.setDeprecatedKeys(ImmutableSet.of(RuleKey.of(name + "old", name + "old"))); + for (Consumer<LoadedActiveRule> consumer : consumers) { + consumer.accept(rule); } - - return new QualityProfiles(profiles); - } - - private static LoadedActiveRule mockRule(String name) { - LoadedActiveRule r = new LoadedActiveRule(); - r.setName(name); - r.setRuleKey(RuleKey.of(name, name)); - r.setDeprecatedKeys(ImmutableSet.of(RuleKey.of(name + "old", name + "old"))); - return r; + return rule; } } diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/rule/DefaultActiveRulesLoaderTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/rule/DefaultActiveRulesLoaderTest.java index 59a49084742..cf66faeb655 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/rule/DefaultActiveRulesLoaderTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/rule/DefaultActiveRulesLoaderTest.java @@ -19,46 +19,49 @@ */ package org.sonar.scanner.rule; -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.util.Collection; +import com.google.gson.Gson; +import java.io.Reader; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.List; import java.util.Map; +import java.util.stream.Collectors; import java.util.stream.IntStream; -import org.junit.Before; -import org.junit.Test; -import org.sonar.scanner.rule.LoadedActiveRule; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.sonar.api.issue.impact.SoftwareQuality; import org.sonar.api.rule.RuleKey; import org.sonar.api.rule.Severity; import org.sonar.scanner.WsTestUtil; import org.sonar.scanner.http.DefaultScannerWsClient; import org.sonar.scanner.scan.branch.BranchConfiguration; -import org.sonarqube.ws.Common; -import org.sonarqube.ws.Rules; -import org.sonarqube.ws.Rules.Active; -import org.sonarqube.ws.Rules.ActiveList; -import org.sonarqube.ws.Rules.Actives; -import org.sonarqube.ws.Rules.Rule; +import static java.util.Map.entry; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; +import static org.sonar.api.issue.impact.Severity.HIGH; +import static org.sonar.scanner.rule.DefaultActiveRulesLoader.ActiveRuleGson; +import static org.sonar.scanner.rule.DefaultActiveRulesLoader.ParamGson; +import static org.sonar.scanner.rule.DefaultActiveRulesLoader.RuleKeyGson; -public class DefaultActiveRulesLoaderTest { +class DefaultActiveRulesLoaderTest { - private static final int PAGE_SIZE_1 = 150; - private static final int PAGE_SIZE_2 = 76; + private static final int NUMBER_OF_RULES = 150; private static final RuleKey EXAMPLE_KEY = RuleKey.of("java", "S108"); + private static final RuleKey CUSTOM_RULE_KEY = RuleKey.of("java", "my-custom-rule"); private static final String FORMAT_KEY = "format"; private static final String FORMAT_VALUE = "^[a-z][a-zA-Z0-9]*$"; + private static final String PROJECT_KEY = "myProjectKey"; private static final String SEVERITY_VALUE = Severity.MINOR; private DefaultActiveRulesLoader loader; private DefaultScannerWsClient wsClient; - @Before - public void setUp() { + @BeforeEach + void setUp() { wsClient = mock(DefaultScannerWsClient.class); BranchConfiguration branchConfig = mock(BranchConfiguration.class); when(branchConfig.isPullRequest()).thenReturn(false); @@ -66,78 +69,131 @@ public class DefaultActiveRulesLoaderTest { } @Test - public void load_shouldRequestRulesAndParseResponse() { - int total = PAGE_SIZE_1 + PAGE_SIZE_2; - - WsTestUtil.mockStream(wsClient, urlOfPage(1), responseOfSize(1, PAGE_SIZE_1, total)); - WsTestUtil.mockStream(wsClient, urlOfPage(2), responseOfSize(2, PAGE_SIZE_2, total)); - - Collection<LoadedActiveRule> activeRules = loader.load("c+-test_c+-values-17445"); - assertThat(activeRules).hasSize(total); - assertThat(activeRules) - .filteredOn(r -> r.getRuleKey().equals(EXAMPLE_KEY)) - .extracting(LoadedActiveRule::getParams) - .extracting(p -> p.get(FORMAT_KEY)) - .containsExactly(FORMAT_VALUE); - assertThat(activeRules) - .filteredOn(r -> r.getRuleKey().equals(EXAMPLE_KEY)) - .extracting(LoadedActiveRule::getSeverity) - .containsExactly(SEVERITY_VALUE); - assertThat(activeRules) - .filteredOn(r -> r.getRuleKey().equals(EXAMPLE_KEY)) - .extracting(LoadedActiveRule::getImpacts) - .containsExactlyInAnyOrder(Map.of(SoftwareQuality.MAINTAINABILITY, org.sonar.api.issue.impact.Severity.HIGH)); - - WsTestUtil.verifyCall(wsClient, urlOfPage(1)); - WsTestUtil.verifyCall(wsClient, urlOfPage(2)); + void load_shouldRequestRulesAndParseResponse() { + WsTestUtil.mockReader(wsClient, getUrl(), response()); + + Map<RuleKey, LoadedActiveRule> activeRulesByKey = loader.load(PROJECT_KEY).stream().collect(Collectors.toMap(LoadedActiveRule::getRuleKey, r -> r)); + assertThat(activeRulesByKey).hasSize(NUMBER_OF_RULES); + + var exampleRule = activeRulesByKey.get(EXAMPLE_KEY); + assertThat(exampleRule.getParams()).containsEntry(FORMAT_KEY, FORMAT_VALUE); + assertThat(exampleRule.getSeverity()).isEqualTo(SEVERITY_VALUE); + assertThat(exampleRule.getImpacts()).containsExactly(entry(SoftwareQuality.MAINTAINABILITY, HIGH)); + + var customRule = activeRulesByKey.get(CUSTOM_RULE_KEY); + assertThat(customRule.getTemplateRuleKey()).isEqualTo("ruleTemplate"); + + WsTestUtil.verifyCall(wsClient, getUrl()); verifyNoMoreInteractions(wsClient); } - private String urlOfPage(int page) { - return "/api/rules/list.protobuf?qprofile=c%2B-test_c%2B-values-17445&ps=500&p=" + page + ""; + private String getUrl() { + return "/api/v2/analysis/active_rules?projectKey=" + PROJECT_KEY; } - /** - * Generates an imaginary protobuf result. - * - * @param pageIndex page index, that the response should contain - * @param numberOfRules the number of rules, that the response should contain - * @param total the number of results on all pages - * @return the binary stream - */ - private InputStream responseOfSize(int pageIndex, int numberOfRules, int total) { - Rules.ListResponse.Builder rules = Rules.ListResponse.newBuilder(); - Actives.Builder actives = Actives.newBuilder(); - - IntStream.rangeClosed(1, numberOfRules) + private Reader response() { + List<ActiveRuleGson> activeRules = new ArrayList<>(); + + IntStream.rangeClosed(1, NUMBER_OF_RULES - 1) .mapToObj(i -> RuleKey.of("java", "S" + i)) .forEach(key -> { + ActiveRuleGsonBuilder builder = new ActiveRuleGsonBuilder(); - Rule.Builder ruleBuilder = Rule.newBuilder(); - ruleBuilder.setKey(key.toString()); - rules.addRules(ruleBuilder); + builder.setRuleKey(new RuleKeyGson(key.repository(), key.rule())); - Active.Builder activeBuilder = Active.newBuilder(); - activeBuilder.setCreatedAt("2014-05-27T15:50:45+0100"); - activeBuilder.setUpdatedAt("2014-05-27T15:50:45+0100"); + builder.setCreatedAt("2014-05-27T15:50:45+0100"); + builder.setUpdatedAt("2014-05-27T15:50:45+0100"); if (EXAMPLE_KEY.equals(key)) { - activeBuilder.addParams(Rules.Active.Param.newBuilder().setKey(FORMAT_KEY).setValue(FORMAT_VALUE)); - activeBuilder.setSeverity(SEVERITY_VALUE); - activeBuilder.setImpacts(Rules.Impacts.newBuilder().addImpacts(Common.Impact.newBuilder() - .setSoftwareQuality(Common.SoftwareQuality.MAINTAINABILITY) - .setSeverity(Common.ImpactSeverity.HIGH).build()).build()); + builder.setParams(List.of(new ParamGson(FORMAT_KEY, FORMAT_VALUE))); + builder.setSeverity(SEVERITY_VALUE); + builder.setImpacts(Map.of(SoftwareQuality.MAINTAINABILITY, HIGH)); } - ActiveList activeList = Rules.ActiveList.newBuilder().addActiveList(activeBuilder).build(); - actives.putAllActives(Map.of(key.toString(), activeList)); + + activeRules.add(builder.build()); }); - rules.setActives(actives); - rules.setPaging(Common.Paging.newBuilder() - .setTotal(total) - .setPageIndex(pageIndex) - .setPageSize(numberOfRules) - .build()); - return new ByteArrayInputStream(rules.build().toByteArray()); + ActiveRuleGsonBuilder builder = new ActiveRuleGsonBuilder(); + builder.setRuleKey(new RuleKeyGson(CUSTOM_RULE_KEY.repository(), CUSTOM_RULE_KEY.rule())); + builder.setCreatedAt("2014-05-27T15:50:45+0100"); + builder.setUpdatedAt("2014-05-27T15:50:45+0100"); + builder.setTemplateRuleKey("java:ruleTemplate"); + activeRules.add(builder.build()); + + return toReader(activeRules); + } + + private static Reader toReader(List<ActiveRuleGson> activeRules) { + String json = new Gson().toJson(activeRules); + return new StringReader(json); + } + + private static class ActiveRuleGsonBuilder { + private RuleKeyGson ruleKey; + private String name; + private String severity; + private String createdAt; + private String updatedAt; + private String internalKey; + private String language; + private String templateRuleKey; + private String qProfilKey; + private final List<RuleKeyGson> deprecatedKeys = new ArrayList<>(); + private final List<ParamGson> params = new ArrayList<>(); + private final Map<SoftwareQuality, org.sonar.api.issue.impact.Severity> impacts = new EnumMap<>(SoftwareQuality.class); + + public void setRuleKey(RuleKeyGson ruleKey) { + this.ruleKey = ruleKey; + } + + public void setName(String name) { + this.name = name; + } + + public void setSeverity(String severity) { + this.severity = severity; + } + + public void setCreatedAt(String createdAt) { + this.createdAt = createdAt; + } + + public void setUpdatedAt(String updatedAt) { + this.updatedAt = updatedAt; + } + + public void setInternalKey(String internalKey) { + this.internalKey = internalKey; + } + + public void setLanguage(String language) { + this.language = language; + } + + public void setTemplateRuleKey(String templateRuleKey) { + this.templateRuleKey = templateRuleKey; + } + + public void setQProfilKey(String qProfilKey) { + this.qProfilKey = qProfilKey; + } + + public void setParams(List<ParamGson> params) { + this.params.clear(); + this.params.addAll(params); + } + + public void addAllDeprecatedKeys(List<RuleKeyGson> deprecatedKeys) { + this.deprecatedKeys.addAll(deprecatedKeys); + } + + public void setImpacts(Map<SoftwareQuality, org.sonar.api.issue.impact.Severity> impacts) { + this.impacts.clear(); + this.impacts.putAll(impacts); + } + + public ActiveRuleGson build() { + return new ActiveRuleGson(ruleKey, name, severity, createdAt, updatedAt, internalKey, language, templateRuleKey, qProfilKey, deprecatedKeys, params, impacts); + } } } |