From 1aa398cc2fa62d16d18ad4b9e5709bc5b21f42ca Mon Sep 17 00:00:00 2001 From: =?utf8?q?S=C3=A9bastien=20Lesaint?= Date: Tue, 30 Jan 2018 18:27:47 +0100 Subject: [PATCH] SONAR-10357 add ruleId to BuiltInQProfile#activeRules --- .../qualityprofile/BuiltInQProfile.java | 38 +++++++-- .../BuiltInQProfileInsertImpl.java | 14 ++-- .../BuiltInQProfileRepositoryImpl.java | 77 +++++++++++++------ .../BuiltInQProfileUpdateImpl.java | 17 ++-- .../BuiltInQProfileInsertImplTest.java | 2 +- .../BuiltInQProfileRepositoryImplTest.java | 30 +++++--- .../BuiltInQProfileRepositoryRule.java | 37 ++++++--- .../BuiltInQProfileUpdateImplTest.java | 10 +-- ...gisterQualityProfilesNotificationTest.java | 26 ++++++- 9 files changed, 173 insertions(+), 78 deletions(-) diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfile.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfile.java index a60ca1a261c..26597123188 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfile.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfile.java @@ -23,6 +23,7 @@ import com.google.common.collect.ImmutableList; import java.util.ArrayList; import java.util.List; import javax.annotation.concurrent.Immutable; +import org.sonar.api.rule.RuleKey; import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition; /** @@ -32,7 +33,7 @@ import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition; public final class BuiltInQProfile { private final QProfileName qProfileName; private final boolean isDefault; - private final List activeRules; + private final List activeRules; private BuiltInQProfile(Builder builder) { this.qProfileName = new QProfileName(builder.language, builder.name); @@ -56,16 +57,38 @@ public final class BuiltInQProfile { return isDefault; } - public List getActiveRules() { + public List getActiveRules() { return activeRules; } + static final class ActiveRule { + private final int ruleId; + private final BuiltInQualityProfilesDefinition.BuiltInActiveRule builtIn; + + ActiveRule(int ruleId, BuiltInQualityProfilesDefinition.BuiltInActiveRule builtIn) { + this.ruleId = ruleId; + this.builtIn = builtIn; + } + + public int getRuleId() { + return ruleId; + } + + public RuleKey getRuleKey() { + return RuleKey.of(builtIn.repoKey(), builtIn.ruleKey()); + } + + public BuiltInQualityProfilesDefinition.BuiltInActiveRule getBuiltIn() { + return builtIn; + } + } + static final class Builder { private String language; private String name; private boolean declaredDefault; private boolean computedDefault; - private final List activeRules = new ArrayList<>(); + private final List activeRules = new ArrayList<>(); public Builder setLanguage(String language) { this.language = language; @@ -95,8 +118,13 @@ public final class BuiltInQProfile { return this; } - Builder addRules(List rules) { - this.activeRules.addAll(rules); + Builder addRule(BuiltInQualityProfilesDefinition.BuiltInActiveRule rule, int ruleId) { + this.activeRules.add(new ActiveRule(ruleId, rule)); + return this; + } + + Builder addRule(ActiveRule activeRule) { + this.activeRules.add(activeRule); return this; } diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileInsertImpl.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileInsertImpl.java index 0ffe5e2b7d8..741e254f364 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileInsertImpl.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileInsertImpl.java @@ -139,8 +139,8 @@ public class BuiltInQProfileInsertImpl implements BuiltInQProfileInsert { return dto; } - private ActiveRuleChange insertActiveRule(DbSession dbSession, RulesProfileDto rulesProfileDto, BuiltInQualityProfilesDefinition.BuiltInActiveRule activeRule, long now) { - RuleKey ruleKey = RuleKey.of(activeRule.repoKey(), activeRule.ruleKey()); + private ActiveRuleChange insertActiveRule(DbSession dbSession, RulesProfileDto rulesProfileDto, BuiltInQProfile.ActiveRule activeRule, long now) { + RuleKey ruleKey = activeRule.getRuleKey(); RuleDefinitionDto ruleDefinitionDto = ruleRepository.getDefinition(ruleKey) .orElseThrow(() -> new IllegalStateException("RuleDefinition not found for key " + ruleKey)); @@ -148,12 +148,12 @@ public class BuiltInQProfileInsertImpl implements BuiltInQProfileInsert { dto.setProfileId(rulesProfileDto.getId()); dto.setRuleId(ruleDefinitionDto.getId()); dto.setKey(ActiveRuleKey.of(rulesProfileDto, ruleDefinitionDto.getKey())); - dto.setSeverity(firstNonNull(activeRule.overriddenSeverity(), ruleDefinitionDto.getSeverityString())); + dto.setSeverity(firstNonNull(activeRule.getBuiltIn().overriddenSeverity(), ruleDefinitionDto.getSeverityString())); dto.setUpdatedAt(now); dto.setCreatedAt(now); dbClient.activeRuleDao().insert(dbSession, dto); - List paramDtos = insertActiveRuleParams(dbSession, activeRule, ruleKey, dto); + List paramDtos = insertActiveRuleParams(dbSession, activeRule, dto); ActiveRuleChange change = new ActiveRuleChange(ActiveRuleChange.Type.ACTIVATED, dto, ruleDefinitionDto); change.setSeverity(dto.getSeverityString()); @@ -161,12 +161,12 @@ public class BuiltInQProfileInsertImpl implements BuiltInQProfileInsert { return change; } - private List insertActiveRuleParams(DbSession session, BuiltInQualityProfilesDefinition.BuiltInActiveRule activeRule, RuleKey ruleKey, + private List insertActiveRuleParams(DbSession session, BuiltInQProfile.ActiveRule activeRule, ActiveRuleDto activeRuleDto) { - Map valuesByParamKey = activeRule.overriddenParams() + Map valuesByParamKey = activeRule.getBuiltIn().overriddenParams() .stream() .collect(MoreCollectors.uniqueIndex(BuiltInQualityProfilesDefinition.OverriddenParam::key, BuiltInQualityProfilesDefinition.OverriddenParam::overriddenValue)); - return ruleRepository.getRuleParams(ruleKey) + return ruleRepository.getRuleParams(activeRule.getRuleKey()) .stream() .map(param -> { String activeRuleValue = valuesByParamKey.get(param.getName()); diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileRepositoryImpl.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileRepositoryImpl.java index 07406726ef0..bb8f4d2ac6c 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileRepositoryImpl.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileRepositoryImpl.java @@ -21,6 +21,7 @@ package org.sonar.server.qualityprofile; import com.google.common.collect.ImmutableList; import java.util.Collection; +import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -29,12 +30,16 @@ import java.util.Set; import javax.annotation.Nullable; import org.sonar.api.profiles.RulesProfile; import org.sonar.api.resources.Languages; +import org.sonar.api.rule.RuleKey; import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition; import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition.BuiltInQualityProfile; import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Loggers; import org.sonar.api.utils.log.Profiler; import org.sonar.core.util.stream.MoreCollectors; +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; +import org.sonar.db.rule.RuleDefinitionDto; import static com.google.common.base.Preconditions.checkState; @@ -42,6 +47,7 @@ public class BuiltInQProfileRepositoryImpl implements BuiltInQProfileRepository private static final Logger LOGGER = Loggers.get(BuiltInQProfileRepositoryImpl.class); private static final String DEFAULT_PROFILE_NAME = "Sonar way"; + private final DbClient dbClient; private final Languages languages; private final List definitions; private List qProfiles; @@ -49,11 +55,12 @@ public class BuiltInQProfileRepositoryImpl implements BuiltInQProfileRepository /** * Requires for pico container when no {@link BuiltInQualityProfilesDefinition} is defined at all */ - public BuiltInQProfileRepositoryImpl(Languages languages) { - this(languages, new BuiltInQualityProfilesDefinition[0]); + public BuiltInQProfileRepositoryImpl(DbClient dbClient, Languages languages) { + this(dbClient, languages, new BuiltInQualityProfilesDefinition[0]); } - public BuiltInQProfileRepositoryImpl(Languages languages, BuiltInQualityProfilesDefinition... definitions) { + public BuiltInQProfileRepositoryImpl(DbClient dbClient, Languages languages, BuiltInQualityProfilesDefinition... definitions) { + this.dbClient = dbClient; this.languages = languages; this.definitions = ImmutableList.copyOf(definitions); } @@ -98,18 +105,29 @@ public class BuiltInQProfileRepositoryImpl implements BuiltInQProfileRepository return profilesByLanguageAndName; } - private static List toFlatList(Map> rulesProfilesByLanguage) { - Map> buildersByLanguage = rulesProfilesByLanguage - .entrySet() - .stream() - .collect(MoreCollectors.uniqueIndex(Map.Entry::getKey, BuiltInQProfileRepositoryImpl::toQualityProfileBuilders)); - return buildersByLanguage - .entrySet() - .stream() - .filter(BuiltInQProfileRepositoryImpl::ensureAtMostOneDeclaredDefault) - .map(entry -> toQualityProfiles(entry.getValue())) - .flatMap(Collection::stream) - .collect(MoreCollectors.toList()); + private List toFlatList(Map> rulesProfilesByLanguage) { + if (rulesProfilesByLanguage.isEmpty()) { + return Collections.emptyList(); + } + + try (DbSession dbSession = dbClient.openSession(false)) { + Map rulesByRuleKey = dbClient.ruleDao().selectAllDefinitions(dbSession) + .stream() + .collect(MoreCollectors.uniqueIndex(RuleDefinitionDto::getKey)); + Map> buildersByLanguage = rulesProfilesByLanguage + .entrySet() + .stream() + .collect(MoreCollectors.uniqueIndex( + Map.Entry::getKey, + rulesProfilesByLanguageAndName -> toQualityProfileBuilders(rulesProfilesByLanguageAndName, rulesByRuleKey))); + return buildersByLanguage + .entrySet() + .stream() + .filter(BuiltInQProfileRepositoryImpl::ensureAtMostOneDeclaredDefault) + .map(entry -> toQualityProfiles(entry.getValue())) + .flatMap(Collection::stream) + .collect(MoreCollectors.toList()); + } } /** @@ -124,14 +142,15 @@ public class BuiltInQProfileRepositoryImpl implements BuiltInQProfileRepository * RulesProfile with a given name * */ - private static List toQualityProfileBuilders(Map.Entry> rulesProfilesByLanguageAndName) { + private static List toQualityProfileBuilders(Map.Entry> rulesProfilesByLanguageAndName, + Map rulesByRuleKey) { String language = rulesProfilesByLanguageAndName.getKey(); // use a LinkedHashMap to keep order of insertion of RulesProfiles Map qualityProfileBuildersByName = new LinkedHashMap<>(); for (BuiltInQualityProfile builtInProfile : rulesProfilesByLanguageAndName.getValue().values()) { qualityProfileBuildersByName.compute( builtInProfile.name(), - (name, existingBuilder) -> updateOrCreateBuilder(language, existingBuilder, builtInProfile)); + (name, existingBuilder) -> updateOrCreateBuilder(language, existingBuilder, builtInProfile, rulesByRuleKey)); } return ImmutableList.copyOf(qualityProfileBuildersByName.values()); } @@ -148,16 +167,26 @@ public class BuiltInQProfileRepositoryImpl implements BuiltInQProfileRepository return true; } - private static BuiltInQProfile.Builder updateOrCreateBuilder(String language, @Nullable BuiltInQProfile.Builder existingBuilder, BuiltInQualityProfile builtInProfile) { - BuiltInQProfile.Builder builder = existingBuilder; - if (builder == null) { - builder = new BuiltInQProfile.Builder() + private static BuiltInQProfile.Builder updateOrCreateBuilder(String language, @Nullable BuiltInQProfile.Builder existingBuilder, BuiltInQualityProfile builtInProfile, + Map rulesByRuleKey) { + BuiltInQProfile.Builder builder = createOrReuseBuilder(existingBuilder, language, builtInProfile); + builder.setDeclaredDefault(builtInProfile.isDefault()); + builtInProfile.rules().forEach(builtInActiveRule -> { + RuleKey ruleKey = RuleKey.of(builtInActiveRule.repoKey(), builtInActiveRule.ruleKey()); + RuleDefinitionDto ruleDefinition = rulesByRuleKey.get(ruleKey); + checkState(ruleDefinition != null, "Rule with key '%s' not found", ruleKey); + builder.addRule(builtInActiveRule, ruleDefinition.getId()); + }); + return builder; + } + + private static BuiltInQProfile.Builder createOrReuseBuilder(@Nullable BuiltInQProfile.Builder existingBuilder, String language, BuiltInQualityProfile builtInProfile) { + if (existingBuilder == null) { + return new BuiltInQProfile.Builder() .setLanguage(language) .setName(builtInProfile.name()); } - return builder - .setDeclaredDefault(builtInProfile.isDefault()) - .addRules(builtInProfile.rules()); + return existingBuilder; } private static List toQualityProfiles(List builders) { diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileUpdateImpl.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileUpdateImpl.java index 9e77286eaab..044ace3cc9b 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileUpdateImpl.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/BuiltInQProfileUpdateImpl.java @@ -27,13 +27,11 @@ import java.util.Set; import java.util.stream.Stream; import org.sonar.api.rule.RuleKey; import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition; -import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition.BuiltInActiveRule; import org.sonar.core.util.stream.MoreCollectors; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.qualityprofile.ActiveRuleDto; import org.sonar.db.qualityprofile.RulesProfileDto; -import org.sonar.db.rule.RuleDefinitionDto; import org.sonar.server.qualityprofile.index.ActiveRuleIndexer; import static org.sonar.core.util.stream.MoreCollectors.toSet; @@ -59,13 +57,13 @@ public class BuiltInQProfileUpdateImpl implements BuiltInQProfileUpdate { Set ruleKeys = Stream.concat( deactivatedKeys.stream(), - builtIn.getActiveRules().stream().map(ar -> RuleKey.of(ar.repoKey(), ar.ruleKey()))) + builtIn.getActiveRules().stream().map(BuiltInQProfile.ActiveRule::getRuleKey)) .collect(toSet()); RuleActivationContext context = ruleActivator.createContextForBuiltInProfile(dbSession, rulesProfile, ruleKeys); Collection activations = new ArrayList<>(); - for (BuiltInActiveRule ar : builtIn.getActiveRules()) { - RuleActivation activation = convert(ar, context); + for (BuiltInQProfile.ActiveRule ar : builtIn.getActiveRules()) { + RuleActivation activation = convert(ar); activations.add(activation); deactivatedKeys.remove(activation.getRuleKey()); } @@ -82,13 +80,10 @@ public class BuiltInQProfileUpdateImpl implements BuiltInQProfileUpdate { return changes; } - private static RuleActivation convert(BuiltInActiveRule ar, RuleActivationContext context) { - RuleKey ruleKey = RuleKey.of(ar.repoKey(), ar.ruleKey()); - context.reset(ruleKey); - RuleDefinitionDto ruleDefinition = context.getRule().get(); - Map params = ar.overriddenParams().stream() + private static RuleActivation convert(BuiltInQProfile.ActiveRule ar) { + Map params = ar.getBuiltIn().overriddenParams().stream() .collect(MoreCollectors.uniqueIndex(BuiltInQualityProfilesDefinition.OverriddenParam::key, BuiltInQualityProfilesDefinition.OverriddenParam::overriddenValue)); - return RuleActivation.create(ruleDefinition.getId(), ruleKey, ar.overriddenSeverity(), params); + return RuleActivation.create(ar.getRuleId(), ar.getRuleKey(), ar.getBuiltIn().overriddenSeverity(), params); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQProfileInsertImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQProfileInsertImplTest.java index f818a5c5668..f2a2081b53f 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQProfileInsertImplTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQProfileInsertImplTest.java @@ -108,7 +108,7 @@ public class BuiltInQProfileInsertImplTest { newQp.activateRule(rule2.getRepositoryKey(), rule2.getRuleKey()).overrideSeverity(Severity.MAJOR); newQp.done(); - BuiltInQProfile builtIn = builtInQProfileRepository.create(context.profile("xoo", "the name")); + BuiltInQProfile builtIn = builtInQProfileRepository.create(context.profile("xoo", "the name"), rule1, rule2); call(builtIn); verifyTableSize("rules_profiles", 1); diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQProfileRepositoryImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQProfileRepositoryImplTest.java index 8e731f1debf..0d1a96835f9 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQProfileRepositoryImplTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQProfileRepositoryImplTest.java @@ -28,11 +28,15 @@ import org.junit.rules.ExpectedException; import org.sonar.api.resources.Language; import org.sonar.api.resources.Languages; import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition; +import org.sonar.api.utils.System2; +import org.sonar.db.DbClient; +import org.sonar.db.DbTester; import org.sonar.server.language.LanguageTesting; import static java.util.Arrays.asList; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.groups.Tuple.tuple; +import static org.mockito.Mockito.mock; public class BuiltInQProfileRepositoryImplTest { private static final Language FOO_LANGUAGE = LanguageTesting.newLanguage("foo", "foo", "foo"); @@ -40,10 +44,14 @@ public class BuiltInQProfileRepositoryImplTest { @Rule public ExpectedException expectedException = ExpectedException.none(); + @Rule + public DbTester dbTester = DbTester.create(System2.INSTANCE); + + private DbClient dbClient = dbTester.getDbClient(); @Test public void get_throws_ISE_if_called_before_initialize() { - BuiltInQProfileRepositoryImpl underTest = new BuiltInQProfileRepositoryImpl(new Languages()); + BuiltInQProfileRepositoryImpl underTest = new BuiltInQProfileRepositoryImpl(mock(DbClient.class), new Languages()); expectedException.expect(IllegalStateException.class); expectedException.expectMessage("initialize must be called first"); @@ -53,7 +61,7 @@ public class BuiltInQProfileRepositoryImplTest { @Test public void initialize_throws_ISE_if_called_twice() { - BuiltInQProfileRepositoryImpl underTest = new BuiltInQProfileRepositoryImpl(new Languages()); + BuiltInQProfileRepositoryImpl underTest = new BuiltInQProfileRepositoryImpl(mock(DbClient.class), new Languages()); underTest.initialize(); expectedException.expect(IllegalStateException.class); @@ -64,7 +72,7 @@ public class BuiltInQProfileRepositoryImplTest { @Test public void initialize_creates_no_BuiltInQProfile_when_there_is_no_definition() { - BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(new Languages(FOO_LANGUAGE)); + BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(mock(DbClient.class), new Languages(FOO_LANGUAGE)); underTest.initialize(); @@ -73,7 +81,7 @@ public class BuiltInQProfileRepositoryImplTest { @Test public void initialize_creates_no_BuiltInQProfile_when_all_definitions_apply_to_non_defined_languages() { - BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(new Languages(), new DummyProfileDefinition("foo", "P1", false)); + BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(mock(DbClient.class), new Languages(), new DummyProfileDefinition("foo", "P1", false)); underTest.initialize(); @@ -82,7 +90,7 @@ public class BuiltInQProfileRepositoryImplTest { @Test public void initialize_makes_single_profile_of_a_language_default_even_if_not_flagged_as_so() { - BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(new Languages(FOO_LANGUAGE), new DummyProfileDefinition("foo", "foo1", false)); + BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(dbClient, new Languages(FOO_LANGUAGE), new DummyProfileDefinition("foo", "foo1", false)); underTest.initialize(); @@ -93,7 +101,7 @@ public class BuiltInQProfileRepositoryImplTest { @Test public void initialize_makes_single_profile_of_a_language_default_even_if_flagged_as_so() { - BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(new Languages(FOO_LANGUAGE), new DummyProfileDefinition("foo", "foo1", true)); + BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(dbClient, new Languages(FOO_LANGUAGE), new DummyProfileDefinition("foo", "foo1", true)); underTest.initialize(); @@ -109,7 +117,7 @@ public class BuiltInQProfileRepositoryImplTest { Collections.shuffle(definitions); String firstName = definitions.get(0).getName(); String secondName = definitions.get(1).getName(); - BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(new Languages(FOO_LANGUAGE), definitions.toArray(new BuiltInQualityProfilesDefinition[0])); + BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(dbClient, new Languages(FOO_LANGUAGE), definitions.toArray(new BuiltInQualityProfilesDefinition[0])); underTest.initialize(); @@ -120,7 +128,7 @@ public class BuiltInQProfileRepositoryImplTest { @Test public void initialize_fails_with_ISE_when_two_profiles_with_different_name_are_default_for_the_same_language() { - BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(new Languages(FOO_LANGUAGE), + BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(dbClient, new Languages(FOO_LANGUAGE), new DummyProfileDefinition("foo", "foo1", true), new DummyProfileDefinition("foo", "foo2", true)); expectedException.expect(IllegalStateException.class); @@ -132,7 +140,7 @@ public class BuiltInQProfileRepositoryImplTest { @Test public void initialize_creates_profile_Sonar_Way_as_default_if_none_other_is_defined_default_for_a_given_language() { BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl( - new Languages(FOO_LANGUAGE), + dbClient, new Languages(FOO_LANGUAGE), new DummyProfileDefinition("foo", "doh", false), new DummyProfileDefinition("foo", "boo", false), new DummyProfileDefinition("foo", SONAR_WAY_QP_NAME, false), new DummyProfileDefinition("foo", "goo", false)); @@ -148,7 +156,7 @@ public class BuiltInQProfileRepositoryImplTest { @Test public void initialize_does_not_create_Sonar_Way_as_default_if_other_profile_is_defined_as_default() { BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl( - new Languages(FOO_LANGUAGE), + dbClient, new Languages(FOO_LANGUAGE), new DummyProfileDefinition("foo", SONAR_WAY_QP_NAME, false), new DummyProfileDefinition("foo", "goo", true)); underTest.initialize(); @@ -164,7 +172,7 @@ public class BuiltInQProfileRepositoryImplTest { public void initialize_matches_Sonar_Way_default_with_case_sensitivity() { String sonarWayInOtherCase = SONAR_WAY_QP_NAME.toUpperCase(); BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl( - new Languages(FOO_LANGUAGE), + dbClient, new Languages(FOO_LANGUAGE), new DummyProfileDefinition("foo", "goo", false), new DummyProfileDefinition("foo", sonarWayInOtherCase, false)); underTest.initialize(); diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQProfileRepositoryRule.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQProfileRepositoryRule.java index 34474b42adf..2f4a3661533 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQProfileRepositoryRule.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQProfileRepositoryRule.java @@ -19,13 +19,18 @@ */ package org.sonar.server.qualityprofile; +import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Map; import org.junit.rules.ExternalResource; import org.sonar.api.resources.Language; +import org.sonar.api.rule.RuleKey; import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition; +import org.sonar.core.util.stream.MoreCollectors; +import org.sonar.db.rule.RuleDefinitionDto; import static com.google.common.base.Preconditions.checkState; @@ -60,27 +65,39 @@ public class BuiltInQProfileRepositoryRule extends ExternalResource implements B return add(language, profileName, false); } - public BuiltInQProfile add(Language language, String profileName, boolean isDefault, BuiltInQualityProfilesDefinition.BuiltInActiveRule... rules) { + public BuiltInQProfile add(Language language, String profileName, boolean isDefault) { + return add(language, profileName, isDefault, new BuiltInQProfile.ActiveRule[0]); + } + + public BuiltInQProfile add(Language language, String profileName, boolean isDefault, BuiltInQProfile.ActiveRule... rules) { BuiltInQProfile builtIn = create(language, profileName, isDefault, rules); profiles.add(builtIn); return builtIn; } - public BuiltInQProfile create(Language language, String profileName, boolean isDefault, BuiltInQualityProfilesDefinition.BuiltInActiveRule... rules) { - return new BuiltInQProfile.Builder() + public BuiltInQProfile create(Language language, String profileName, boolean isDefault, BuiltInQProfile.ActiveRule... rules) { + BuiltInQProfile.Builder builder = new BuiltInQProfile.Builder() .setLanguage(language.getKey()) .setName(profileName) - .setDeclaredDefault(isDefault) - .addRules(Arrays.asList(rules)) - .build(); + .setDeclaredDefault(isDefault); + Arrays.stream(rules).forEach(builder::addRule); + return builder.build(); } - public BuiltInQProfile create(BuiltInQualityProfilesDefinition.BuiltInQualityProfile api) { - return new BuiltInQProfile.Builder() + public BuiltInQProfile create(BuiltInQualityProfilesDefinition.BuiltInQualityProfile api, RuleDefinitionDto... rules) { + BuiltInQProfile.Builder builder = new BuiltInQProfile.Builder() .setLanguage(api.language()) .setName(api.name()) - .setDeclaredDefault(api.isDefault()) - .addRules(new ArrayList<>(api.rules())) + .setDeclaredDefault(api.isDefault()); + Map rulesByRuleKey = Arrays.stream(rules) + .collect(MoreCollectors.uniqueIndex(RuleDefinitionDto::getKey)); + api.rules().forEach(rule -> { + RuleKey ruleKey = RuleKey.of(rule.repoKey(), rule.ruleKey()); + RuleDefinitionDto ruleDefinition = rulesByRuleKey.get(ruleKey); + Preconditions.checkState(ruleDefinition != null, "Rule '%s' not found", ruleKey); + builder.addRule(rule, ruleDefinition.getId()); + }); + return builder .build(); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQProfileUpdateImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQProfileUpdateImplTest.java index b966d46665a..81c9a6717b3 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQProfileUpdateImplTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/BuiltInQProfileUpdateImplTest.java @@ -87,7 +87,7 @@ public class BuiltInQProfileUpdateImplTest { newQp.activateRule(rule1.getRepositoryKey(), rule1.getRuleKey()).overrideSeverity(Severity.CRITICAL); newQp.activateRule(rule2.getRepositoryKey(), rule2.getRuleKey()).overrideSeverity(Severity.MAJOR); newQp.done(); - BuiltInQProfile builtIn = builtInProfileRepository.create(context.profile("xoo", "Sonar way")); + BuiltInQProfile builtIn = builtInProfileRepository.create(context.profile("xoo", "Sonar way"), rule1, rule2); underTest.update(db.getSession(), builtIn, persistedProfile); @@ -105,7 +105,7 @@ public class BuiltInQProfileUpdateImplTest { NewBuiltInQualityProfile newQp = context.createBuiltInQualityProfile("Sonar way", "xoo"); newQp.activateRule(rule.getRepositoryKey(), rule.getRuleKey()).overrideSeverity(Severity.CRITICAL); newQp.done(); - BuiltInQProfile builtIn = builtInProfileRepository.create(context.profile("xoo", "Sonar way")); + BuiltInQProfile builtIn = builtInProfileRepository.create(context.profile("xoo", "Sonar way"), rule); activateRuleInDb(persistedProfile, rule, BLOCKER); @@ -124,7 +124,7 @@ public class BuiltInQProfileUpdateImplTest { NewBuiltInQualityProfile newQp = context.createBuiltInQualityProfile("Sonar way", "xoo"); newQp.activateRule(rule.getRepositoryKey(), rule.getRuleKey()).overrideSeverity(Severity.CRITICAL); newQp.done(); - BuiltInQProfile builtIn = builtInProfileRepository.create(context.profile("xoo", "Sonar way")); + BuiltInQProfile builtIn = builtInProfileRepository.create(context.profile("xoo", "Sonar way"), rule); activateRuleInDb(persistedProfile, rule, CRITICAL); @@ -144,7 +144,7 @@ public class BuiltInQProfileUpdateImplTest { NewBuiltInQualityProfile newQp = context.createBuiltInQualityProfile("Sonar way", "xoo"); newQp.activateRule(rule2.getRepositoryKey(), rule2.getRuleKey()).overrideSeverity(Severity.MAJOR); newQp.done(); - BuiltInQProfile builtIn = builtInProfileRepository.create(context.profile("xoo", "Sonar way")); + BuiltInQProfile builtIn = builtInProfileRepository.create(context.profile("xoo", "Sonar way"), rule1, rule2); // built-in definition contains only rule2 // so rule1 must be deactivated @@ -169,7 +169,7 @@ public class BuiltInQProfileUpdateImplTest { newQp.activateRule(rule1.getRepositoryKey(), rule1.getRuleKey()).overrideSeverity(Severity.CRITICAL); newQp.activateRule(rule2.getRepositoryKey(), rule2.getRuleKey()).overrideSeverity(Severity.MAJOR); newQp.done(); - BuiltInQProfile builtIn = builtInProfileRepository.create(context.profile("xoo", "Sonar way")); + BuiltInQProfile builtIn = builtInProfileRepository.create(context.profile("xoo", "Sonar way"), rule1, rule2); // rule1 must be updated (blocker to critical) // rule2 must be activated diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RegisterQualityProfilesNotificationTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RegisterQualityProfilesNotificationTest.java index cc2983410bf..b67057e584f 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RegisterQualityProfilesNotificationTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RegisterQualityProfilesNotificationTest.java @@ -22,12 +22,15 @@ package org.sonar.server.qualityprofile; import com.google.common.collect.Multimap; import java.security.SecureRandom; import java.util.Arrays; +import java.util.List; +import java.util.Map; import java.util.Random; import java.util.function.Consumer; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.mockito.ArgumentCaptor; +import org.sonar.api.rule.RuleKey; import org.sonar.api.rule.Severity; import org.sonar.api.rules.RulePriority; import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition; @@ -36,6 +39,7 @@ import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition.NewBuiltInQ import org.sonar.api.utils.System2; import org.sonar.api.utils.log.LogTester; import org.sonar.core.util.UuidFactoryFast; +import org.sonar.core.util.stream.MoreCollectors; import org.sonar.db.DbClient; import org.sonar.db.DbTester; import org.sonar.db.organization.OrganizationDto; @@ -48,6 +52,7 @@ import org.sonar.server.rule.index.RuleIndex; import org.sonar.server.tester.UserSessionRule; import org.sonar.server.util.TypeValidations; +import static com.google.common.base.Preconditions.checkState; import static java.util.Collections.singleton; import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; import static org.apache.commons.lang.math.RandomUtils.nextLong; @@ -303,8 +308,21 @@ public class RegisterQualityProfilesNotificationTest { Arrays.stream(dbRules).forEach(dbRule -> newQp.activateRule(dbRule.getRepositoryKey(), dbRule.getRuleKey()).overrideSeverity(Severity.MAJOR)); newQp.done(); - builtInQProfileRepositoryRule.add(newLanguage(dbProfile.getLanguage()), dbProfile.getName(), false, - context.profile(dbProfile.getLanguage(), dbProfile.getName()).rules().toArray(new BuiltInActiveRule[0])); + List rules = context.profile(dbProfile.getLanguage(), dbProfile.getName()).rules(); + BuiltInQProfile.ActiveRule[] activeRules = toActiveRules(rules, dbRules); + builtInQProfileRepositoryRule.add(newLanguage(dbProfile.getLanguage()), dbProfile.getName(), false, activeRules); + } + + private static BuiltInQProfile.ActiveRule[] toActiveRules(List rules, RuleDefinitionDto[] dbRules) { + Map dbRulesByRuleKey = Arrays.stream(dbRules) + .collect(MoreCollectors.uniqueIndex(RuleDefinitionDto::getKey)); + return rules.stream() + .map(r -> { + RuleKey ruleKey = RuleKey.of(r.repoKey(), r.ruleKey()); + RuleDefinitionDto ruleDefinitionDto = dbRulesByRuleKey.get(ruleKey); + checkState(ruleDefinitionDto != null, "Rule '%s' not found", ruleKey); + return new BuiltInQProfile.ActiveRule(ruleDefinitionDto.getId(), r); + }).toArray(BuiltInQProfile.ActiveRule[]::new); } private void addPluginProfile(QProfileDto profile, RuleDefinitionDto... dbRules) { @@ -313,8 +331,8 @@ public class RegisterQualityProfilesNotificationTest { Arrays.stream(dbRules).forEach(dbRule -> newQp.activateRule(dbRule.getRepositoryKey(), dbRule.getRuleKey()).overrideSeverity(Severity.MAJOR)); newQp.done(); - builtInQProfileRepositoryRule.add(newLanguage(profile.getLanguage()), profile.getName(), false, - context.profile(profile.getLanguage(), profile.getName()).rules().toArray(new BuiltInActiveRule[0])); + BuiltInQProfile.ActiveRule[] activeRules = toActiveRules(context.profile(profile.getLanguage(), profile.getName()).rules(), dbRules); + builtInQProfileRepositoryRule.add(newLanguage(profile.getLanguage()), profile.getName(), false, activeRules); } private RulesProfileDto insertBuiltInProfile(String language) { -- 2.39.5