]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-8888 add DefinedQProfileRepository
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Thu, 16 Mar 2017 09:28:37 +0000 (10:28 +0100)
committerSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Thu, 23 Mar 2017 16:38:34 +0000 (17:38 +0100)
12 files changed:
server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/DefinedQProfile.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/DefinedQProfileRepository.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/DefinedQProfileRepositoryImpl.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RegisterQualityProfiles.java
server/sonar-server/src/test/java/org/sonar/server/organization/OrganizationCreationImplTest.java
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/DefinedQProfileRepositoryImplTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/DefinedQProfileRepositoryRule.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileResetMediumTest.java
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QualityProfileTest.java
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RegisterQualityProfilesTest.java
server/sonar-server/src/test/java/org/sonar/server/rule/RegisterRulesMediumTest.java

index 2a2ac3cc83fa47f6a79fb95e403ec274e30aa887..df4b1e4cb7c3b9cd69b85a2ded09a7d056031279 100644 (file)
@@ -140,6 +140,7 @@ import org.sonar.server.projecttag.ws.ProjectTagsWsModule;
 import org.sonar.server.property.InternalPropertiesImpl;
 import org.sonar.server.property.ws.PropertiesWs;
 import org.sonar.server.qualitygate.QualityGateModule;
+import org.sonar.server.qualityprofile.DefinedQProfileRepositoryImpl;
 import org.sonar.server.qualityprofile.QProfileBackuperImpl;
 import org.sonar.server.qualityprofile.QProfileComparison;
 import org.sonar.server.qualityprofile.QProfileCopier;
