From e80f6ae26761d68ff7e9e2775cc9e33e715c43af Mon Sep 17 00:00:00 2001 From: =?utf8?q?S=C3=A9bastien=20Lesaint?= Date: Wed, 8 Mar 2017 18:02:03 +0100 Subject: [PATCH] SONAR-6315 remove SQL update to set default QP for language --- .../qualityprofile/QProfileFactory.java | 12 +- .../RegisterQualityProfiles.java | 262 +++++++++++++----- .../QProfileFactoryMediumTest.java | 36 +-- .../RegisterQualityProfilesTest.java | 155 +++++++++++ 4 files changed, 371 insertions(+), 94 deletions(-) create mode 100644 server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RegisterQualityProfilesTest.java diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileFactory.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileFactory.java index 6870eb05bb5..1dbe93f878f 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileFactory.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileFactory.java @@ -28,7 +28,6 @@ import java.util.Objects; import java.util.Set; import javax.annotation.CheckForNull; import javax.annotation.Nullable; -import org.apache.commons.lang.RandomStringUtils; import org.apache.commons.lang.StringUtils; import org.sonar.core.util.UuidFactory; import org.sonar.db.DbClient; @@ -62,7 +61,7 @@ public class QProfileFactory { requireNonNull(organization); QualityProfileDto profile = db.qualityProfileDao().selectByNameAndLanguage(organization, name.getName(), name.getLanguage(), dbSession); if (profile == null) { - profile = doCreate(dbSession, organization, name); + profile = doCreate(dbSession, organization, name, false); } return profile; } @@ -76,7 +75,7 @@ public class QProfileFactory { requireNonNull(organization); QualityProfileDto dto = db.qualityProfileDao().selectByNameAndLanguage(organization, name.getName(), name.getLanguage(), dbSession); checkRequest(dto == null, "Quality profile already exists: %s", name); - return doCreate(dbSession, organization, name); + return doCreate(dbSession, organization, name, false); } /** @@ -84,8 +83,8 @@ public class QProfileFactory { * * A DB error will be thrown if the quality profile already exists. */ - public QualityProfileDto create(DbSession dbSession, OrganizationDto organization, QProfileName name) { - return doCreate(dbSession, requireNonNull(organization), name); + public QualityProfileDto create(DbSession dbSession, OrganizationDto organization, QProfileName name, boolean isDefault) { + return doCreate(dbSession, requireNonNull(organization), name, isDefault); } private static OrganizationDto requireNonNull(@Nullable OrganizationDto organization) { @@ -93,7 +92,7 @@ public class QProfileFactory { return organization; } - private QualityProfileDto doCreate(DbSession dbSession, OrganizationDto organization, QProfileName name) { + private QualityProfileDto doCreate(DbSession dbSession, OrganizationDto organization, QProfileName name, boolean isDefault) { if (StringUtils.isEmpty(name.getName())) { throw BadRequestException.create("quality_profiles.profile_name_cant_be_blank"); } @@ -102,6 +101,7 @@ public class QProfileFactory { .setName(name.getName()) .setOrganizationUuid(organization.getUuid()) .setLanguage(name.getLanguage()) + .setDefault(isDefault) .setRulesUpdatedAtAsDate(now); db.qualityProfileDao().insert(dbSession, dto); return dto; diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RegisterQualityProfiles.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RegisterQualityProfiles.java index 2a797dd169a..714967f0dae 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RegisterQualityProfiles.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RegisterQualityProfiles.java @@ -20,15 +20,19 @@ package org.sonar.server.qualityprofile; import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ListMultimap; import com.google.common.collect.Multimaps; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; +import java.util.Map; +import java.util.Optional; import java.util.Set; -import org.apache.commons.lang.StringUtils; +import javax.annotation.Nullable; import org.sonar.api.profiles.ProfileDefinition; import org.sonar.api.profiles.RulesProfile; import org.sonar.api.resources.Languages; @@ -94,12 +98,22 @@ public class RegisterQualityProfiles { public void start() { Profiler profiler = Profiler.create(Loggers.get(getClass())).startInfo("Register quality profiles"); - List changes = new ArrayList<>(); - ListMultimap profilesByLanguage = profilesByLanguage(); - validateAndClean(profilesByLanguage); + + ListMultimap rulesProfilesByLanguage = buildRulesProfilesByLanguage(); + validateAndClean(rulesProfilesByLanguage); + Map> qualityProfilesByLanguage = toQualityProfilesByLanguage(rulesProfilesByLanguage); + if (qualityProfilesByLanguage.isEmpty()) { + // do not open DB session if there is no quality profile to register + profiler.stopDebug("No quality profile to register"); + return; + } + try (DbSession session = dbClient.openSession(false)) { - Multimaps.asMap(profilesByLanguage).entrySet() - .forEach(entry -> registerProfilesForLanguage(session, entry.getKey(), entry.getValue(), changes)); + OrganizationDto organization = dbClient.organizationDao().selectByUuid(session, defaultOrganizationProvider.get().getUuid()) + .orElseThrow(() -> new IllegalStateException("Failed to retrieve default organization")); + List changes = new ArrayList<>(); + qualityProfilesByLanguage.entrySet() + .forEach(entry -> registerProfilesForLanguage(session, organization, entry.getValue(), changes)); activeRuleIndexer.index(changes); profiler.stopDebug(); } @@ -108,13 +122,14 @@ public class RegisterQualityProfiles { /** * @return profiles by language */ - private ListMultimap profilesByLanguage() { + private ListMultimap buildRulesProfilesByLanguage() { ListMultimap byLang = ArrayListMultimap.create(); for (ProfileDefinition definition : definitions) { ValidationMessages validation = ValidationMessages.create(); RulesProfile profile = definition.createProfile(validation); validation.log(LOGGER); if (profile != null && !validation.hasErrors()) { + checkArgument(isNotEmpty(profile.getName()), "Profile created by Definition %s can't have a blank name", definition); byLang.put(lowerCase(profile.getLanguage(), Locale.ENGLISH), profile); } } @@ -134,93 +149,198 @@ public class RegisterQualityProfiles { LOGGER.warn("No Quality profiles defined for language: {}", language); return true; } - profiles.forEach(profile -> checkArgument(isNotEmpty(profile.getName()), "Profile name can not be blank")); - Set defaultProfileNames = defaultProfileNames(profiles); - checkState(defaultProfileNames.size() <= 1, "Several Quality profiles are flagged as default for the language %s: %s", language, defaultProfileNames); return false; }); } - private void registerProfilesForLanguage(DbSession session, String language, List defs, List changes) { - OrganizationDto organization = dbClient.organizationDao().selectByUuid(session, defaultOrganizationProvider.get().getUuid()) - .orElseThrow(() -> new IllegalStateException("Failed to retrieve default organization")); - defs.stream().collect(Collectors.index(RulesProfile::getName)).asMap().entrySet() - .forEach(entry -> { - String name = entry.getKey(); - QProfileName profileName = new QProfileName(language, name); - if (shouldRegister(profileName, session)) { - register(session, organization, profileName, entry.getValue(), changes); - } - }); - setDefault(language, organization, defs, session); - session.commit(); + private Map> toQualityProfilesByLanguage(ListMultimap rulesProfilesByLanguage) { + Map> buildersByLanguage = Multimaps.asMap(rulesProfilesByLanguage) + .entrySet() + .stream() + .collect(Collectors.uniqueIndex(Map.Entry::getKey, RegisterQualityProfiles::toQualityProfileBuilders)); + return buildersByLanguage + .entrySet() + .stream() + .filter(RegisterQualityProfiles::ensureAtMostOneDeclaredDefault) + .collect(Collectors.uniqueIndex(Map.Entry::getKey, entry -> toQualityProfiles(entry.getValue()), buildersByLanguage.size())); } - private void register(DbSession session, OrganizationDto organization, QProfileName name, Collection profiles, List changes) { - LOGGER.info("Register profile " + name); - - QualityProfileDto profileDto = dbClient.qualityProfileDao().selectByNameAndLanguage(organization, name.getName(), name.getLanguage(), session); - if (profileDto != null) { - changes.addAll(profileFactory.delete(session, profileDto.getKey(), true)); - } - QualityProfileDto newQProfileDto = profileFactory.create(session, organization, name); - for (RulesProfile profile : profiles) { - for (org.sonar.api.rules.ActiveRule activeRule : profile.getActiveRules()) { - RuleKey ruleKey = RuleKey.of(activeRule.getRepositoryKey(), activeRule.getRuleKey()); - RuleActivation activation = new RuleActivation(ruleKey); - activation.setSeverity(activeRule.getSeverity() != null ? activeRule.getSeverity().name() : null); - for (ActiveRuleParam param : activeRule.getActiveRuleParams()) { - activation.setParameter(param.getKey(), param.getValue()); - } - changes.addAll(ruleActivator.activate(session, activation, newQProfileDto)); - } + /** + * Creates {@link QualityProfile.Builder} for each unique quality profile name for a given language. + * Builders will have the following properties populated: + *
    + *
  • {@link QualityProfile.Builder#language language}: key of the method's parameter
  • + *
  • {@link QualityProfile.Builder#name name}: {@link RulesProfile#getName()}
  • + *
  • {@link QualityProfile.Builder#declaredDefault declaredDefault}: {@code true} if at least one RulesProfile + * with a given name has {@link RulesProfile#getDefaultProfile()} is {@code true}
  • + *
  • {@link QualityProfile.Builder#activeRules activeRules}: the concatenate of the active rules of all + * RulesProfile with a given name
  • + *
+ */ + private static List toQualityProfileBuilders(Map.Entry> rulesProfilesByLanguage) { + String language = rulesProfilesByLanguage.getKey(); + // use a LinkedHashMap to keep order of insertion of RulesProfiles + Map qualityProfileBuildersByName = new LinkedHashMap<>(); + for (RulesProfile rulesProfile : rulesProfilesByLanguage.getValue()) { + qualityProfileBuildersByName.compute( + rulesProfile.getName(), + (name, existingBuilder) -> updateOrCreateBuilder(language, existingBuilder, rulesProfile, name)); } + return ImmutableList.copyOf(qualityProfileBuildersByName.values()); + } - LoadedTemplateDto template = new LoadedTemplateDto(templateKey(name), LoadedTemplateDto.QUALITY_PROFILE_TYPE); - dbClient.loadedTemplateDao().insert(template, session); - session.commit(); + /** + * Fails if more than one {@link QualityProfile.Builder#declaredDefault} is {@code true}, otherwise returns {@code true}. + */ + private static boolean ensureAtMostOneDeclaredDefault(Map.Entry> entry) { + Set declaredDefaultProfileNames = entry.getValue().stream() + .filter(QualityProfile.Builder::isDeclaredDefault) + .map(QualityProfile.Builder::getName) + .collect(Collectors.toSet()); + checkState(declaredDefaultProfileNames.size() <= 1, "Several Quality profiles are flagged as default for the language %s: %s", entry.getKey(), declaredDefaultProfileNames); + return true; } - private void setDefault(String language, OrganizationDto organization, List profileDefs, DbSession session) { - QualityProfileDto currentDefault = dbClient.qualityProfileDao().selectDefaultProfile(session, organization, language); + private static QualityProfile.Builder updateOrCreateBuilder(String language, @Nullable QualityProfile.Builder existingBuilder, RulesProfile rulesProfile, String name) { + QualityProfile.Builder builder = existingBuilder; + if (builder == null) { + builder = new QualityProfile.Builder() + .setLanguage(language) + .setName(name); + } + Boolean defaultProfile = rulesProfile.getDefaultProfile(); + boolean declaredDefault = defaultProfile != null && defaultProfile; + return builder + // if there is multiple RulesProfiles with the same name, if at least one is declared default, + // then QualityProfile is flagged as declared default + .setDeclaredDefault(builder.declaredDefault || declaredDefault) + .addRules(rulesProfile.getActiveRules()); + } - if (currentDefault == null) { - String defaultProfileName = nameOfDefaultProfile(profileDefs); - LOGGER.info("Set default " + language + " profile: " + defaultProfileName); - QualityProfileDto newDefaultProfile = dbClient.qualityProfileDao().selectByNameAndLanguage(defaultProfileName, language, session); - if (newDefaultProfile == null) { - // Must not happen, we just registered it - throw new IllegalStateException("Could not find declared default profile '%s' for language '%s'"); + private static List toQualityProfiles(List builders) { + if (builders.stream().noneMatch(QualityProfile.Builder::isDeclaredDefault)) { + Optional sonarWayProfile = builders.stream().filter(builder -> builder.getName().equals(DEFAULT_PROFILE_NAME)).findFirst(); + if (sonarWayProfile.isPresent()) { + sonarWayProfile.get().setComputedDefault(true); } else { - dbClient.qualityProfileDao().update(session, newDefaultProfile.setDefault(true)); + builders.iterator().next().setComputedDefault(true); } } + return builders.stream().map(QualityProfile.Builder::build).collect(Collectors.toList(builders.size())); } - private static String nameOfDefaultProfile(List profiles) { - String defaultName = null; - boolean hasSonarWay = false; + private static final class QualityProfile { + private final QProfileName qProfileName; + private final boolean isDefault; + private final List activeRules; - for (RulesProfile profile : profiles) { - if (profile.getDefaultProfile()) { - defaultName = profile.getName(); - } else if (DEFAULT_PROFILE_NAME.equals(profile.getName())) { - hasSonarWay = true; - } + public QualityProfile(Builder builder) { + this.qProfileName = new QProfileName(builder.getLanguage(), builder.getName()); + this.isDefault = builder.declaredDefault || builder.computedDefault; + this.activeRules = ImmutableList.copyOf(builder.activeRules); + } + + public String getName() { + return qProfileName.getName(); } - if (StringUtils.isBlank(defaultName) && !hasSonarWay && !profiles.isEmpty()) { - defaultName = profiles.get(0).getName(); + public String getLanguage() { + return qProfileName.getLanguage(); } - return StringUtils.defaultIfBlank(defaultName, DEFAULT_PROFILE_NAME); + public QProfileName getQProfileName() { + return qProfileName; + } + + public boolean isDefault() { + return isDefault; + } + + public List getActiveRules() { + return activeRules; + } + + private static final class Builder { + private String language; + private String name; + private boolean declaredDefault; + private boolean computedDefault; + private List activeRules = new ArrayList<>(); + + public String getLanguage() { + return language; + } + + public Builder setLanguage(String language) { + this.language = language; + return this; + } + + Builder setName(String name) { + this.name = name; + return this; + } + + String getName() { + return name; + } + + Builder setDeclaredDefault(boolean declaredDefault) { + this.declaredDefault = declaredDefault; + return this; + } + + boolean isDeclaredDefault() { + return declaredDefault; + } + + Builder setComputedDefault(boolean flag) { + computedDefault = flag; + return this; + } + + Builder addRules(List rules) { + this.activeRules.addAll(rules); + return this; + } + + QualityProfile build() { + return new QualityProfile(this); + } + } } - private static Set defaultProfileNames(Collection profiles) { - return profiles.stream() - .filter(RulesProfile::getDefaultProfile) - .map(RulesProfile::getName) - .collect(Collectors.toSet()); + private void registerProfilesForLanguage(DbSession session, OrganizationDto organization, List qualityProfiles, List changes) { + qualityProfiles + .forEach(qualityProfile -> { + if (shouldRegister(qualityProfile.getQProfileName(), session)) { + register(session, organization, qualityProfile, changes); + } + }); + session.commit(); + } + + private void register(DbSession session, OrganizationDto organization, QualityProfile qualityProfile, List changes) { + LOGGER.info("Register profile " + qualityProfile.getQProfileName()); + + QualityProfileDto profileDto = dbClient.qualityProfileDao().selectByNameAndLanguage(organization, qualityProfile.getName(), qualityProfile.getLanguage(), session); + if (profileDto != null) { + changes.addAll(profileFactory.delete(session, profileDto.getKey(), true)); + } + QualityProfileDto newQProfileDto = profileFactory.create(session, organization, qualityProfile.getQProfileName(), qualityProfile.isDefault()); + for (org.sonar.api.rules.ActiveRule activeRule : qualityProfile.getActiveRules()) { + RuleKey ruleKey = RuleKey.of(activeRule.getRepositoryKey(), activeRule.getRuleKey()); + RuleActivation activation = new RuleActivation(ruleKey); + activation.setSeverity(activeRule.getSeverity() != null ? activeRule.getSeverity().name() : null); + for (ActiveRuleParam param : activeRule.getActiveRuleParams()) { + activation.setParameter(param.getKey(), param.getValue()); + } + changes.addAll(ruleActivator.activate(session, activation, newQProfileDto)); + } + + LoadedTemplateDto template = new LoadedTemplateDto(templateKey(qualityProfile.getQProfileName()), LoadedTemplateDto.QUALITY_PROFILE_TYPE); + dbClient.loadedTemplateDao().insert(template, session); + session.commit(); } private boolean shouldRegister(QProfileName key, DbSession session) { diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileFactoryMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileFactoryMediumTest.java index d3640b47f89..110db4fbea6 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileFactoryMediumTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileFactoryMediumTest.java @@ -100,12 +100,7 @@ public class QProfileFactoryMediumTest { // reload the dto QualityProfileDto readDto = db.qualityProfileDao().selectByNameAndLanguage("P1", "xoo", dbSession); - assertThat(readDto.getOrganizationUuid()).isEqualTo(uuid); - assertThat(readDto.getName()).isEqualTo(writtenDto.getName()); - assertThat(readDto.getKey()).startsWith(writtenDto.getKey()); - assertThat(readDto.getLanguage()).isEqualTo(writtenDto.getLanguage()); - assertThat(readDto.getId()).isEqualTo(writtenDto.getId()); - assertThat(readDto.getParentKee()).isNull(); + assertEqual(writtenDto, readDto); assertThat(db.qualityProfileDao().selectAll(dbSession, organization)).hasSize(1); } @@ -114,7 +109,7 @@ public class QProfileFactoryMediumTest { public void create() { String uuid = organization.getUuid(); - QualityProfileDto writtenDto = factory.create(dbSession, organization, new QProfileName("xoo", "P1")); + QualityProfileDto writtenDto = factory.create(dbSession, organization, new QProfileName("xoo", "P1"), true); dbSession.commit(); dbSession.clearCache(); assertThat(writtenDto.getOrganizationUuid()).isEqualTo(uuid); @@ -122,15 +117,12 @@ public class QProfileFactoryMediumTest { assertThat(writtenDto.getName()).isEqualTo("P1"); assertThat(writtenDto.getLanguage()).isEqualTo("xoo"); assertThat(writtenDto.getId()).isNotNull(); + assertThat(writtenDto.getParentKee()).isNull(); + assertThat(writtenDto.isDefault()).isTrue(); // reload the dto QualityProfileDto readDto = db.qualityProfileDao().selectByNameAndLanguage(organization, "P1", "xoo", dbSession); - assertThat(readDto.getOrganizationUuid()).isEqualTo(uuid); - assertThat(readDto.getName()).isEqualTo(writtenDto.getName()); - assertThat(readDto.getKey()).startsWith(writtenDto.getKey()); - assertThat(readDto.getLanguage()).isEqualTo(writtenDto.getLanguage()); - assertThat(readDto.getId()).isEqualTo(writtenDto.getId()); - assertThat(readDto.getParentKee()).isNull(); + assertEqual(writtenDto, readDto); assertThat(db.qualityProfileDao().selectAll(dbSession, organization)).hasSize(1); } @@ -171,7 +163,7 @@ public class QProfileFactoryMediumTest { expectBadRequestException("quality_profiles.profile_name_cant_be_blank"); - factory.create(dbSession, organization, name); + factory.create(dbSession, organization, name, true); } @Test @@ -180,17 +172,17 @@ public class QProfileFactoryMediumTest { expectBadRequestException("quality_profiles.profile_name_cant_be_blank"); - factory.create(dbSession, organization, name); + factory.create(dbSession, organization, name, false); } @Test public void create_does_not_fail_if_already_exists() { QProfileName name = new QProfileName("xoo", "P1"); - factory.create(dbSession, organization, name); + factory.create(dbSession, organization, name, true); dbSession.commit(); dbSession.clearCache(); - assertThat(factory.create(dbSession, organization, name)).isNotNull(); + assertThat(factory.create(dbSession, organization, name, true)).isNotNull(); } @Test @@ -320,4 +312,14 @@ public class QProfileFactoryMediumTest { thrown.expect(BadRequestException.class); thrown.expectMessage(message); } + + private static void assertEqual(QualityProfileDto writtenDto, QualityProfileDto readDto) { + assertThat(readDto.getOrganizationUuid()).isEqualTo(writtenDto.getOrganizationUuid()); + assertThat(readDto.getName()).isEqualTo(writtenDto.getName()); + assertThat(readDto.getKey()).startsWith(writtenDto.getKey()); + assertThat(readDto.getLanguage()).isEqualTo(writtenDto.getLanguage()); + assertThat(readDto.getId()).isEqualTo(writtenDto.getId()); + assertThat(readDto.getParentKee()).isEqualTo(writtenDto.getParentKee()); + assertThat(readDto.isDefault()).isEqualTo(writtenDto.isDefault()); + } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RegisterQualityProfilesTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RegisterQualityProfilesTest.java new file mode 100644 index 00000000000..48d8ccb7bad --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RegisterQualityProfilesTest.java @@ -0,0 +1,155 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program 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. + * + * This program 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.server.qualityprofile; + +import java.util.Collections; +import java.util.List; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.api.profiles.ProfileDefinition; +import org.sonar.api.profiles.RulesProfile; +import org.sonar.api.resources.Language; +import org.sonar.api.resources.Languages; +import org.sonar.api.utils.System2; +import org.sonar.api.utils.ValidationMessages; +import org.sonar.api.utils.internal.AlwaysIncreasingSystem2; +import org.sonar.core.util.UuidFactoryFast; +import org.sonar.db.DbClient; +import org.sonar.db.DbTester; +import org.sonar.server.organization.DefaultOrganizationProvider; +import org.sonar.server.organization.TestDefaultOrganizationProvider; +import org.sonar.server.qualityprofile.index.ActiveRuleIndexer; +import org.sonar.server.tester.UserSessionRule; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verifyZeroInteractions; + +public class RegisterQualityProfilesTest { + + private static final DummyLanguage FOO_LANGUAGE = new DummyLanguage("foo"); + + @Rule + public DbTester dbTester = DbTester.create(System2.INSTANCE); + @Rule + public UserSessionRule userSessionRule = UserSessionRule.standalone(); + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + private DbClient dbClient = dbTester.getDbClient(); + private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(dbTester); + private DbClient mockedDbClient = mock(DbClient.class); + private ActiveRuleIndexer mockedActiveRuleIndexer = mock(ActiveRuleIndexer.class); + + @Test + public void no_action_in_DB_nor_index_when_there_is_no_definition() { + RegisterQualityProfiles underTest = mockedDBAndEs(Collections.emptyList(), new Languages(FOO_LANGUAGE)); + + underTest.start(); + + verifyZeroInteractions(mockedDbClient, mockedActiveRuleIndexer); + } + + @Test + public void no_action_in_DB_nor_index_when_all_definitions_apply_to_non_defined_languages() { + RegisterQualityProfiles underTest = mockedDBAndEs(Collections.singletonList(new DummyProfileDefinition("foo", "P1", false)), new Languages()); + + underTest.start(); + + verifyZeroInteractions(mockedDbClient, mockedActiveRuleIndexer); + } + + @Test + public void start_throws_IAE_if_profileDefinition_creates_RulesProfile_with_null_name() { + DummyProfileDefinition definition = new DummyProfileDefinition("foo", null, false); + RegisterQualityProfiles underTest = mockedDBAndEs(Collections.singletonList(definition), new Languages()); + + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("Profile created by Definition " + definition + " can't have a blank name"); + + underTest.start(); + } + + @Test + public void start_throws_IAE_if_profileDefinition_creates_RulesProfile_with_empty_name() { + DummyProfileDefinition definition = new DummyProfileDefinition("foo", "", false); + RegisterQualityProfiles underTest = mockedDBAndEs(Collections.singletonList(definition), new Languages()); + + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("Profile created by Definition " + definition + " can't have a blank name"); + + underTest.start(); + } + + private RegisterQualityProfiles mockedDBAndEs(List definitions, Languages languages) { + return new RegisterQualityProfiles(mockedDbClient, null, null, definitions, languages, mockedActiveRuleIndexer, null); + } + + public RegisterQualityProfiles mockedEs(List definitions, Languages languages) { + return new RegisterQualityProfiles( + dbClient, + new QProfileFactory(dbClient, UuidFactoryFast.getInstance()), + new CachingRuleActivator(AlwaysIncreasingSystem2.INSTANCE, dbClient, null, new RuleActivatorContextFactory(dbClient), null, null, userSessionRule), + definitions, + languages, + mockedActiveRuleIndexer, + defaultOrganizationProvider); + } + + private static final class DummyProfileDefinition extends ProfileDefinition { + private final String language; + private final String name; + private final boolean defaultProfile; + + private DummyProfileDefinition(String language, String name, boolean defaultProfile) { + this.language = language; + this.name = name; + this.defaultProfile = defaultProfile; + } + + @Override + public RulesProfile createProfile(ValidationMessages validation) { + return RulesProfile.create(name, language); + } + } + + private static class DummyLanguage implements Language { + private final String key; + + private DummyLanguage(String key) { + this.key = key; + } + + @Override + public String getKey() { + return key; + } + + @Override + public String getName() { + return key; + } + + @Override + public String[] getFileSuffixes() { + return new String[] {key}; + } + } +} -- 2.39.5