From af4b29f383fbd946c4a70abe390b3f8f808b5179 Mon Sep 17 00:00:00 2001 From: Julien Lancelot Date: Tue, 29 Apr 2014 16:18:07 +0200 Subject: [PATCH] SONAR-4764 Create a DefaultProfilesCache component to store default profile names in order to speed up display of popup displayed when clicking on 'Restore Default Profile' button --- .../server/platform/ServerComponents.java | 1 + .../qualityprofile/DefaultProfilesCache.java | 54 +++++++++++++ .../QProfileActiveRuleOperations.java | 8 +- .../server/qualityprofile/QProfileBackup.java | 38 +++++---- .../startup/RegisterQualityProfiles.java | 7 +- .../DefaultProfilesCacheTest.java | 55 +++++++++++++ .../QProfileActiveRuleOperationsTest.java | 36 +-------- .../qualityprofile/QProfileBackupTest.java | 77 ++++++++++++------- .../startup/RegisterQualityProfilesTest.java | 25 +++--- 9 files changed, 204 insertions(+), 97 deletions(-) create mode 100644 sonar-server/src/main/java/org/sonar/server/qualityprofile/DefaultProfilesCache.java create mode 100644 sonar-server/src/test/java/org/sonar/server/qualityprofile/DefaultProfilesCacheTest.java diff --git a/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java b/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java index 472498ba7fb..0c437cf82ce 100644 --- a/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java +++ b/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java @@ -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 index 00000000000..992403ed23d --- /dev/null +++ b/sonar-server/src/main/java/org/sonar/server/qualityprofile/DefaultProfilesCache.java @@ -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 defaultProfilesCache; + + public DefaultProfilesCache() { + this.defaultProfilesCache = ArrayListMultimap.create(); + } + + public Collection byLanguage(String language) { + return defaultProfilesCache.get(language); + } + + public DefaultProfilesCache put(String language, String name) { + defaultProfilesCache.put(language, name); + return this; + } + +} diff --git a/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileActiveRuleOperations.java b/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileActiveRuleOperations.java index 789e01b5f70..ed25e2d1984 100644 --- a/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileActiveRuleOperations.java +++ b/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileActiveRuleOperations.java @@ -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) diff --git a/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileBackup.java b/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileBackup.java index a94ffe26729..624bfbfa349 100644 --- a/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileBackup.java +++ b/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileBackup.java @@ -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
Internal.profile_backup
@@ -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 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.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.emptyList(), defaultProfilesCache, dryRunCache); } public QProfileBackup(DatabaseSessionFactory sessionFactory, XMLProfileParser xmlProfileParser, XMLProfileSerializer xmlProfileSerializer, MyBatis myBatis, - QProfileLookup qProfileLookup, QProfileOperations qProfileOperations, QProfileActiveRuleOperations qProfileActiveRuleOperations, ESActiveRule esActiveRule, - List definitions, PreviewCache dryRunCache) { + QProfileLookup qProfileLookup, QProfileOperations qProfileOperations, QProfileActiveRuleOperations qProfileActiveRuleOperations, RuleDao ruleDao, + ESActiveRule esActiveRule, List 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 findDefaultProfileNamesByLanguage(String language) { - Set profiles = newHashSet(); - ListMultimap 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) { diff --git a/sonar-server/src/main/java/org/sonar/server/startup/RegisterQualityProfiles.java b/sonar-server/src/main/java/org/sonar/server/startup/RegisterQualityProfiles.java index 94fe7d579b7..3810d2a8789 100644 --- a/sonar-server/src/main/java/org/sonar/server/startup/RegisterQualityProfiles.java +++ b/sonar-server/src/main/java/org/sonar/server/startup/RegisterQualityProfiles.java @@ -58,6 +58,7 @@ public class RegisterQualityProfiles { private final ESActiveRule esActiveRule; private final PersistentSettings settings; private final List 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.emptyList()); } @@ -82,6 +84,7 @@ public class RegisterQualityProfiles { QProfileBackup qProfileBackup, QProfileOperations qProfileOperations, QProfileLookup qProfileLookup, + DefaultProfilesCache defaultProfilesCache, RegisterRules registerRulesBefore, List 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 index 00000000000..7729e3bcc8d --- /dev/null +++ b/sonar-server/src/test/java/org/sonar/server/qualityprofile/DefaultProfilesCacheTest.java @@ -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"); + } +} diff --git a/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileActiveRuleOperationsTest.java b/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileActiveRuleOperationsTest.java index 00aefa48247..e43169f12c6 100644 --- a/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileActiveRuleOperationsTest.java +++ b/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileActiveRuleOperationsTest.java @@ -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 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")); diff --git a/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileBackupTest.java b/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileBackupTest.java index 8760c76ab90..3a970d2a29e 100644 --- a/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileBackupTest.java +++ b/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileBackupTest.java @@ -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 result = backup.findDefaultProfileNamesByLanguage("java"); assertThat(result).containsOnly("Basic", "Default"); diff --git a/sonar-server/src/test/java/org/sonar/server/startup/RegisterQualityProfilesTest.java b/sonar-server/src/test/java/org/sonar/server/startup/RegisterQualityProfilesTest.java index 028d50a85bf..8f2bc43a7bc 100644 --- a/sonar-server/src/test/java/org/sonar/server/startup/RegisterQualityProfilesTest.java +++ b/sonar-server/src/test/java/org/sonar/server/startup/RegisterQualityProfilesTest.java @@ -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 -- 2.39.5