@@ -256,6 +257,7 @@ public class PlatformLevel4 extends PlatformLevel {
       OrganizationsWsModule.class,
 
       // quality profile
+      DefinedQProfileRepositoryImpl.class,
       ActiveRuleIndexer.class,
       XMLProfileParser.class,
       XMLProfileSerializer.class,
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/DefinedQProfile.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/DefinedQProfile.java
new file mode 100644 (file)
index 0000000..278caad
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * 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 com.google.common.collect.ImmutableList;
+import java.security.MessageDigest;
+import java.util.ArrayList;
+import java.util.List;
+import javax.annotation.concurrent.Immutable;
+import org.sonar.api.profiles.ProfileDefinition;
+
+import static java.lang.String.format;
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.apache.commons.codec.binary.Hex.encodeHexString;
+import static org.apache.commons.lang.StringUtils.lowerCase;
+import static org.sonar.db.loadedtemplate.LoadedTemplateDto.QUALITY_PROFILE_TYPE;
+
+/**
+ * Represent a Quality Profile as computed from {@link ProfileDefinition} provided by installed plugins.
+ */
+@Immutable
+public final class DefinedQProfile {
+  private final QProfileName qProfileName;
+  private final boolean isDefault;
+  private final String loadedTemplateType;
+  private final List<org.sonar.api.rules.ActiveRule> activeRules;
+
+  private DefinedQProfile(Builder builder, MessageDigest messageDigest) {
+    this.qProfileName = new QProfileName(builder.language, builder.getName());
+    this.isDefault = builder.declaredDefault || builder.computedDefault;
+    this.loadedTemplateType = computeLoadedTemplateType(this.qProfileName, messageDigest);
+    this.activeRules = ImmutableList.copyOf(builder.activeRules);
+  }
+
+  private static String computeLoadedTemplateType(QProfileName qProfileName, MessageDigest messageDigest) {
+    String qpIdentifier = lowerCase(qProfileName.getLanguage()) + ":" + qProfileName.getName();
+    return format("%s.%s", QUALITY_PROFILE_TYPE, encodeHexString(messageDigest.digest(qpIdentifier.getBytes(UTF_8))));
+  }
+
+  public String getName() {
+    return qProfileName.getName();
+  }
+
+  public String getLanguage() {
+    return qProfileName.getLanguage();
+  }
+
+  public QProfileName getQProfileName() {
+    return qProfileName;
+  }
+
+  public boolean isDefault() {
+    return isDefault;
+  }
+
+  public String getLoadedTemplateType() {
+    return loadedTemplateType;
+  }
+
+  public List<org.sonar.api.rules.ActiveRule> getActiveRules() {
+    return activeRules;
+  }
+
+  static final class Builder {
+    private String language;
+    private String name;
+    private boolean declaredDefault;
+    private boolean computedDefault;
+    private final List<org.sonar.api.rules.ActiveRule> activeRules = new ArrayList<>();
+
+    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<org.sonar.api.rules.ActiveRule> rules) {
+      this.activeRules.addAll(rules);
+      return this;
+    }
+
+    DefinedQProfile build(MessageDigest messageDigest) {
+      return new DefinedQProfile(this, messageDigest);
+    }
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/DefinedQProfileRepository.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/DefinedQProfileRepository.java
new file mode 100644 (file)
index 0000000..53452d1
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * 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.List;
+import java.util.Map;
+
+public interface DefinedQProfileRepository {
+  /**
+   * Initializes the Repository.
+   *
+   * This method is intended to be called from a startup task
+   * (see {@link org.sonar.server.platform.platformlevel.PlatformLevelStartup}).
+   *
+   * @throws IllegalStateException if called more then once
+   */
+  void initialize();
+
+  /**
+   * @return an immutable map containing immutable lists.
+   *
+   * @throws IllegalStateException if {@link #initialize()} has not been called
+   */
+  Map<String, List<DefinedQProfile>> getQProfilesByLanguage();
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/DefinedQProfileRepositoryImpl.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/DefinedQProfileRepositoryImpl.java
new file mode 100644 (file)
index 0000000..e89d2fd
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * 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 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.security.MessageDigest;
+import java.util.Collection;
+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 javax.annotation.Nullable;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.sonar.api.profiles.ProfileDefinition;
+import org.sonar.api.profiles.RulesProfile;
+import org.sonar.api.resources.Languages;
+import org.sonar.api.utils.ValidationMessages;
+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.Collectors;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
+import static org.apache.commons.lang.StringUtils.isNotEmpty;
+import static org.apache.commons.lang.StringUtils.lowerCase;
+
+public class DefinedQProfileRepositoryImpl implements DefinedQProfileRepository {
+  private static final Logger LOGGER = Loggers.get(DefinedQProfileRepositoryImpl.class);
+  private static final String DEFAULT_PROFILE_NAME = "Sonar way";
+
+  private final Languages languages;
+  private final List<ProfileDefinition> definitions;
+  private Map<String, List<DefinedQProfile>> qProfilesByLanguage;
+
+  /**
+   * Requires for pico container when no {@link ProfileDefinition} is defined at all
+   */
+  public DefinedQProfileRepositoryImpl(Languages languages) {
+    this(languages, new ProfileDefinition[0]);
+  }
+
+  public DefinedQProfileRepositoryImpl(Languages languages, ProfileDefinition... definitions) {
+    this.languages = languages;
+    this.definitions = ImmutableList.copyOf(definitions);
+  }
+
+  @Override
+  public void initialize() {
+    checkState(qProfilesByLanguage == null, "initialize must be called only once");
+
+    Profiler profiler = Profiler.create(Loggers.get(getClass())).startInfo("Load quality profiles");
+    ListMultimap<String, RulesProfile> rulesProfilesByLanguage = buildRulesProfilesByLanguage();
+    validateAndClean(rulesProfilesByLanguage);
+    this.qProfilesByLanguage = toQualityProfilesByLanguage(rulesProfilesByLanguage);
+    profiler.stopDebug();
+  }
+
+  @Override
+  public Map<String, List<DefinedQProfile>> getQProfilesByLanguage() {
+    checkState(qProfilesByLanguage != null, "initialize must be called first");
+
+    return qProfilesByLanguage;
+  }
+
+  /**
+   * @return profiles by language
+   */
+  private ListMultimap<String, RulesProfile> buildRulesProfilesByLanguage() {
+    ListMultimap<String, RulesProfile> 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);
+      }
+    }
+    return byLang;
+  }
+
+  private void validateAndClean(ListMultimap<String, RulesProfile> byLang) {
+    byLang.asMap().entrySet()
+      .removeIf(entry -> {
+        String language = entry.getKey();
+        if (languages.get(language) == null) {
+          LOGGER.info("Language {} is not installed, related Quality profiles are ignored", language);
+          return true;
+        }
+        Collection<RulesProfile> profiles = entry.getValue();
+        if (profiles.isEmpty()) {
+          LOGGER.warn("No Quality profiles defined for language: {}", language);
+          return true;
+        }
+        return false;
+      });
+  }
+
+  private Map<String, List<DefinedQProfile>> toQualityProfilesByLanguage(ListMultimap<String, RulesProfile> rulesProfilesByLanguage) {
+    Map<String, List<DefinedQProfile.Builder>> buildersByLanguage = Multimaps.asMap(rulesProfilesByLanguage)
+      .entrySet()
+      .stream()
+      .collect(Collectors.uniqueIndex(Map.Entry::getKey, DefinedQProfileRepositoryImpl::toQualityProfileBuilders));
+    return buildersByLanguage
+      .entrySet()
+      .stream()
+      .filter(DefinedQProfileRepositoryImpl::ensureAtMostOneDeclaredDefault)
+      .collect(Collectors.uniqueIndex(Map.Entry::getKey, entry -> toQualityProfiles(entry.getValue()), buildersByLanguage.size()));
+  }
+
+  /**
+   * Creates {@link DefinedQProfile.Builder} for each unique quality profile name for a given language.
+   * Builders will have the following properties populated:
+   * <ul>
+   *   <li>{@link DefinedQProfile.Builder#language language}: key of the method's parameter</li>
+   *   <li>{@link DefinedQProfile.Builder#name name}: {@link RulesProfile#getName()}</li>
+   *   <li>{@link DefinedQProfile.Builder#declaredDefault declaredDefault}: {@code true} if at least one RulesProfile
+   *       with a given name has {@link RulesProfile#getDefaultProfile()} is {@code true}</li>
+   *   <li>{@link DefinedQProfile.Builder#activeRules activeRules}: the concatenate of the active rules of all
+   *       RulesProfile with a given name</li>
+   * </ul>
+   */
+  private static List<DefinedQProfile.Builder> toQualityProfileBuilders(Map.Entry<String, List<RulesProfile>> rulesProfilesByLanguage) {
+    String language = rulesProfilesByLanguage.getKey();
+    // use a LinkedHashMap to keep order of insertion of RulesProfiles
+    Map<String, DefinedQProfile.Builder> qualityProfileBuildersByName = new LinkedHashMap<>();
+    for (RulesProfile rulesProfile : rulesProfilesByLanguage.getValue()) {
+      qualityProfileBuildersByName.compute(
+        rulesProfile.getName(),
+        (name, existingBuilder) -> updateOrCreateBuilder(language, existingBuilder, rulesProfile, name));
+    }
+    return ImmutableList.copyOf(qualityProfileBuildersByName.values());
+  }
+
+  /**
+   * Fails if more than one {@link DefinedQProfile.Builder#declaredDefault} is {@code true}, otherwise returns {@code true}.
+   */
+  private static boolean ensureAtMostOneDeclaredDefault(Map.Entry<String, List<DefinedQProfile.Builder>> entry) {
+    Set<String> declaredDefaultProfileNames = entry.getValue().stream()
+      .filter(DefinedQProfile.Builder::isDeclaredDefault)
+      .map(DefinedQProfile.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 static DefinedQProfile.Builder updateOrCreateBuilder(String language, @Nullable DefinedQProfile.Builder existingBuilder, RulesProfile rulesProfile, String name) {
+    DefinedQProfile.Builder builder = existingBuilder;
+    if (builder == null) {
+      builder = new DefinedQProfile.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.isDeclaredDefault() || declaredDefault)
+      .addRules(rulesProfile.getActiveRules());
+  }
+
+  private static List<DefinedQProfile> toQualityProfiles(List<DefinedQProfile.Builder> builders) {
+    if (builders.stream().noneMatch(DefinedQProfile.Builder::isDeclaredDefault)) {
+      Optional<DefinedQProfile.Builder> sonarWayProfile = builders.stream().filter(builder -> builder.getName().equals(DEFAULT_PROFILE_NAME)).findFirst();
+      if (sonarWayProfile.isPresent()) {
+        sonarWayProfile.get().setComputedDefault(true);
+      } else {
+        builders.iterator().next().setComputedDefault(true);
+      }
+    }
+    MessageDigest md5Digest = DigestUtils.getMd5Digest();
+    return builders.stream()
+      .map(builder -> builder.build(md5Digest))
+      .collect(Collectors.toList(builders.size()));
+  }
+}
index df177787b6a5cda10fa280ae9b48210dd13c71d9..23ef3093c429a77fbbc6cf739ee40e09dd46f520 100644 (file)
  */
 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.security.MessageDigest;
 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 javax.annotation.Nullable;
-import org.apache.commons.codec.digest.DigestUtils;
-import org.sonar.api.profiles.ProfileDefinition;
-import org.sonar.api.profiles.RulesProfile;
-import org.sonar.api.resources.Languages;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.rules.ActiveRuleParam;
 import org.sonar.api.server.ServerSide;
-import org.sonar.api.utils.ValidationMessages;
 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.Collectors;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.Pagination;
@@ -54,15 +35,7 @@ import org.sonar.db.organization.OrganizationDto;
 import org.sonar.db.qualityprofile.QualityProfileDto;
 import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
 
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkState;
-import static java.lang.String.format;
-import static java.nio.charset.StandardCharsets.UTF_8;
-import static org.apache.commons.codec.binary.Hex.encodeHexString;
-import static org.apache.commons.lang.StringUtils.isNotEmpty;
-import static org.apache.commons.lang.StringUtils.lowerCase;
 import static org.sonar.db.Pagination.forPage;
-import static org.sonar.db.loadedtemplate.LoadedTemplateDto.QUALITY_PROFILE_TYPE;
 
 /**
  * Synchronize Quality profiles during server startup
@@ -71,175 +44,43 @@ import static org.sonar.db.loadedtemplate.LoadedTemplateDto.QUALITY_PROFILE_TYPE
 public class RegisterQualityProfiles {
 
   private static final Logger LOGGER = Loggers.get(RegisterQualityProfiles.class);
-  private static final String DEFAULT_PROFILE_NAME = "Sonar way";
   private static final Pagination PROCESSED_ORGANIZATIONS_BATCH_SIZE = forPage(1).andSize(2000);
 
-  private final List<ProfileDefinition> definitions;
+  private final DefinedQProfileRepository definedQProfileRepository;
   private final DbClient dbClient;
   private final QProfileFactory profileFactory;
   private final RuleActivator ruleActivator;
-  private final Languages languages;
   private final ActiveRuleIndexer activeRuleIndexer;
 
-  /**
-   * To be kept when no ProfileDefinition are injected
-   */
-  public RegisterQualityProfiles(DbClient dbClient,
-    QProfileFactory profileFactory, CachingRuleActivator ruleActivator, Languages languages, ActiveRuleIndexer activeRuleIndexer) {
-    this(dbClient, profileFactory, ruleActivator, Collections.emptyList(), languages, activeRuleIndexer);
-  }
-
-  public RegisterQualityProfiles(DbClient dbClient,
-    QProfileFactory profileFactory, CachingRuleActivator ruleActivator,
-    List<ProfileDefinition> definitions, Languages languages, ActiveRuleIndexer activeRuleIndexer) {
+  public RegisterQualityProfiles(DefinedQProfileRepository definedQProfileRepository,
+    DbClient dbClient,
+    QProfileFactory profileFactory, CachingRuleActivator ruleActivator, ActiveRuleIndexer activeRuleIndexer) {
+    this.definedQProfileRepository = definedQProfileRepository;
     this.dbClient = dbClient;
     this.profileFactory = profileFactory;
     this.ruleActivator = ruleActivator;
-    this.definitions = definitions;
-    this.languages = languages;
     this.activeRuleIndexer = activeRuleIndexer;
   }
 
   public void start() {
     Profiler profiler = Profiler.create(Loggers.get(getClass())).startInfo("Register quality profiles");
 
-    ListMultimap<String, RulesProfile> rulesProfilesByLanguage = buildRulesProfilesByLanguage();
-    validateAndClean(rulesProfilesByLanguage);
-    Map<String, List<QualityProfile>> 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;
-    }
-
+    definedQProfileRepository.initialize();
     try (DbSession session = dbClient.openSession(false)) {
       List<ActiveRuleChange> changes = new ArrayList<>();
-      qualityProfilesByLanguage.entrySet()
+      definedQProfileRepository.getQProfilesByLanguage().entrySet()
         .forEach(entry -> registerPerLanguage(session, entry.getValue(), changes));
       activeRuleIndexer.index(changes);
       profiler.stopDebug();
     }
   }
 
-  /**
-   * @return profiles by language
-   */
-  private ListMultimap<String, RulesProfile> buildRulesProfilesByLanguage() {
-    ListMultimap<String, RulesProfile> 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);
-      }
-    }
-    return byLang;
-  }
-
-  private void validateAndClean(ListMultimap<String, RulesProfile> byLang) {
-    byLang.asMap().entrySet()
-      .removeIf(entry -> {
-        String language = entry.getKey();
-        if (languages.get(language) == null) {
-          LOGGER.info("Language {} is not installed, related Quality profiles are ignored", language);
-          return true;
-        }
-        Collection<RulesProfile> profiles = entry.getValue();
-        if (profiles.isEmpty()) {
-          LOGGER.warn("No Quality profiles defined for language: {}", language);
-          return true;
-        }
-        return false;
-      });
-  }
-
-  private Map<String, List<QualityProfile>> toQualityProfilesByLanguage(ListMultimap<String, RulesProfile> rulesProfilesByLanguage) {
-    Map<String, List<QualityProfile.Builder>> 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()));
-  }
-
-  /**
-   * Creates {@link QualityProfile.Builder} for each unique quality profile name for a given language.
-   * Builders will have the following properties populated:
-   * <ul>
-   *   <li>{@link QualityProfile.Builder#language language}: key of the method's parameter</li>
-   *   <li>{@link QualityProfile.Builder#name name}: {@link RulesProfile#getName()}</li>
-   *   <li>{@link QualityProfile.Builder#declaredDefault declaredDefault}: {@code true} if at least one RulesProfile
-   *       with a given name has {@link RulesProfile#getDefaultProfile()} is {@code true}</li>
-   *   <li>{@link QualityProfile.Builder#activeRules activeRules}: the concatenate of the active rules of all
-   *       RulesProfile with a given name</li>
-   * </ul>
-   */
-  private static List<QualityProfile.Builder> toQualityProfileBuilders(Map.Entry<String, List<RulesProfile>> rulesProfilesByLanguage) {
-    String language = rulesProfilesByLanguage.getKey();
-    // use a LinkedHashMap to keep order of insertion of RulesProfiles
-    Map<String, QualityProfile.Builder> qualityProfileBuildersByName = new LinkedHashMap<>();
-    for (RulesProfile rulesProfile : rulesProfilesByLanguage.getValue()) {
-      qualityProfileBuildersByName.compute(
-        rulesProfile.getName(),
-        (name, existingBuilder) -> updateOrCreateBuilder(language, existingBuilder, rulesProfile, name));
-    }
-    return ImmutableList.copyOf(qualityProfileBuildersByName.values());
-  }
-
-  /**
-   * Fails if more than one {@link QualityProfile.Builder#declaredDefault} is {@code true}, otherwise returns {@code true}.
-   */
-  private static boolean ensureAtMostOneDeclaredDefault(Map.Entry<String, List<QualityProfile.Builder>> entry) {
-    Set<String> 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 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());
-  }
-
-  private static List<QualityProfile> toQualityProfiles(List<QualityProfile.Builder> builders) {
-    if (builders.stream().noneMatch(QualityProfile.Builder::isDeclaredDefault)) {
-      Optional<QualityProfile.Builder> sonarWayProfile = builders.stream().filter(builder -> builder.getName().equals(DEFAULT_PROFILE_NAME)).findFirst();
-      if (sonarWayProfile.isPresent()) {
-        sonarWayProfile.get().setComputedDefault(true);
-      } else {
-        builders.iterator().next().setComputedDefault(true);
-      }
-    }
-    MessageDigest md5Digest = DigestUtils.getMd5Digest();
-    return builders.stream()
-      .map(builder -> builder.build(md5Digest))
-      .collect(Collectors.toList(builders.size()));
-  }
-
-  private void registerPerLanguage(DbSession session, List<QualityProfile> qualityProfiles, List<ActiveRuleChange> changes) {
+  private void registerPerLanguage(DbSession session, List<DefinedQProfile> qualityProfiles, List<ActiveRuleChange> changes) {
     qualityProfiles.forEach(qp -> registerPerQualityProfile(session, qp, changes));
     session.commit();
   }
 
-  private void registerPerQualityProfile(DbSession session, QualityProfile qualityProfile, List<ActiveRuleChange> changes) {
+  private void registerPerQualityProfile(DbSession session, DefinedQProfile qualityProfile, List<ActiveRuleChange> changes) {
     LOGGER.info("Register profile {}", qualityProfile.getQProfileName());
 
     List<OrganizationDto> organizationDtos;
@@ -248,12 +89,12 @@ public class RegisterQualityProfiles {
     }
   }
 
-  private List<OrganizationDto> getOrganizationsWithoutQP(DbSession session, QualityProfile qualityProfile) {
+  private List<OrganizationDto> getOrganizationsWithoutQP(DbSession session, DefinedQProfile qualityProfile) {
     return dbClient.organizationDao().selectOrganizationsWithoutLoadedTemplate(session,
       qualityProfile.getLoadedTemplateType(), PROCESSED_ORGANIZATIONS_BATCH_SIZE);
   }
 
-  private void registerPerQualityProfileAndOrganization(DbSession session, QualityProfile qualityProfile, OrganizationDto organization, List<ActiveRuleChange> changes) {
+  private void registerPerQualityProfileAndOrganization(DbSession session, DefinedQProfile qualityProfile, OrganizationDto organization, List<ActiveRuleChange> changes) {
     LOGGER.debug("Register profile {} for organization {}", qualityProfile.getQProfileName(), organization.getKey());
 
     QualityProfileDto profileDto = dbClient.qualityProfileDao().selectByNameAndLanguage(organization, qualityProfile.getName(), qualityProfile.getLanguage(), session);
@@ -276,95 +117,4 @@ public class RegisterQualityProfiles {
     session.commit();
   }
 
-  private static final class QualityProfile {
-    private final QProfileName qProfileName;
-    private final boolean isDefault;
-    private final String loadedTemplateType;
-    private final List<org.sonar.api.rules.ActiveRule> activeRules;
-
-    public QualityProfile(Builder builder, MessageDigest messageDigest) {
-      this.qProfileName = new QProfileName(builder.getLanguage(), builder.getName());
-      this.isDefault = builder.declaredDefault || builder.computedDefault;
-      this.loadedTemplateType = computeLoadedTemplateType(this.qProfileName, messageDigest);
-      this.activeRules = ImmutableList.copyOf(builder.activeRules);
-    }
-
-    private static String computeLoadedTemplateType(QProfileName qProfileName, MessageDigest messageDigest) {
-      String qpIdentifier = lowerCase(qProfileName.getLanguage(), Locale.ENGLISH) + ":" + qProfileName.getName();
-      return format("%s.%s", QUALITY_PROFILE_TYPE, encodeHexString(messageDigest.digest(qpIdentifier.getBytes(UTF_8))));
-    }
-
-    public String getName() {
-      return qProfileName.getName();
-    }
-
-    public String getLanguage() {
-      return qProfileName.getLanguage();
-    }
-
-    public QProfileName getQProfileName() {
-      return qProfileName;
-    }
-
-    public boolean isDefault() {
-      return isDefault;
-    }
-
-    public String getLoadedTemplateType() {
-      return loadedTemplateType;
-    }
-
-    public List<org.sonar.api.rules.ActiveRule> getActiveRules() {
-      return activeRules;
-    }
-
-    private static final class Builder {
-      private String language;
-      private String name;
-      private boolean declaredDefault;
-      private boolean computedDefault;
-      private List<org.sonar.api.rules.ActiveRule> 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<org.sonar.api.rules.ActiveRule> rules) {
-        this.activeRules.addAll(rules);
-        return this;
-      }
-
-      QualityProfile build(MessageDigest messageDigest) {
-        return new QualityProfile(this, messageDigest);
-      }
-    }
-  }
 }
index 9bf636f7572088064c1bb152cde4e346822cc8f2..a37dbb129bfbc58372a9532d6ba7d004249c6bff 100644 (file)
@@ -214,6 +214,7 @@ public class OrganizationCreationImplTest {
   @Test
   public void create_add_current_user_as_member_of_organization() throws OrganizationCreation.KeyConflictException {
     mockForSuccessfulInsert(SOME_UUID, SOME_DATE);
+    definedQProfileRepositoryRule.initialize();
 
     underTest.create(dbSession, SOME_USER_ID, FULL_POPULATED_NEW_ORGANIZATION);
 
@@ -362,6 +363,7 @@ public class OrganizationCreationImplTest {
     when(organizationValidation.generateKeyFrom(A_LOGIN)).thenReturn(SLUG_OF_A_LOGIN);
     mockForSuccessfulInsert(SOME_UUID, SOME_DATE);
     enableCreatePersonalOrg(true);
+    definedQProfileRepositoryRule.initialize();
 
     underTest.createForUser(dbSession, user);
 
diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/DefinedQProfileRepositoryImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/DefinedQProfileRepositoryImplTest.java
new file mode 100644 (file)
index 0000000..a302f6d
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ * 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.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+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.ValidationMessages;
+import org.sonar.server.language.LanguageTesting;
+
+import static java.util.Arrays.asList;
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class DefinedQProfileRepositoryImplTest {
+  private static final Language FOO_LANGUAGE = LanguageTesting.newLanguage("foo", "foo", "foo");
+  private static final String SONAR_WAY_QP_NAME = "Sonar way";
+
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+
+  @Test
+  public void getQProfilesByLanguage_throws_ISE_if_called_before_initialize() {
+    DefinedQProfileRepositoryImpl underTest = new DefinedQProfileRepositoryImpl(new Languages());
+
+    expectedException.expect(IllegalStateException.class);
+    expectedException.expectMessage("initialize must be called first");
+
+    underTest.getQProfilesByLanguage();
+  }
+
+  @Test
+  public void initialize_throws_ISE_if_called_twice() {
+    DefinedQProfileRepositoryImpl underTest = new DefinedQProfileRepositoryImpl(new Languages());
+    underTest.initialize();
+
+    expectedException.expect(IllegalStateException.class);
+    expectedException.expectMessage("initialize must be called only once");
+
+    underTest.initialize();
+  }
+
+  @Test
+  public void initialize_creates_no_DefinedQProfile_when_there_is_no_definition() {
+    DefinedQProfileRepository underTest = new DefinedQProfileRepositoryImpl(new Languages(FOO_LANGUAGE));
+
+    underTest.initialize();
+
+    assertThat(underTest.getQProfilesByLanguage()).isEmpty();
+  }
+
+  @Test
+  public void initialize_creates_no_DefinedQProfile_when_all_definitions_apply_to_non_defined_languages() {
+    DefinedQProfileRepository underTest = new DefinedQProfileRepositoryImpl(new Languages(), new DummyProfileDefinition("foo", "P1", false));
+
+    underTest.initialize();
+
+    assertThat(underTest.getQProfilesByLanguage()).isEmpty();
+  }
+
+  @Test
+  public void initialize_throws_IAE_if_profileDefinition_creates_RulesProfile_with_null_name() {
+    DummyProfileDefinition definition = new DummyProfileDefinition("foo", null, false);
+    DefinedQProfileRepository underTest = new DefinedQProfileRepositoryImpl(new Languages(), definition);
+
+    expectedException.expect(IllegalArgumentException.class);
+    expectedException.expectMessage("Profile created by Definition " + definition + " can't have a blank name");
+
+    underTest.initialize();
+  }
+
+  @Test
+  public void initialize_throws_IAE_if_profileDefinition_creates_RulesProfile_with_empty_name() {
+    DummyProfileDefinition definition = new DummyProfileDefinition("foo", "", false);
+    DefinedQProfileRepository underTest = new DefinedQProfileRepositoryImpl(new Languages(), definition);
+
+    expectedException.expect(IllegalArgumentException.class);
+    expectedException.expectMessage("Profile created by Definition " + definition + " can't have a blank name");
+
+    underTest.initialize();
+  }
+
+  @Test
+  public void initialize_makes_single_qp_of_a_language_default_even_if_not_flagged_as_so() {
+    DefinedQProfileRepository underTest = new DefinedQProfileRepositoryImpl(new Languages(FOO_LANGUAGE), new DummyProfileDefinition("foo", "foo1", false));
+
+    underTest.initialize();
+
+    Map<String, List<DefinedQProfile>> qProfilesByLanguage = underTest.getQProfilesByLanguage();
+    assertThat(qProfilesByLanguage)
+      .hasSize(1)
+      .containsOnlyKeys(FOO_LANGUAGE.getKey());
+    assertThat(qProfilesByLanguage.get(FOO_LANGUAGE.getKey()))
+      .extracting(DefinedQProfile::isDefault)
+      .containsExactly(true);
+  }
+
+  @Test
+  public void initialize_makes_single_qp_of_a_language_default_even_if_flagged_as_so() {
+    DefinedQProfileRepository underTest = new DefinedQProfileRepositoryImpl(new Languages(FOO_LANGUAGE), new DummyProfileDefinition("foo", "foo1", true));
+
+    underTest.initialize();
+
+    Map<String, List<DefinedQProfile>> qProfilesByLanguage = underTest.getQProfilesByLanguage();
+    assertThat(qProfilesByLanguage)
+      .hasSize(1)
+      .containsOnlyKeys(FOO_LANGUAGE.getKey());
+    assertThat(qProfilesByLanguage.get(FOO_LANGUAGE.getKey()))
+      .extracting(DefinedQProfile::isDefault)
+      .containsExactly(true);
+  }
+
+  @Test
+  public void initialize_makes_first_qp_of_a_language_default_when_none_flagged_as_so() {
+    List<DummyProfileDefinition> definitions = new ArrayList<>(
+      asList(new DummyProfileDefinition("foo", "foo1", false), new DummyProfileDefinition("foo", "foo2", false)));
+    Collections.shuffle(definitions);
+    String firstQPName = definitions.get(0).getName();
+    String secondQPName = definitions.get(1).getName();
+    DefinedQProfileRepository underTest = new DefinedQProfileRepositoryImpl(new Languages(FOO_LANGUAGE), definitions.stream().toArray(ProfileDefinition[]::new));
+
+    underTest.initialize();
+
+    Map<String, List<DefinedQProfile>> qProfilesByLanguage = underTest.getQProfilesByLanguage();
+    assertThat(qProfilesByLanguage)
+      .hasSize(1)
+      .containsOnlyKeys(FOO_LANGUAGE.getKey());
+    List<DefinedQProfile> fooDefinedQProfiles = qProfilesByLanguage.get(FOO_LANGUAGE.getKey());
+    assertThat(fooDefinedQProfiles)
+      .extracting(DefinedQProfile::getName)
+      .containsExactly(firstQPName, secondQPName);
+    assertThat(fooDefinedQProfiles)
+      .extracting(DefinedQProfile::isDefault)
+      .containsExactly(true, false);
+  }
+
+  @Test
+  public void initialize_fails_with_ISE_when_two_sq_with_different_name_are_default_for_the_same_language() {
+    DefinedQProfileRepository underTest = new DefinedQProfileRepositoryImpl(new Languages(FOO_LANGUAGE),
+      new DummyProfileDefinition("foo", "foo1", true), new DummyProfileDefinition("foo", "foo2", true));
+
+    expectedException.expect(IllegalStateException.class);
+    expectedException.expectMessage("Several Quality profiles are flagged as default for the language foo: [foo1, foo2]");
+
+    underTest.initialize();
+  }
+
+  @Test
+  public void initialize_create_qp_as_default_even_if_only_one_profile_with_given_name_has_default_flag_true() {
+    String name = "doh";
+    boolean flag = new Random().nextBoolean();
+    DefinedQProfileRepository underTest = new DefinedQProfileRepositoryImpl(new Languages(FOO_LANGUAGE),
+      new DummyProfileDefinition("foo", name, flag), new DummyProfileDefinition("foo", name, !flag));
+
+    underTest.initialize();
+
+    assertThat(underTest.getQProfilesByLanguage().get(FOO_LANGUAGE.getKey()))
+      .extracting(DefinedQProfile::isDefault)
+      .containsExactly(true);
+  }
+
+  @Test
+  public void initialize_creates_single_qp_if_several_profile_have_the_same_name_for_a_given_language() {
+    DefinedQProfileRepository underTest = new DefinedQProfileRepositoryImpl(new Languages(FOO_LANGUAGE),
+      new DummyProfileDefinition("foo", "foo1", true), new DummyProfileDefinition("foo", "foo1", true));
+
+    underTest.initialize();
+
+    Map<String, List<DefinedQProfile>> qProfilesByLanguage = underTest.getQProfilesByLanguage();
+    assertThat(qProfilesByLanguage)
+      .hasSize(1)
+      .containsOnlyKeys(FOO_LANGUAGE.getKey());
+    assertThat(qProfilesByLanguage.get(FOO_LANGUAGE.getKey()))
+      .extracting(DefinedQProfile::getName)
+      .containsExactly("foo1");
+  }
+
+  @Test
+  public void initialize_creates_qp_Sonar_Way_as_default_if_none_other_is_defined_default_for_a_given_language() {
+    DefinedQProfileRepository underTest = new DefinedQProfileRepositoryImpl(
+      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));
+
+    underTest.initialize();
+
+    Map<String, List<DefinedQProfile>> qProfilesByLanguage = underTest.getQProfilesByLanguage();
+    assertThat(qProfilesByLanguage)
+      .hasSize(1)
+      .containsOnlyKeys(FOO_LANGUAGE.getKey());
+    List<DefinedQProfile> fooDefinedQProfiles = qProfilesByLanguage.get(FOO_LANGUAGE.getKey());
+    assertThat(fooDefinedQProfiles)
+      .extracting(DefinedQProfile::getName)
+      .containsExactly("doh", "boo", SONAR_WAY_QP_NAME, "goo");
+    assertThat(fooDefinedQProfiles)
+      .extracting(DefinedQProfile::isDefault)
+      .containsExactly(false, false, true, false);
+  }
+
+  @Test
+  public void initialize_does_not_create_Sonar_Way_as_default_if_other_profile_is_defined_as_default() {
+    DefinedQProfileRepository underTest = new DefinedQProfileRepositoryImpl(
+      new Languages(FOO_LANGUAGE),
+      new DummyProfileDefinition("foo", SONAR_WAY_QP_NAME, false), new DummyProfileDefinition("foo", "goo", true));
+
+    underTest.initialize();
+
+    List<DefinedQProfile> fooDefinedQProfiles = underTest.getQProfilesByLanguage().get(FOO_LANGUAGE.getKey());
+    assertThat(fooDefinedQProfiles)
+      .extracting(DefinedQProfile::getName)
+      .containsExactly(SONAR_WAY_QP_NAME, "goo");
+    assertThat(fooDefinedQProfiles)
+      .extracting(DefinedQProfile::isDefault)
+      .containsExactly(false, true);
+  }
+
+  @Test
+  public void initialize_matches_Sonar_Way_default_with_case_sensitivity() {
+    String sonarWayInOtherCase = SONAR_WAY_QP_NAME.toUpperCase();
+    DefinedQProfileRepository underTest = new DefinedQProfileRepositoryImpl(
+      new Languages(FOO_LANGUAGE),
+      new DummyProfileDefinition("foo", "goo", false), new DummyProfileDefinition("foo", sonarWayInOtherCase, false));
+
+    underTest.initialize();
+
+    List<DefinedQProfile> fooDefinedQProfiles = underTest.getQProfilesByLanguage().get(FOO_LANGUAGE.getKey());
+    assertThat(fooDefinedQProfiles)
+      .extracting(DefinedQProfile::getName)
+      .containsExactly("goo", sonarWayInOtherCase);
+    assertThat(fooDefinedQProfiles)
+      .extracting(DefinedQProfile::isDefault)
+      .containsExactly(true, false);
+  }
+
+  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) {
+      RulesProfile res = RulesProfile.create(name, language);
+      res.setDefaultProfile(defaultProfile);
+      return res;
+    }
+
+    String getLanguage() {
+      return language;
+    }
+
+    String getName() {
+      return name;
+    }
+
+    boolean isDefaultProfile() {
+      return defaultProfile;
+    }
+  }
+
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/DefinedQProfileRepositoryRule.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/DefinedQProfileRepositoryRule.java
new file mode 100644 (file)
index 0000000..b6745a0
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * 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 com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Stream;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.junit.rules.ExternalResource;
+import org.sonar.api.resources.Language;
+import org.sonar.core.util.stream.Collectors;
+
+import static com.google.common.base.Preconditions.checkState;
+import static org.sonar.core.util.stream.Collectors.toList;
+
+public class DefinedQProfileRepositoryRule extends ExternalResource implements DefinedQProfileRepository {
+  private boolean initializeCalled = false;
+  private Map<String, List<DefinedQProfile>> qProfilesbyLanguage = new HashMap<>();
+
+  @Override
+  protected void before() throws Throwable {
+    this.initializeCalled = false;
+    this.qProfilesbyLanguage.clear();
+  }
+
+  @Override
+  public void initialize() {
+    checkState(!initializeCalled, "initialize must be called only once");
+    this.initializeCalled = true;
+  }
+
+  @Override
+  public Map<String, List<DefinedQProfile>> getQProfilesByLanguage() {
+    checkState(initializeCalled, "initialize must be called first");
+
+    return ImmutableMap.copyOf(qProfilesbyLanguage);
+  }
+
+  public boolean isInitialized() {
+    return initializeCalled;
+  }
+
+  public DefinedQProfileRepositoryRule set(String languageKey, DefinedQProfile first, DefinedQProfile... others) {
+    qProfilesbyLanguage.put(
+      languageKey,
+      Stream.concat(Stream.of(first), Arrays.stream(others)).collect(toList(1 + others.length)));
+    return this;
+  }
+
+  public DefinedQProfile add(Language language, String profileName) {
+    return add(language, profileName, false);
+  }
+
+  public DefinedQProfile add(Language language, String profileName, boolean isDefault) {
+    DefinedQProfile definedQProfile = create(language, profileName, isDefault);
+    qProfilesbyLanguage.compute(language.getKey(),
+      (key, existing) -> {
+        if (existing == null) {
+          return ImmutableList.of(definedQProfile);
+        }
+        return Stream.concat(existing.stream(), Stream.of(definedQProfile)).collect(Collectors.toList(existing.size() + 1));
+      });
+    return definedQProfile;
+  }
+
+  private DefinedQProfile create(Language language, String profileName, boolean isDefault) {
+    return new DefinedQProfile.Builder()
+      .setLanguage(language.getKey())
+      .setName(profileName)
+      .setDeclaredDefault(isDefault)
+      .build(DigestUtils.getMd5Digest());
+  }
+}
index 1ac983d31e5439c2f335490308bc2d65fa089a36..d3a7b06208de8aaa10ae08268bd4e265f0504322 100644 (file)
@@ -91,7 +91,7 @@ public class QProfileResetMediumTest {
     }
     RULE_DEFS.set(rules);
     PROFILE_DEFS.set(profile);
-    tester.get(Platform.class).executeStartupTasks();
+    tester.get(Platform.class).restart();
 
     db = tester.get(DbClient.class);
     dbSession = tester.get(DbClient.class).openSession(false);
index 37e98962f39e89b0381b57434116ed5d936da665..e7f84617fb723b7b8c57d441e07397fd1560f025 100644 (file)
@@ -76,6 +76,5 @@ public class QualityProfileTest {
   @Test
   public void verify_toString() {
     assertThat(QUALITY_PROFILE.toString()).isEqualTo("QualityProfile{key=qpKey, name=qpName, language=languageKey, rulesUpdatedAt=1274194245000}");
-
   }
 }
index 6c61a05c8a7f7280ca1567e15183ab8cf7bd94c7..d25d5f8f88c249147ddf70b14defe6cde1ecc845 100644 (file)
  */
 package org.sonar.server.qualityprofile;
 
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Date;
-import java.util.List;
-import org.apache.commons.codec.digest.DigestUtils;
 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.core.util.UuidFactory;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbTester;
@@ -44,13 +37,10 @@ import org.sonar.server.language.LanguageTesting;
 import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
 import org.sonar.server.tester.UserSessionRule;
 
-import static java.lang.String.format;
-import static java.nio.charset.StandardCharsets.UTF_8;
-import static java.util.Arrays.asList;
-import static org.apache.commons.lang.StringUtils.lowerCase;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 import static org.sonar.core.util.UtcDateUtils.formatDateTime;
 
@@ -58,8 +48,6 @@ public class RegisterQualityProfilesTest {
   private static final Language FOO_LANGUAGE = LanguageTesting.newLanguage("foo", "foo", "foo");
   private static final Language BAR_LANGUAGE = LanguageTesting.newLanguage("bar", "bar", "bar");
   private static final String TABLE_RULES_PROFILES = "RULES_PROFILES";
-  private static final String TYPE_QUALITY_PROFILE = "QUALITY_PROFILE";
-  private static final String SONAR_WAY_QP_NAME = "Sonar way";
   private static final String TABLE_LOADED_TEMPLATES = "loaded_templates";
 
   @Rule
@@ -68,65 +56,45 @@ public class RegisterQualityProfilesTest {
   public UserSessionRule userSessionRule = UserSessionRule.standalone();
   @Rule
   public ExpectedException expectedException = ExpectedException.none();
+  @Rule
+  public DefinedQProfileRepositoryRule definedQProfileRepositoryRule = new DefinedQProfileRepositoryRule();
 
   private DbClient dbClient = dbTester.getDbClient();
   private DbClient mockedDbClient = mock(DbClient.class);
   private UuidFactory mockedUuidFactory = mock(UuidFactory.class);
   private System2 mockedSystem2 = mock(System2.class);
   private ActiveRuleIndexer mockedActiveRuleIndexer = mock(ActiveRuleIndexer.class);
+  private RegisterQualityProfiles underTest = new RegisterQualityProfiles(
+    definedQProfileRepositoryRule,
+    dbClient,
+    new QProfileFactory(dbClient, mockedUuidFactory, mockedSystem2),
+    new CachingRuleActivator(mockedSystem2, dbClient, null, new CachingRuleActivatorContextFactory(dbClient), null, null, userSessionRule),
+    mockedActiveRuleIndexer);
 
   @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());
+  public void no_action_in_DB_nothing_to_index_when_there_is_no_DefinedQProfile() {
+    RegisterQualityProfiles underTest = new RegisterQualityProfiles(definedQProfileRepositoryRule, mockedDbClient, null, null, mockedActiveRuleIndexer);
 
     underTest.start();
 
-    verifyZeroInteractions(mockedDbClient, mockedActiveRuleIndexer);
+    assertThat(definedQProfileRepositoryRule.isInitialized()).isTrue();
+    verify(mockedDbClient).openSession(false);
+    verify(mockedActiveRuleIndexer).index(Collections.emptyList());
+    verifyNoMoreInteractions(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();
-  }
-
-  @Test
-  public void start_creates_qp_if_language_exists_and_store_flag_in_loaded_templates_for_each_organization_id_BD() {
+  public void start_creates_qp_and_store_flag_in_loaded_templates_for_each_organization_id_BD() {
     OrganizationDto otherOrganization = dbTester.organizations().insert();
     String[] uuids = {"uuid 1", "uuid 2"};
     Long[] dates = {2_456_789L, 6_123_789L};
     String[] formattedDates = {formatDateTime(new Date(dates[0])), formatDateTime(new Date(dates[1]))};
-    DummyProfileDefinition qpDefinition = new DummyProfileDefinition("foo", "foo1", false);
-    RegisterQualityProfiles underTest = mockedEs(Collections.singletonList(qpDefinition), new Languages(FOO_LANGUAGE));
+    DefinedQProfile definedQProfile = definedQProfileRepositoryRule.add(FOO_LANGUAGE, "foo1");
     mockForQPInserts(uuids, dates);
 
     underTest.start();
 
+    assertThat(definedQProfileRepositoryRule.isInitialized()).isTrue();
     Arrays.asList(dbTester.getDefaultOrganization(), otherOrganization)
       .forEach(organization -> {
         QualityProfileDto dto = getPersistedQP(organization, FOO_LANGUAGE, "foo1");
@@ -140,111 +108,65 @@ public class RegisterQualityProfilesTest {
         assertThat(dto.getRulesUpdatedAt()).isIn(formattedDates);
         assertThat(dto.getLastUsed()).isNull();
         assertThat(dto.getUserUpdatedAt()).isNull();
-        assertThat(dto.isDefault()).isTrue();
+        assertThat(dto.isDefault()).isFalse();
 
-        assertThat(dbClient.loadedTemplateDao().countByTypeAndKey(computeLoadedTemplateType(qpDefinition), organization.getUuid(), dbTester.getSession()))
+        assertThat(dbClient.loadedTemplateDao().countByTypeAndKey(definedQProfile.getLoadedTemplateType(), organization.getUuid(), dbTester.getSession()))
           .isEqualTo(1);
       });
     assertThat(dbTester.countRowsOfTable(dbTester.getSession(), TABLE_RULES_PROFILES)).isEqualTo(2);
   }
 
   @Test
-  public void start_makes_single_qp_of_a_language_default_even_if_not_flagged_as_so() {
-    RegisterQualityProfiles underTest = mockedEs(Collections.singletonList(new DummyProfileDefinition("foo", "foo1", false)), new Languages(FOO_LANGUAGE));
-    mockForSingleQPInsert();
+  public void start_persists_default_flag_of_DefinedQualityProfile() {
+    definedQProfileRepositoryRule.add(FOO_LANGUAGE, "foo1", false);
+    definedQProfileRepositoryRule.add(FOO_LANGUAGE, "foo2", true);
+    definedQProfileRepositoryRule.add(BAR_LANGUAGE, "bar1", true);
+    definedQProfileRepositoryRule.add(BAR_LANGUAGE, "bar2", false);
+    mockForQPInserts(new String[]{"uuid1", "uuid2", "uuid3", "uuid4"}, new Long[]{ 1L, 2L, 3L, 4L});
 
     underTest.start();
 
-    assertThat(getPersistedQP(dbTester.getDefaultOrganization(), FOO_LANGUAGE, "foo1").isDefault()).isTrue();
-  }
-
-  @Test
-  public void start_makes_single_qp_of_a_language_default_even_if_flagged_as_so() {
-    RegisterQualityProfiles underTest = mockedEs(Collections.singletonList(new DummyProfileDefinition("foo", "foo1", true)), new Languages(FOO_LANGUAGE));
-    mockForSingleQPInsert();
-
-    underTest.start();
-
-    assertThat(getPersistedQP(dbTester.getDefaultOrganization(), FOO_LANGUAGE, "foo1").isDefault()).isTrue();
-  }
-
-  @Test
-  public void start_makes_first_qp_of_a_language_default_when_none_flagged_as_so() {
-    List<ProfileDefinition> definitions = new ArrayList<>(asList(new DummyProfileDefinition("foo", "foo1", false), new DummyProfileDefinition("foo", "foo2", false)));
-    Collections.shuffle(definitions);
-    String firstQPName = ((DummyProfileDefinition) definitions.iterator().next()).getName();
-    RegisterQualityProfiles underTest = mockedEs(definitions, new Languages(FOO_LANGUAGE));
-    mockForTwoQPInserts();
-
-    underTest.start();
-
-    QualityProfileDto dto = getPersistedQP(dbTester.getDefaultOrganization(), FOO_LANGUAGE, "foo1");
-    assertThat(dto.isDefault()).isEqualTo(dto.getName().equals(firstQPName));
-    dto = getPersistedQP(dbTester.getDefaultOrganization(), FOO_LANGUAGE, "foo2");
-    assertThat(dto.isDefault()).isEqualTo(dto.getName().equals(firstQPName));
-    assertThat(dbTester.countRowsOfTable(dbTester.getSession(), TABLE_RULES_PROFILES)).isEqualTo(2);
+    assertThat(definedQProfileRepositoryRule.isInitialized()).isTrue();
+    assertThat(getPersistedQP(dbTester.getDefaultOrganization(), FOO_LANGUAGE, "foo1").isDefault()).isFalse();
+    assertThat(getPersistedQP(dbTester.getDefaultOrganization(), FOO_LANGUAGE, "foo2").isDefault()).isTrue();
+    assertThat(getPersistedQP(dbTester.getDefaultOrganization(), BAR_LANGUAGE, "bar1").isDefault()).isTrue();
+    assertThat(getPersistedQP(dbTester.getDefaultOrganization(), BAR_LANGUAGE, "bar2").isDefault()).isFalse();
   }
 
   @Test
   public void start_does_not_create_sq_if_loaded_profile_of_organization_already_exists() {
     OrganizationDto org1 = dbTester.organizations().insert();
     OrganizationDto org2 = dbTester.organizations().insert();
-    DummyProfileDefinition qpDefinition = new DummyProfileDefinition("foo", "foo1", false);
-    dbClient.loadedTemplateDao().insert(new LoadedTemplateDto(dbTester.getDefaultOrganization().getUuid(), computeLoadedTemplateType(qpDefinition)), dbTester.getSession());
-    dbClient.loadedTemplateDao().insert(new LoadedTemplateDto(org1.getUuid(), computeLoadedTemplateType(qpDefinition)), dbTester.getSession());
+    DefinedQProfile definedQProfile = definedQProfileRepositoryRule.add(FOO_LANGUAGE, "foo1");
+    dbClient.loadedTemplateDao().insert(new LoadedTemplateDto(dbTester.getDefaultOrganization().getUuid(), definedQProfile.getLoadedTemplateType()), dbTester.getSession());
+    dbClient.loadedTemplateDao().insert(new LoadedTemplateDto(org1.getUuid(), definedQProfile.getLoadedTemplateType()), dbTester.getSession());
     dbTester.commit();
-    RegisterQualityProfiles underTest = mockedEs(Collections.singletonList(qpDefinition), new Languages(FOO_LANGUAGE));
     mockForSingleQPInsert();
 
     underTest.start();
 
-    assertThat(dbClient.loadedTemplateDao().countByTypeAndKey(computeLoadedTemplateType(qpDefinition), org2.getUuid(), dbTester.getSession()))
+    assertThat(definedQProfileRepositoryRule.isInitialized()).isTrue();
+    assertThat(dbClient.loadedTemplateDao().countByTypeAndKey(definedQProfile.getLoadedTemplateType(), org2.getUuid(), dbTester.getSession()))
       .isEqualTo(1);
     assertThat(dbTester.countRowsOfTable(dbTester.getSession(), TABLE_LOADED_TEMPLATES)).isEqualTo(3);
     assertThat(dbTester.countRowsOfTable(dbTester.getSession(), TABLE_RULES_PROFILES)).isEqualTo(1);
   }
 
   @Test
-  public void start_fails_with_ISE_when_two_sq_with_different_name_are_default_for_the_same_language() {
-    RegisterQualityProfiles underTest = mockedEs(
-      asList(new DummyProfileDefinition("foo", "foo1", true), new DummyProfileDefinition("foo", "foo2", true)),
-      new Languages(FOO_LANGUAGE));
-
-    expectedException.expect(IllegalStateException.class);
-    expectedException.expectMessage("Several Quality profiles are flagged as default for the language foo: [foo1, foo2]");
-
-    underTest.start();
-  }
-
-  @Test
-  public void starts_creates_single_qp_if_several_profile_have_the_same_name_for_a_given_language() {
-    RegisterQualityProfiles underTest = mockedEs(
-      asList(new DummyProfileDefinition("foo", "foo1", true), new DummyProfileDefinition("foo", "foo1", true)),
-      new Languages(FOO_LANGUAGE));
-    mockForSingleQPInsert();
-
-    underTest.start();
-
-    assertThat(getPersistedQP(dbTester.getDefaultOrganization(), FOO_LANGUAGE, "foo1").isDefault()).isTrue();
-    assertThat(dbTester.countRowsOfTable(dbTester.getSession(), TABLE_RULES_PROFILES)).isEqualTo(1);
-  }
-
-  @Test
-  public void start_creates_different_qp_and_their_loaded_templates_if_several_profile_has_same_name_for_different_languages() {
+  public void start_creates_different_qps_and_their_loaded_templates_if_several_profile_has_same_name_for_different_languages() {
     String uuid1 = "uuid1";
     String uuid2 = "uuid2";
     long date1 = 2_456_789L;
     long date2 = 4_231_654L;
     String name = "doh";
 
-    DummyProfileDefinition qpDefinition1 = new DummyProfileDefinition("foo", name, true);
-    DummyProfileDefinition qpDefinition2 = new DummyProfileDefinition("bar", name, true);
-    RegisterQualityProfiles underTest = mockedEs(asList(qpDefinition1, qpDefinition2), new Languages(FOO_LANGUAGE, BAR_LANGUAGE));
-    when(mockedUuidFactory.create()).thenReturn(uuid1).thenReturn(uuid2).thenThrow(new UnsupportedOperationException("uuidFactory should be called only twice"));
-    when(mockedSystem2.now()).thenReturn(date1).thenReturn(date2).thenThrow(new UnsupportedOperationException("now should be called only twice"));
+    DefinedQProfile definedQProfile1 = definedQProfileRepositoryRule.add(FOO_LANGUAGE, name, true);
+    DefinedQProfile definedQProfile2 = definedQProfileRepositoryRule.add(BAR_LANGUAGE, name, true);
+    mockForQPInserts(new String[]{uuid1, uuid2}, new Long[]{date1, date2});
 
     underTest.start();
 
+    assertThat(definedQProfileRepositoryRule.isInitialized()).isTrue();
     OrganizationDto organization = dbTester.getDefaultOrganization();
     QualityProfileDto dto = getPersistedQP(organization, FOO_LANGUAGE, name);
     String uuidQP1 = dto.getKee();
@@ -273,81 +195,16 @@ public class RegisterQualityProfilesTest {
     assertThat(dto.isDefault()).isTrue();
     assertThat(dbTester.countRowsOfTable(dbTester.getSession(), TABLE_RULES_PROFILES)).isEqualTo(2);
 
-    assertThat(dbClient.loadedTemplateDao().countByTypeAndKey(computeLoadedTemplateType(qpDefinition1), organization.getUuid(), dbTester.getSession()))
+    assertThat(dbClient.loadedTemplateDao().countByTypeAndKey(definedQProfile1.getLoadedTemplateType(), organization.getUuid(), dbTester.getSession()))
       .isEqualTo(1);
-    assertThat(dbClient.loadedTemplateDao().countByTypeAndKey(computeLoadedTemplateType(qpDefinition2), organization.getUuid(), dbTester.getSession()))
+    assertThat(dbClient.loadedTemplateDao().countByTypeAndKey(definedQProfile2.getLoadedTemplateType(), organization.getUuid(), dbTester.getSession()))
       .isEqualTo(1);
   }
 
-  @Test
-  public void start_create_qp_as_default_even_if_only_one_profile_with_given_name_has_default_flag_true() {
-    String name = "doh";
-    RegisterQualityProfiles underTest = mockedEs(
-      asList(new DummyProfileDefinition("foo", name, false), new DummyProfileDefinition("foo", name, true)),
-      new Languages(FOO_LANGUAGE));
-    mockForSingleQPInsert();
-
-    underTest.start();
-
-    assertThat(getPersistedQP(dbTester.getDefaultOrganization(), FOO_LANGUAGE, name).isDefault()).isTrue();
-  }
-
-  @Test
-  public void start_creates_qp_Sonar_Way_as_default_if_none_other_is_defined_default_for_a_given_language() {
-
-    RegisterQualityProfiles underTest = mockedEs(
-      asList(
-        new DummyProfileDefinition("foo", "doh", false), new DummyProfileDefinition("foo", "boo", false),
-        new DummyProfileDefinition("foo", SONAR_WAY_QP_NAME, false), new DummyProfileDefinition("foo", "goo", false)),
-      new Languages(FOO_LANGUAGE));
-    mockForQPInserts(new String[] {"uuid1", "uuid2", "uuid3", "uuid4"}, new Long[] {2_456_789L, 2_456_789L, 2_456_789L, 2_456_789L});
-
-    underTest.start();
-
-    Arrays.asList("doh", "boo", "goo")
-      .forEach(name -> assertThat(getPersistedQP(dbTester.getDefaultOrganization(), FOO_LANGUAGE, name).isDefault())
-        .describedAs("QP with name " + name + " should not be default")
-        .isFalse());
-    assertThat(getPersistedQP(dbTester.getDefaultOrganization(), FOO_LANGUAGE, SONAR_WAY_QP_NAME).isDefault()).isTrue();
-  }
-
-  @Test
-  public void start_does_not_create_Sonar_Way_as_default_if_other_profile_is_defined_as_default() {
-    RegisterQualityProfiles underTest = mockedEs(
-      asList(
-        new DummyProfileDefinition("foo", SONAR_WAY_QP_NAME, false), new DummyProfileDefinition("foo", "goo", true)),
-      new Languages(FOO_LANGUAGE));
-    mockForTwoQPInserts();
-
-    underTest.start();
-
-    assertThat(getPersistedQP(dbTester.getDefaultOrganization(), FOO_LANGUAGE, SONAR_WAY_QP_NAME).isDefault()).isFalse();
-    assertThat(getPersistedQP(dbTester.getDefaultOrganization(), FOO_LANGUAGE, "goo").isDefault()).isTrue();
-  }
-
-  @Test
-  public void start_matches_Sonar_Way_default_with_case_sensitivity() {
-    String sonarWayInOtherCase = SONAR_WAY_QP_NAME.toUpperCase();
-    RegisterQualityProfiles underTest = mockedEs(
-      asList(
-        new DummyProfileDefinition("foo", "goo", false), new DummyProfileDefinition("foo", sonarWayInOtherCase, false)),
-      new Languages(FOO_LANGUAGE));
-    mockForTwoQPInserts();
-
-    underTest.start();
-
-    assertThat(getPersistedQP(dbTester.getDefaultOrganization(), FOO_LANGUAGE, sonarWayInOtherCase).isDefault()).isFalse();
-    assertThat(getPersistedQP(dbTester.getDefaultOrganization(), FOO_LANGUAGE, "goo").isDefault()).isTrue();
-  }
-
   private void mockForSingleQPInsert() {
     mockForSingleQPInsert("generated uuid", 2_456_789);
   }
 
-  private void mockForTwoQPInserts() {
-    mockForQPInserts(new String[] {"uuid1", "uuid2"}, new Long[] {2_456_789L, 3_789_159L});
-  }
-
   private void mockForSingleQPInsert(String uuid, long now) {
     when(mockedUuidFactory.create()).thenReturn(uuid).thenThrow(new UnsupportedOperationException("uuidFactory should be called only once"));
     when(mockedSystem2.now()).thenReturn(now).thenThrow(new UnsupportedOperationException("now should be called only once"));
@@ -367,53 +224,4 @@ public class RegisterQualityProfilesTest {
     return dbClient.qualityProfileDao().selectByNameAndLanguage(organization, name, language.getKey(), dbTester.getSession());
   }
 
-  private RegisterQualityProfiles mockedDBAndEs(List<ProfileDefinition> definitions, Languages languages) {
-    return new RegisterQualityProfiles(mockedDbClient, null, null, definitions, languages, mockedActiveRuleIndexer);
-  }
-
-  private RegisterQualityProfiles mockedEs(List<ProfileDefinition> definitions, Languages languages) {
-    return new RegisterQualityProfiles(
-      dbClient,
-      new QProfileFactory(dbClient, mockedUuidFactory, mockedSystem2),
-      new CachingRuleActivator(mockedSystem2, dbClient, null, new CachingRuleActivatorContextFactory(dbClient), null, null, userSessionRule),
-      definitions,
-      languages,
-      mockedActiveRuleIndexer);
-  }
-
-  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) {
-      RulesProfile res = RulesProfile.create(name, language);
-      res.setDefaultProfile(defaultProfile);
-      return res;
-    }
-
-    String getLanguage() {
-      return language;
-    }
-
-    String getName() {
-      return name;
-    }
-
-    boolean isDefaultProfile() {
-      return defaultProfile;
-    }
-  }
-
-  private String computeLoadedTemplateType(DummyProfileDefinition qpDefinition) {
-    String qpIdentifier = lowerCase(qpDefinition.getLanguage()) + ":" + qpDefinition.getName();
-    return format("%s.%s", TYPE_QUALITY_PROFILE, DigestUtils.md5Hex(qpIdentifier.getBytes(UTF_8)));
-  }
 }
index 527c989fc4e74d871d6acb78ad5c7079d24e4e6e..acfb40a545b5390d1a6cc38b8185069c772945a8 100644 (file)
@@ -101,7 +101,7 @@ public class RegisterRulesMediumTest {
       dbSession.close();
     }
     RULE_DEFS.set(rules);
-    TESTER.get(Platform.class).executeStartupTasks();
+    TESTER.get(Platform.class).restart();
     db = TESTER.get(DbClient.class);
     dbSession = TESTER.get(DbClient.class).openSession(false);
     dbSession.clearCache();