]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-4764 Create a DefaultProfilesCache component to store default profile names...
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Tue, 29 Apr 2014 14:18:07 +0000 (16:18 +0200)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Tue, 29 Apr 2014 14:32:04 +0000 (16:32 +0200)
sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java
sonar-server/src/main/java/org/sonar/server/qualityprofile/DefaultProfilesCache.java [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileActiveRuleOperations.java
sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileBackup.java
sonar-server/src/main/java/org/sonar/server/startup/RegisterQualityProfiles.java
sonar-server/src/test/java/org/sonar/server/qualityprofile/DefaultProfilesCacheTest.java [new file with mode: 0644]
sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileActiveRuleOperationsTest.java
sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileBackupTest.java
sonar-server/src/test/java/org/sonar/server/startup/RegisterQualityProfilesTest.java

index 472498ba7fb6ffaf638510ba1e146758b828d295..0c437cf82ce36371247caf34694a078189f01e42 100644 (file)
@@ -259,6 +259,7 @@ class ServerComponents {
     pico.addSingleton(QProfileProjectLookup.class);
     pico.addSingleton(QProfileBackup.class);
     pico.addSingleton(QProfileRepositoryExporter.class);
+    pico.addSingleton(DefaultProfilesCache.class);
     pico.addSingleton(ESActiveRule.class);
     pico.addSingleton(QProfileBackupWsHandler.class);
     pico.addSingleton(QProfilesWs.class);
diff --git a/sonar-server/src/main/java/org/sonar/server/qualityprofile/DefaultProfilesCache.java b/sonar-server/src/main/java/org/sonar/server/qualityprofile/DefaultProfilesCache.java
new file mode 100644 (file)
index 0000000..992403e
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.Multimap;
+import org.sonar.api.ServerComponent;
+
+import java.util.Collection;
+
+/**
+ * Used to list default profile names.
+ *
+ * It should be removed as soon as a new API to define quality profiles is created.
+ * As {@link org.sonar.api.profiles.ProfileDefinition} is using {@link sun.reflect.annotation.AnnotationParser}, a lot of time is taken to load all profile definitions as
+ * it load all rules from db, so we've created this class to prevent taking too much time to load default profile names.
+ */
+public class DefaultProfilesCache implements ServerComponent {
+
+  // default profile names by language
+  private final Multimap<String, String> defaultProfilesCache;
+
+  public DefaultProfilesCache() {
+    this.defaultProfilesCache = ArrayListMultimap.create();
+  }
+
+  public Collection<String> byLanguage(String language) {
+    return defaultProfilesCache.get(language);
+  }
+
+  public DefaultProfilesCache put(String language, String name) {
+    defaultProfilesCache.put(language, name);
+    return this;
+  }
+
+}
index 789e01b5f705e5b93c6ef6cf6dedad187d013024..ed25e2d19842fb57fbc1768c1a7d996e46c936ef 100644 (file)
@@ -27,7 +27,6 @@ import org.apache.ibatis.session.SqlSession;
 import org.elasticsearch.common.base.Predicate;
 import org.elasticsearch.common.collect.Iterables;
 import org.sonar.api.ServerComponent;
-import org.sonar.api.rule.RuleKey;
 import org.sonar.api.rule.Severity;
 import org.sonar.api.rules.RulePriority;
 import org.sonar.api.server.rule.RuleParamType;
@@ -109,12 +108,7 @@ public class QProfileActiveRuleOperations implements ServerComponent {
     return activeRule;
   }
 
-  ActiveRuleDto createActiveRule(int profileId, RuleKey ruleKey, String severity, SqlSession session) {
-    RuleDto rule = ruleDao.selectByKey(ruleKey, session);
-    return createActiveRule(profileId, QProfileValidations.checkRuleIsNotNull(rule).getId(), severity, session);
-  }
-
-  private ActiveRuleDto createActiveRule(int profileId, int ruleId, String severity, SqlSession session) {
+  ActiveRuleDto createActiveRule(int profileId, int ruleId, String severity, SqlSession session) {
     ActiveRuleDto activeRule = new ActiveRuleDto()
       .setProfileId(profileId)
       .setRuleId(ruleId)
index a94ffe26729dbbce7c404b4e4b30c468213497cc..624bfbfa349f5c10dafe20e5d227b82afb9d4901 100644 (file)
@@ -36,17 +36,22 @@ import org.sonar.core.permission.GlobalPermissions;
 import org.sonar.core.persistence.MyBatis;
 import org.sonar.core.preview.PreviewCache;
 import org.sonar.core.qualityprofile.db.ActiveRuleDto;
+import org.sonar.core.rule.RuleDao;
+import org.sonar.core.rule.RuleDto;
 import org.sonar.jpa.session.DatabaseSessionFactory;
 import org.sonar.server.exceptions.BadRequestException;
+import org.sonar.server.exceptions.NotFoundException;
 import org.sonar.server.user.UserSession;
 
 import java.io.StringReader;
 import java.io.StringWriter;
 import java.io.Writer;
-import java.util.*;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
 
 import static com.google.common.collect.Lists.newArrayList;
-import static com.google.common.collect.Sets.newHashSet;
 
 /**
  * Used through ruby code <pre>Internal.profile_backup</pre>
@@ -61,20 +66,22 @@ public class QProfileBackup implements ServerComponent {
   private final QProfileLookup qProfileLookup;
   private final QProfileOperations qProfileOperations;
   private final QProfileActiveRuleOperations qProfileActiveRuleOperations;
+  private final RuleDao ruleDao;
   private final ESActiveRule esActiveRule;
   private final List<ProfileDefinition> definitions;
+  private final DefaultProfilesCache defaultProfilesCache;
   private final PreviewCache dryRunCache;
 
   public QProfileBackup(DatabaseSessionFactory sessionFactory, XMLProfileParser xmlProfileParser, XMLProfileSerializer xmlProfileSerializer, MyBatis myBatis,
-                        QProfileLookup qProfileLookup, QProfileOperations qProfileOperations, QProfileActiveRuleOperations qProfileActiveRuleOperations, ESActiveRule esActiveRule,
-                        PreviewCache dryRunCache) {
-    this(sessionFactory, xmlProfileParser, xmlProfileSerializer, myBatis, qProfileLookup, qProfileOperations, qProfileActiveRuleOperations, esActiveRule,
-      Collections.<ProfileDefinition>emptyList(), dryRunCache);
+                        QProfileLookup qProfileLookup, QProfileOperations qProfileOperations, QProfileActiveRuleOperations qProfileActiveRuleOperations, RuleDao ruleDao,
+                        ESActiveRule esActiveRule, DefaultProfilesCache defaultProfilesCache, PreviewCache dryRunCache) {
+    this(sessionFactory, xmlProfileParser, xmlProfileSerializer, myBatis, qProfileLookup, qProfileOperations, qProfileActiveRuleOperations, ruleDao, esActiveRule,
+      Collections.<ProfileDefinition>emptyList(), defaultProfilesCache, dryRunCache);
   }
 
   public QProfileBackup(DatabaseSessionFactory sessionFactory, XMLProfileParser xmlProfileParser, XMLProfileSerializer xmlProfileSerializer, MyBatis myBatis,
-                        QProfileLookup qProfileLookup, QProfileOperations qProfileOperations, QProfileActiveRuleOperations qProfileActiveRuleOperations, ESActiveRule esActiveRule,
-                        List<ProfileDefinition> definitions, PreviewCache dryRunCache) {
+                        QProfileLookup qProfileLookup, QProfileOperations qProfileOperations, QProfileActiveRuleOperations qProfileActiveRuleOperations, RuleDao ruleDao,
+                        ESActiveRule esActiveRule, List<ProfileDefinition> definitions, DefaultProfilesCache defaultProfilesCache, PreviewCache dryRunCache) {
     this.sessionFactory = sessionFactory;
     this.xmlProfileParser = xmlProfileParser;
     this.xmlProfileSerializer = xmlProfileSerializer;
@@ -82,8 +89,10 @@ public class QProfileBackup implements ServerComponent {
     this.qProfileLookup = qProfileLookup;
     this.qProfileOperations = qProfileOperations;
     this.qProfileActiveRuleOperations = qProfileActiveRuleOperations;
+    this.ruleDao = ruleDao;
     this.esActiveRule = esActiveRule;
     this.definitions = definitions;
+    this.defaultProfilesCache = defaultProfilesCache;
     this.dryRunCache = dryRunCache;
   }
 
@@ -174,7 +183,11 @@ public class QProfileBackup implements ServerComponent {
   public void restoreFromActiveRules(QProfile profile, RulesProfile rulesProfile, SqlSession session) {
     for (org.sonar.api.rules.ActiveRule activeRule : rulesProfile.getActiveRules()) {
       RuleKey ruleKey = RuleKey.of(activeRule.getRepositoryKey(), activeRule.getRuleKey());
-      ActiveRuleDto activeRuleDto = qProfileActiveRuleOperations.createActiveRule(profile.id(), ruleKey, activeRule.getSeverity().name(), session);
+      RuleDto rule = ruleDao.selectByKey(ruleKey, session);
+      if (rule == null) {
+        throw new NotFoundException(String.format("Rule '%s' does not exists.", ruleKey));
+      }
+      ActiveRuleDto activeRuleDto = qProfileActiveRuleOperations.createActiveRule(profile.id(), rule.getId(), activeRule.getSeverity().name(), session);
       for (RuleParam param : activeRule.getRule().getParams()) {
         String paramKey = param.getKey();
         String value = activeRule.getParameter(param.getKey());
@@ -189,12 +202,7 @@ public class QProfileBackup implements ServerComponent {
    * Return the list of default profile names for a given language
    */
   public Collection<String> findDefaultProfileNamesByLanguage(String language) {
-    Set<String> profiles = newHashSet();
-    ListMultimap<String, RulesProfile> profilesByName = profilesByName(language, new QProfileResult());
-    for (RulesProfile rulesProfile : profilesByName.values()) {
-      profiles.add(rulesProfile.getName());
-    }
-    return profiles;
+    return defaultProfilesCache.byLanguage(language);
   }
 
   private void checkProfileDoesNotExists(RulesProfile importedProfile, boolean deleteExisting, DatabaseSession hibernateSession) {
index 94fe7d579b7d66e525a860b156cf14eca40959d7..3810d2a8789e8905b1c74e94a24de3dd945ea009 100644 (file)
@@ -58,6 +58,7 @@ public class RegisterQualityProfiles {
   private final ESActiveRule esActiveRule;
   private final PersistentSettings settings;
   private final List<ProfileDefinition> definitions;
+  private final DefaultProfilesCache defaultProfilesCache;
   private final DatabaseSessionFactory sessionFactory;
   private final MyBatis myBatis;
 
@@ -69,8 +70,9 @@ public class RegisterQualityProfiles {
                                  QProfileBackup qProfileBackup,
                                  QProfileOperations qProfileOperations,
                                  QProfileLookup qProfileLookup,
+                                 DefaultProfilesCache defaultProfilesCache,
                                  RegisterRules registerRulesBefore) {
-    this(sessionFactory, myBatis, settings, esActiveRule, loadedTemplateDao, qProfileBackup, qProfileOperations, qProfileLookup, registerRulesBefore,
+    this(sessionFactory, myBatis, settings, esActiveRule, loadedTemplateDao, qProfileBackup, qProfileOperations, qProfileLookup, defaultProfilesCache, registerRulesBefore,
       Collections.<ProfileDefinition>emptyList());
   }
 
@@ -82,6 +84,7 @@ public class RegisterQualityProfiles {
                                  QProfileBackup qProfileBackup,
                                  QProfileOperations qProfileOperations,
                                  QProfileLookup qProfileLookup,
+                                 DefaultProfilesCache defaultProfilesCache,
                                  RegisterRules registerRulesBefore,
                                  List<ProfileDefinition> definitions) {
     this.sessionFactory = sessionFactory;
@@ -91,6 +94,7 @@ public class RegisterQualityProfiles {
     this.qProfileBackup = qProfileBackup;
     this.qProfileOperations = qProfileOperations;
     this.qProfileLookup = qProfileLookup;
+    this.defaultProfilesCache = defaultProfilesCache;
     this.definitions = definitions;
     this.loadedTemplateDao = loadedTemplateDao;
   }
@@ -114,6 +118,7 @@ public class RegisterQualityProfiles {
           if (shouldRegister(language, name, session)) {
             register(language, name, entry.getValue(), session);
           }
+          defaultProfilesCache.put(language, name);
         }
         setDefault(language, profiles, session);
       }
diff --git a/sonar-server/src/test/java/org/sonar/server/qualityprofile/DefaultProfilesCacheTest.java b/sonar-server/src/test/java/org/sonar/server/qualityprofile/DefaultProfilesCacheTest.java
new file mode 100644 (file)
index 0000000..7729e3b
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 org.junit.Before;
+import org.junit.Test;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+
+public class DefaultProfilesCacheTest {
+
+  DefaultProfilesCache cache;
+
+  @Before
+  public void setUp() throws Exception {
+    cache = new DefaultProfilesCache();
+  }
+
+  @Test
+  public void add_profiles() throws Exception {
+    cache.put("java", "Default");
+    cache.put("java", "Sonar Way");
+    cache.put("js", "Default");
+
+    assertThat(cache.byLanguage("java")).containsOnly("Default", "Sonar Way");
+    assertThat(cache.byLanguage("js")).containsOnly("Default");
+  }
+
+  @Test
+  public void not_add_same_profile_name() throws Exception {
+    cache.put("java", "Default");
+    cache.put("java", "Default");
+
+    assertThat(cache.byLanguage("java")).containsOnly("Default");
+  }
+}
index 00aefa48247231e9a5775a7859a0f8a83fe72aa5..e43169f12c62b0f021702e5932153813a7816a04 100644 (file)
@@ -39,17 +39,12 @@ import org.sonar.api.utils.System2;
 import org.sonar.core.permission.GlobalPermissions;
 import org.sonar.core.persistence.DbSession;
 import org.sonar.core.persistence.MyBatis;
-import org.sonar.core.qualityprofile.db.ActiveRuleDao;
-import org.sonar.core.qualityprofile.db.ActiveRuleDto;
-import org.sonar.core.qualityprofile.db.ActiveRuleParamDto;
-import org.sonar.core.qualityprofile.db.QualityProfileDao;
-import org.sonar.core.qualityprofile.db.QualityProfileDto;
+import org.sonar.core.qualityprofile.db.*;
 import org.sonar.core.rule.RuleDao;
 import org.sonar.core.rule.RuleDto;
 import org.sonar.core.rule.RuleParamDto;
 import org.sonar.server.exceptions.BadRequestException;
 import org.sonar.server.exceptions.ForbiddenException;
-import org.sonar.server.exceptions.NotFoundException;
 import org.sonar.server.user.MockUserSession;
 import org.sonar.server.user.UserSession;
 import org.sonar.server.util.TypeValidations;
@@ -65,14 +60,7 @@ import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyList;
 import static org.mockito.Matchers.anyListOf;
 import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.*;
 
 @RunWith(MockitoJUnitRunner.class)
 public class QProfileActiveRuleOperationsTest {
@@ -178,11 +166,10 @@ public class QProfileActiveRuleOperationsTest {
   @Test
   public void create_active_rule() throws Exception {
     RuleKey ruleKey = RuleKey.of("repo", "key");
-    when(ruleDao.selectByKey(ruleKey, session)).thenReturn(new RuleDto().setId(10));
 
     when(ruleDao.selectParametersByRuleId(eq(10), eq(session))).thenReturn(newArrayList(new RuleParamDto().setId(20).setName("max").setDefaultValue("10")));
 
-    operations.createActiveRule(1, ruleKey, Severity.CRITICAL, session);
+    operations.createActiveRule(1, 10, Severity.CRITICAL, session);
 
     ArgumentCaptor<ActiveRuleDto> activeRuleArgument = ArgumentCaptor.forClass(ActiveRuleDto.class);
     verify(activeRuleDao).insert(activeRuleArgument.capture(), eq(session));
@@ -199,23 +186,6 @@ public class QProfileActiveRuleOperationsTest {
     verifyZeroInteractions(esActiveRule);
   }
 
-  @Test
-  public void fail_create_active_rule_when_rule_does_not_exists() throws Exception {
-    RuleKey ruleKey = RuleKey.of("repo", "key");
-    when(ruleDao.selectByKey(ruleKey, session)).thenReturn(null);
-
-    try {
-      operations.createActiveRule(1, ruleKey, Severity.CRITICAL, session);
-    } catch(Exception e) {
-      assertThat(e).isInstanceOf(NotFoundException.class);
-    }
-
-    verifyZeroInteractions(session);
-    verifyZeroInteractions(activeRuleDao);
-    verifyZeroInteractions(profilesManager);
-    verifyZeroInteractions(esActiveRule);
-  }
-
   @Test
   public void update_severity() throws Exception {
     when(profileDao.selectById(1, session)).thenReturn(new QualityProfileDto().setId(1).setName("Default").setLanguage("java"));
index 8760c76ab90f27c76a37a0967db116e5def967f8..3a970d2a29e1fcbe0a003435960c5cc9cbebf230 100644 (file)
@@ -42,9 +42,12 @@ import org.sonar.core.persistence.DbSession;
 import org.sonar.core.persistence.MyBatis;
 import org.sonar.core.preview.PreviewCache;
 import org.sonar.core.qualityprofile.db.ActiveRuleDto;
+import org.sonar.core.rule.RuleDao;
+import org.sonar.core.rule.RuleDto;
 import org.sonar.jpa.session.DatabaseSessionFactory;
 import org.sonar.server.exceptions.BadRequestException;
 import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.exceptions.NotFoundException;
 import org.sonar.server.user.MockUserSession;
 import org.sonar.server.user.UserSession;
 
@@ -59,13 +62,7 @@ import static org.fest.assertions.Fail.fail;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.*;
 
 @RunWith(MockitoJUnitRunner.class)
 public class QProfileBackupTest {
@@ -97,9 +94,14 @@ public class QProfileBackupTest {
   @Mock
   QProfileActiveRuleOperations qProfileActiveRuleOperations;
 
+  @Mock
+  RuleDao ruleDao;
+
   @Mock
   ESActiveRule esActiveRule;
 
+  DefaultProfilesCache defaultProfilesCache = new DefaultProfilesCache();
+
   @Mock
   PreviewCache dryRunCache;
 
@@ -114,8 +116,8 @@ public class QProfileBackupTest {
 
     definitions = newArrayList();
 
-    backup = new QProfileBackup(sessionFactory, xmlProfileParser, xmlProfileSerializer, myBatis, qProfileLookup, qProfileOperations, qProfileActiveRuleOperations,
-      esActiveRule, definitions, dryRunCache);
+    backup = new QProfileBackup(sessionFactory, xmlProfileParser, xmlProfileSerializer, myBatis, qProfileLookup, qProfileOperations, qProfileActiveRuleOperations, ruleDao,
+      esActiveRule, definitions, defaultProfilesCache, dryRunCache);
 
     MockUserSession.set().setLogin("nicolas").setName("Nicolas").setGlobalPermissions(GlobalPermissions.QUALITY_PROFILE_ADMIN);
   }
@@ -316,14 +318,15 @@ public class QProfileBackupTest {
 
     ProfileDefinition profileDefinition = mock(ProfileDefinition.class);
     when(profileDefinition.createProfile(any(ValidationMessages.class))).thenReturn(profile);
-
     definitions.add(profileDefinition);
 
+    when(ruleDao.selectByKey(RuleKey.of("pmd", "rule"), session)).thenReturn(new RuleDto().setId(10).setSeverity("INFO"));
+
     when(qProfileOperations.newProfile(eq(name), eq(language), eq(true), any(UserSession.class), eq(session))).thenReturn(new QProfile().setId(1));
 
     backup.restoreDefaultProfilesByLanguage(language);
 
-    verify(qProfileActiveRuleOperations).createActiveRule(eq(1), eq(RuleKey.of("pmd", "rule")), eq("BLOCKER"), eq(session));
+    verify(qProfileActiveRuleOperations).createActiveRule(eq(1), eq(10), eq("BLOCKER"), eq(session));
     verify(qProfileActiveRuleOperations).updateActiveRuleParam(any(ActiveRuleDto.class), eq("max"), eq("10"), eq(session));
     verifyNoMoreInteractions(qProfileActiveRuleOperations);
 
@@ -346,12 +349,15 @@ public class QProfileBackupTest {
     when(profileDefinition2.createProfile(any(ValidationMessages.class))).thenReturn(profile2);
     definitions.add(profileDefinition2);
 
+    when(ruleDao.selectByKey(RuleKey.of("pmd", "rule"), session)).thenReturn(new RuleDto().setId(10).setSeverity("INFO"));
+    when(ruleDao.selectByKey(RuleKey.of("checkstyle", "rule"), session)).thenReturn(new RuleDto().setId(11).setSeverity("INFO"));
+
     when(qProfileOperations.newProfile(eq("Default"), eq("java"), eq(true), any(UserSession.class), eq(session))).thenReturn(new QProfile().setId(1));
 
     backup.restoreDefaultProfilesByLanguage("java");
 
-    verify(qProfileActiveRuleOperations).createActiveRule(eq(1), eq(RuleKey.of("pmd", "rule")), eq("BLOCKER"), eq(session));
-    verify(qProfileActiveRuleOperations).createActiveRule(eq(1), eq(RuleKey.of("checkstyle", "rule")), eq("MAJOR"), eq(session));
+    verify(qProfileActiveRuleOperations).createActiveRule(eq(1), eq(10), eq("BLOCKER"), eq(session));
+    verify(qProfileActiveRuleOperations).createActiveRule(eq(1), eq(11), eq("MAJOR"), eq(session));
     verifyNoMoreInteractions(qProfileActiveRuleOperations);
 
     verify(esActiveRule).bulkIndexProfile(eq(1), eq(session));
@@ -359,6 +365,33 @@ public class QProfileBackupTest {
     verify(session).commit();
   }
 
+  @Test
+  public void fail_to_restore_profile_when_rule_not_found() throws Exception {
+    String name = "Default";
+    String language = "java";
+
+    RulesProfile profile = RulesProfile.create(name, language);
+    Rule rule = Rule.create("pmd", "rule");
+    profile.activateRule(rule, null);
+
+    ProfileDefinition profileDefinition = mock(ProfileDefinition.class);
+    when(profileDefinition.createProfile(any(ValidationMessages.class))).thenReturn(profile);
+    definitions.add(profileDefinition);
+
+    when(ruleDao.selectByKey(RuleKey.of("pmd", "rule"), session)).thenReturn(null);
+
+    when(qProfileOperations.newProfile(eq(name), eq(language), eq(true), any(UserSession.class), eq(session))).thenReturn(new QProfile().setId(1));
+
+    try {
+      backup.restoreDefaultProfilesByLanguage(language);
+      fail();
+    } catch (Exception e) {
+      assertThat(e).isInstanceOf(NotFoundException.class);
+    }
+    verifyZeroInteractions(qProfileActiveRuleOperations);
+    verifyZeroInteractions(esActiveRule);
+  }
+
   @Test
   public void not_restore_default_profiles_from_another_language() throws Exception {
     RulesProfile profile = RulesProfile.create("Default", "java");
@@ -371,26 +404,14 @@ public class QProfileBackupTest {
 
     verifyZeroInteractions(qProfileOperations);
     verifyZeroInteractions(qProfileActiveRuleOperations);
-
     verifyZeroInteractions(esActiveRule);
   }
 
   @Test
   public void find_default_profile_names_by_language() throws Exception {
-    RulesProfile rulesProfile1 = RulesProfile.create("Basic", "java");
-    ProfileDefinition profileDefinition1 = mock(ProfileDefinition.class);
-    when(profileDefinition1.createProfile(any(ValidationMessages.class))).thenReturn(rulesProfile1);
-    definitions.add(profileDefinition1);
-
-    RulesProfile rulesProfile2 = RulesProfile.create("Default", "java");
-    ProfileDefinition profileDefinition2 = mock(ProfileDefinition.class);
-    when(profileDefinition2.createProfile(any(ValidationMessages.class))).thenReturn(rulesProfile2);
-    definitions.add(profileDefinition2);
-
-    RulesProfile rulesProfile3 = RulesProfile.create("Default", "java");
-    ProfileDefinition profileDefinition3 = mock(ProfileDefinition.class);
-    when(profileDefinition3.createProfile(any(ValidationMessages.class))).thenReturn(rulesProfile3);
-    definitions.add(profileDefinition3);
+    defaultProfilesCache.put("java", "Basic");
+    defaultProfilesCache.put("java", "Default");
+    defaultProfilesCache.put("java", "Default");
 
     Collection<String> result = backup.findDefaultProfileNamesByLanguage("java");
     assertThat(result).containsOnly("Basic", "Default");
index 028d50a85bf48ba90b1e149161f6c77a7d9f0bcc..8f2bc43a7bc72c0411c7e213cd8680885dc82d05 100644 (file)
@@ -38,11 +38,7 @@ import org.sonar.core.template.LoadedTemplateDao;
 import org.sonar.core.template.LoadedTemplateDto;
 import org.sonar.jpa.session.DatabaseSessionFactory;
 import org.sonar.server.platform.PersistentSettings;
-import org.sonar.server.qualityprofile.ESActiveRule;
-import org.sonar.server.qualityprofile.QProfile;
-import org.sonar.server.qualityprofile.QProfileBackup;
-import org.sonar.server.qualityprofile.QProfileLookup;
-import org.sonar.server.qualityprofile.QProfileOperations;
+import org.sonar.server.qualityprofile.*;
 import org.sonar.server.user.UserSession;
 
 import java.util.List;
@@ -53,12 +49,7 @@ import static org.fest.assertions.Fail.fail;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.*;
 
 @RunWith(MockitoJUnitRunner.class)
 public class RegisterQualityProfilesTest {
@@ -81,6 +72,8 @@ public class RegisterQualityProfilesTest {
   @Mock
   ESActiveRule esActiveRule;
 
+  DefaultProfilesCache defaultProfilesCache = new DefaultProfilesCache();
+
   @Mock
   MyBatis myBatis;
 
@@ -103,7 +96,8 @@ public class RegisterQualityProfilesTest {
     when(sessionFactory.getSession()).thenReturn(mock(DatabaseSession.class));
 
     definitions = newArrayList();
-    registerQualityProfiles = new RegisterQualityProfiles(sessionFactory, myBatis, settings, esActiveRule, loadedTemplateDao, qProfileBackup, qProfileOperations, qProfileLookup, null, definitions);
+    registerQualityProfiles = new RegisterQualityProfiles(sessionFactory, myBatis, settings, esActiveRule, loadedTemplateDao, qProfileBackup, qProfileOperations, qProfileLookup,
+      defaultProfilesCache, null, definitions);
   }
 
   @Test
@@ -127,8 +121,9 @@ public class RegisterQualityProfilesTest {
 
     verify(settings).saveProperty("sonar.profile.java", "Default");
 
-    verify(session).commit();
+    assertThat(defaultProfilesCache.byLanguage("java")).containsOnly("Default");
 
+    verify(session).commit();
     verify(esActiveRule).bulkRegisterActiveRules();
   }
 
@@ -159,6 +154,9 @@ public class RegisterQualityProfilesTest {
 
     verify(settings).saveProperty("sonar.profile.java", "Default");
     verify(settings).saveProperty("sonar.profile.js", "Default");
+
+    assertThat(defaultProfilesCache.byLanguage("java")).containsOnly("Default");
+    assertThat(defaultProfilesCache.byLanguage("js")).containsOnly("Default");
   }
 
   @Test
@@ -184,6 +182,7 @@ public class RegisterQualityProfilesTest {
     registerQualityProfiles.start();
 
     verify(settings).saveProperty("sonar.profile.java", "Default");
+    assertThat(defaultProfilesCache.byLanguage("java")).containsOnly("Default", "Basic");
   }
 
   @Test