From 2bc8b951c6cd51ea1d6a9bc132527b640983c177 Mon Sep 17 00:00:00 2001 From: Simon Brandhof Date: Tue, 3 Jun 2014 15:25:11 +0200 Subject: [PATCH] SONAR-5007 restore Q profile backup by keeping parent-child association --- .../qualityprofile/ProfilesManager.java | 29 -- .../server/qualityprofile/QProfileBackup.java | 80 +----- .../qualityprofile/QProfileBackuper.java | 214 ++++++++++++++ .../qualityprofile/QProfileService.java | 86 +++++- .../qualityprofile/RuleActivationContext.java | 26 +- .../RuleActivationContextFactory.java | 6 +- .../server/qualityprofile/RuleActivator.java | 37 +-- .../ws/BulkRuleActivationActions.java | 9 +- .../server/qualityprofile/ws/ProfilesWs.java | 2 - .../org/sonar/server/rule/RegisterRules.java | 18 +- .../controllers/api/profiles_controller.rb | 12 +- .../app/controllers/profiles_controller.rb | 21 +- .../webapp/WEB-INF/app/models/internal.rb | 2 - .../qualityprofile/ProfilesManagerTest.java | 23 -- .../qualityprofile/QProfileBackupTest.java | 212 +------------- .../QProfileBackuperMediumTest.java | 263 ++++++++++++++++++ .../RuleActivatorMediumTest.java | 182 ++++++------ .../server/qualityprofile/RuleChangeTest.java | 8 - .../sonar/server/rule/RegisterRulesTest.java | 6 +- .../server/rule/RuleBackendMediumTest.java | 15 +- .../expected-backup.xml | 18 ++ .../not-xml-backup.txt | 1 + .../restore-child.xml | 18 ++ .../restore-parent.xml | 18 ++ .../QProfileBackuperMediumTest/restore.xml | 18 ++ ...ore_fails_to_deactivate_inherited_rule.xml | 12 + 26 files changed, 838 insertions(+), 498 deletions(-) create mode 100644 sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileBackuper.java create mode 100644 sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileBackuperMediumTest.java create mode 100644 sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileBackuperMediumTest/expected-backup.xml create mode 100644 sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileBackuperMediumTest/not-xml-backup.txt create mode 100644 sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileBackuperMediumTest/restore-child.xml create mode 100644 sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileBackuperMediumTest/restore-parent.xml create mode 100644 sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileBackuperMediumTest/restore.xml create mode 100644 sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileBackuperMediumTest/restore_fails_to_deactivate_inherited_rule.xml diff --git a/sonar-server/src/main/java/org/sonar/server/qualityprofile/ProfilesManager.java b/sonar-server/src/main/java/org/sonar/server/qualityprofile/ProfilesManager.java index 80c3c507799..84f1e5916e8 100644 --- a/sonar-server/src/main/java/org/sonar/server/qualityprofile/ProfilesManager.java +++ b/sonar-server/src/main/java/org/sonar/server/qualityprofile/ProfilesManager.java @@ -91,35 +91,6 @@ public class ProfilesManager extends BaseDao { return actions; } - /** - * Deactivate all active rules from profiles using a rule, then remove then. - */ - public void removeActivatedRules(int ruleId) { - List activeRules = getSession().createQuery("FROM " + ActiveRule.class.getSimpleName() + " WHERE rule.id=:ruleId").setParameter("ruleId", ruleId).getResultList(); - List activeRulesToRemove = Lists.newArrayList(); - - for (ActiveRule activeRule : activeRules) { - if (!activeRule.isInherited()) { - RulesProfile profile = activeRule.getRulesProfile(); - incrementProfileVersionIfNeeded(profile); - ruleDisabled(profile, activeRule, null); - for (RulesProfile child : getChildren(profile.getId())) { - deactivate(child, activeRule.getRule(), null); - } - activeRulesToRemove.add(activeRule); - } - } - - for (ActiveRule activeRule : activeRulesToRemove) { - // Do not use getSingleResult as it can generate an EntityNotFoundException - ActiveRule activeRuleToRemove = getSession().getEntity(ActiveRule.class, activeRule.getId()); - removeActiveRule(activeRuleToRemove); - } - getSession().commit(); - dryRunCache.reportGlobalModification(); - } - - /** * Rule was activated */ 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 8a19ddda3ea..6b8325461d6 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 @@ -23,11 +23,8 @@ package org.sonar.server.qualityprofile; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ListMultimap; import org.sonar.api.ServerComponent; -import org.sonar.api.database.DatabaseSession; import org.sonar.api.profiles.ProfileDefinition; import org.sonar.api.profiles.RulesProfile; -import org.sonar.api.profiles.XMLProfileParser; -import org.sonar.api.profiles.XMLProfileSerializer; import org.sonar.api.rule.RuleKey; import org.sonar.api.rules.RuleParam; import org.sonar.api.utils.ValidationMessages; @@ -38,15 +35,11 @@ import org.sonar.core.preview.PreviewCache; import org.sonar.core.qualityprofile.db.ActiveRuleDto; import org.sonar.core.qualityprofile.db.QualityProfileKey; 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.rule.db.RuleDao; import org.sonar.server.user.UserSession; -import java.io.StringReader; -import java.io.StringWriter; -import java.io.Writer; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -56,12 +49,7 @@ import static com.google.common.collect.Lists.newArrayList; public class QProfileBackup implements ServerComponent { - private final DatabaseSessionFactory sessionFactory; - private final XMLProfileParser xmlProfileParser; - private final XMLProfileSerializer xmlProfileSerializer; - private final MyBatis myBatis; - private final QProfileLookup qProfileLookup; private final QProfileOperations qProfileOperations; private final QProfileActiveRuleOperations qProfileActiveRuleOperations; private final RuleDao ruleDao; @@ -69,21 +57,17 @@ public class QProfileBackup implements ServerComponent { private final DefaultProfilesCache defaultProfilesCache; private final PreviewCache dryRunCache; - public QProfileBackup(DatabaseSessionFactory sessionFactory, XMLProfileParser xmlProfileParser, XMLProfileSerializer xmlProfileSerializer, MyBatis myBatis, - QProfileLookup qProfileLookup, QProfileOperations qProfileOperations, QProfileActiveRuleOperations qProfileActiveRuleOperations, RuleDao ruleDao, + public QProfileBackup(MyBatis myBatis, + QProfileOperations qProfileOperations, QProfileActiveRuleOperations qProfileActiveRuleOperations, RuleDao ruleDao, DefaultProfilesCache defaultProfilesCache, PreviewCache dryRunCache) { - this(sessionFactory, xmlProfileParser, xmlProfileSerializer, myBatis, qProfileLookup, qProfileOperations, qProfileActiveRuleOperations, ruleDao, + this(myBatis, qProfileOperations, qProfileActiveRuleOperations, ruleDao, Collections.emptyList(), defaultProfilesCache, dryRunCache); } - public QProfileBackup(DatabaseSessionFactory sessionFactory, XMLProfileParser xmlProfileParser, XMLProfileSerializer xmlProfileSerializer, MyBatis myBatis, - QProfileLookup qProfileLookup, QProfileOperations qProfileOperations, QProfileActiveRuleOperations qProfileActiveRuleOperations, RuleDao ruleDao, + public QProfileBackup(MyBatis myBatis, + QProfileOperations qProfileOperations, QProfileActiveRuleOperations qProfileActiveRuleOperations, RuleDao ruleDao, List definitions, DefaultProfilesCache defaultProfilesCache, PreviewCache dryRunCache) { - this.sessionFactory = sessionFactory; - this.xmlProfileParser = xmlProfileParser; - this.xmlProfileSerializer = xmlProfileSerializer; this.myBatis = myBatis; - this.qProfileLookup = qProfileLookup; this.qProfileOperations = qProfileOperations; this.qProfileActiveRuleOperations = qProfileActiveRuleOperations; this.ruleDao = ruleDao; @@ -92,47 +76,6 @@ public class QProfileBackup implements ServerComponent { this.dryRunCache = dryRunCache; } - public String backupProfile(QProfile profile) { - DatabaseSession session = sessionFactory.getSession(); - RulesProfile rulesProfile = session.getSingleResult(RulesProfile.class, "id", profile.id()); - Writer writer = new StringWriter(); - xmlProfileSerializer.write(rulesProfile, writer); - return writer.toString(); - } - - /** - * @param deleteExisting is used to not fail if profile exist but to delete it first. It's only used by WS, and it should be soon removed. - */ - public QProfileResult restore(String xmlBackup, boolean deleteExisting) { - checkPermission(UserSession.get()); - - DbSession session = myBatis.openSession(false); - QProfileResult result = new QProfileResult(); - try { - ValidationMessages messages = ValidationMessages.create(); - RulesProfile importedProfile = xmlProfileParser.parse(new StringReader(xmlBackup), messages); - processValidationMessages(messages, result); - if (importedProfile != null) { - DatabaseSession hibernateSession = sessionFactory.getSession(); - checkProfileDoesNotExists(importedProfile, deleteExisting, hibernateSession); - hibernateSession.saveWithoutFlush(importedProfile); - hibernateSession.commit(); - - QProfile newProfile = qProfileLookup.profile(importedProfile.getId(), session); - if (newProfile == null) { - throw new BadRequestException("Restore of the profile has failed."); - } - //esActiveRule.bulkIndexProfile(newProfile.id(), session); - dryRunCache.reportGlobalModification(session); - session.commit(); - result.setProfile(newProfile); - } - } finally { - MyBatis.closeQuietly(session); - } - return result; - } - /** * Recreate built-in profile for a given language. * If a profile with same name than default profile already exists, an exception will be thrown. @@ -201,19 +144,6 @@ public class QProfileBackup implements ServerComponent { return defaultProfilesCache.byLanguage(language); } - private void checkProfileDoesNotExists(RulesProfile importedProfile, boolean deleteExisting, DatabaseSession hibernateSession) { - RulesProfile existingProfile = hibernateSession.getSingleResult(RulesProfile.class, "name", importedProfile.getName(), "language", importedProfile.getLanguage()); - if (existingProfile != null && !deleteExisting) { - throw BadRequestException.of("The profile " + existingProfile + " already exists. Please delete it before restoring."); - } - if (existingProfile != null) { - // Warning, profile with children can be deleted as no check is done! - hibernateSession.removeWithoutFlush(existingProfile); - hibernateSession.commit(); - //esActiveRule.deleteActiveRulesFromProfile(existingProfile.getId()); - } - } - private void processValidationMessages(ValidationMessages messages, QProfileResult result) { if (!messages.getErrors().isEmpty()) { List errors = newArrayList(); diff --git a/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileBackuper.java b/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileBackuper.java new file mode 100644 index 00000000000..d6132387ab5 --- /dev/null +++ b/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileBackuper.java @@ -0,0 +1,214 @@ +/* + * 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.Maps; +import com.google.common.collect.Sets; +import org.apache.commons.lang.StringUtils; +import org.codehaus.staxmate.SMInputFactory; +import org.codehaus.staxmate.in.SMHierarchicCursor; +import org.codehaus.staxmate.in.SMInputCursor; +import org.sonar.api.ServerComponent; +import org.sonar.api.rule.RuleKey; +import org.sonar.api.utils.text.XmlWriter; +import org.sonar.core.persistence.DbSession; +import org.sonar.core.qualityprofile.db.ActiveRuleDto; +import org.sonar.core.qualityprofile.db.ActiveRuleKey; +import org.sonar.core.qualityprofile.db.QualityProfileDto; +import org.sonar.core.qualityprofile.db.QualityProfileKey; +import org.sonar.server.db.DbClient; +import org.sonar.server.qualityprofile.index.ActiveRuleIndex; +import org.sonar.server.search.IndexClient; + +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import java.io.Reader; +import java.io.Writer; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class QProfileBackuper implements ServerComponent { + + private final RuleActivator activator; + private final DbClient db; + private final IndexClient index; + + public QProfileBackuper(RuleActivator activator, DbClient db, IndexClient index) { + this.activator = activator; + this.db = db; + this.index = index; + } + + public void backup(QualityProfileKey key, Writer writer) { + // TODO check permission + DbSession dbSession = db.openSession(false); + try { + QualityProfileDto profile = db.qualityProfileDao().getByKey(key, dbSession); + if (profile == null) { + throw new IllegalArgumentException("Quality profile does not exist: " + key); + } + List activeRules = index.get(ActiveRuleIndex.class).findByProfile(key); + writeXml(writer, profile, activeRules); + + } finally { + dbSession.close(); + } + } + + private void writeXml(Writer writer, QualityProfileDto profile, List activeRules) { + XmlWriter xml = XmlWriter.of(writer).declaration(); + xml.begin("profile"); + xml.prop("name", profile.getName()); + xml.prop("language", profile.getLanguage()); + xml.begin("rules"); + for (ActiveRule activeRule : activeRules) { + xml.begin("rule"); + xml.prop("repositoryKey", activeRule.key().ruleKey().repository()); + xml.prop("key", activeRule.key().ruleKey().rule()); + xml.prop("priority", activeRule.severity()); + xml.begin("parameters"); + for (Map.Entry param : activeRule.params().entrySet()) { + xml + .begin("parameter") + .prop("key", param.getKey()) + .prop("value", param.getValue()) + .end(); + } + xml.end("parameters"); + xml.end("rule"); + } + xml.end("rules"); + xml.end("profile").close(); + } + + public void restore(Reader reader) { + try { + String profileLang = null, profileName = null; + SMInputFactory inputFactory = initStax(); + SMHierarchicCursor rootC = inputFactory.rootElementCursor(reader); + rootC.advance(); // + SMInputCursor cursor = rootC.childElementCursor(); + while (cursor.getNext() != null) { + String nodeName = cursor.getLocalName(); + if (StringUtils.equals("name", nodeName)) { + profileName = StringUtils.trim(cursor.collectDescendantText(false)); + + } else if (StringUtils.equals("language", nodeName)) { + profileLang = StringUtils.trim(cursor.collectDescendantText(false)); + + } else if (StringUtils.equals("rules", nodeName)) { + QualityProfileKey profileKey = QualityProfileKey.of(profileName, profileLang); + SMInputCursor rulesCursor = cursor.childElementCursor("rule"); + doRestore(rulesCursor, profileKey); + } + } + } catch (XMLStreamException e) { + throw new IllegalStateException("Fail to restore Quality profile backup", e); + } + } + + private void doRestore(SMInputCursor rulesCursor, QualityProfileKey profileKey) throws XMLStreamException { + Set rulesToDeactivate = Sets.newHashSet(); + DbSession dbSession = db.openSession(false); + try { + // find or create profile + if (db.qualityProfileDao().getByKey(profileKey, dbSession) == null) { + // create new profile + db.qualityProfileDao().insert(dbSession, QualityProfileDto.createFor(profileKey)); + } else { + // already exists. Keep reference to all the activated rules before backup restore + for (ActiveRuleDto activeRuleDto : db.activeRuleDao().findByProfileKey(dbSession, profileKey)) { + rulesToDeactivate.add(activeRuleDto.getKey().ruleKey()); + } + } + + while (rulesCursor.getNext() != null) { + SMInputCursor ruleCursor = rulesCursor.childElementCursor(); + String repositoryKey = null, key = null, severity = null; + Map parameters = Maps.newHashMap(); + while (ruleCursor.getNext() != null) { + String nodeName = ruleCursor.getLocalName(); + if (StringUtils.equals("repositoryKey", nodeName)) { + repositoryKey = StringUtils.trim(ruleCursor.collectDescendantText(false)); + + } else if (StringUtils.equals("key", nodeName)) { + key = StringUtils.trim(ruleCursor.collectDescendantText(false)); + + } else if (StringUtils.equals("priority", nodeName)) { + severity = StringUtils.trim(ruleCursor.collectDescendantText(false)); + + } else if (StringUtils.equals("parameters", nodeName)) { + SMInputCursor propsCursor = ruleCursor.childElementCursor("parameter"); + readParameters(propsCursor, parameters); + } + } + RuleKey ruleKey = RuleKey.of(repositoryKey, key); + RuleActivation activation = new RuleActivation(ActiveRuleKey.of(profileKey, ruleKey)); + activation.setSeverity(severity); + activation.setParameters(parameters); + activator.activate(dbSession, activation); + rulesToDeactivate.remove(ruleKey); + } + for (RuleKey ruleKey : rulesToDeactivate) { + // Will fail to deactivate a rule which is activated in a parent profile + activator.deactivate(ActiveRuleKey.of(profileKey, ruleKey), dbSession); + } + dbSession.commit(); + + } finally { + dbSession.close(); + } + } + + private void readParameters(SMInputCursor propsCursor, Map parameters) throws XMLStreamException { + while (propsCursor.getNext() != null) { + SMInputCursor propCursor = propsCursor.childElementCursor(); + String key = null; + String value = null; + while (propCursor.getNext() != null) { + String nodeName = propCursor.getLocalName(); + if (StringUtils.equals("key", nodeName)) { + key = StringUtils.trim(propCursor.collectDescendantText(false)); + + } else if (StringUtils.equals("value", nodeName)) { + value = StringUtils.trim(propCursor.collectDescendantText(false)); + } + } + if (key != null) { + parameters.put(key, value); + } + } + } + + private SMInputFactory initStax() { + XMLInputFactory xmlFactory = XMLInputFactory.newInstance(); + xmlFactory.setProperty(XMLInputFactory.IS_COALESCING, Boolean.TRUE); + xmlFactory.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, Boolean.FALSE); + // just so it won't try to load DTD in if there's DOCTYPE + xmlFactory.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE); + xmlFactory.setProperty(XMLInputFactory.IS_VALIDATING, Boolean.FALSE); + return new SMInputFactory(xmlFactory); + } + + public void resetForLang(String language) { + // TODO + } +} diff --git a/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileService.java b/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileService.java index b1346dd9e28..953dc925073 100644 --- a/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileService.java +++ b/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileService.java @@ -22,23 +22,32 @@ package org.sonar.server.qualityprofile; import com.google.common.collect.Multimap; import org.sonar.api.ServerComponent; import org.sonar.api.rule.RuleKey; +import org.sonar.core.permission.GlobalPermissions; import org.sonar.core.qualityprofile.db.ActiveRuleKey; import org.sonar.core.qualityprofile.db.QualityProfileKey; import org.sonar.server.qualityprofile.index.ActiveRuleIndex; import org.sonar.server.rule.index.RuleQuery; import org.sonar.server.search.IndexClient; +import org.sonar.server.user.UserSession; import javax.annotation.CheckForNull; +import javax.annotation.Nullable; +import java.io.Reader; +import java.io.StringReader; +import java.io.StringWriter; +import java.io.Writer; import java.util.List; public class QProfileService implements ServerComponent { private final IndexClient index; private final RuleActivator ruleActivator; + private final QProfileBackuper backuper; - public QProfileService(IndexClient index, RuleActivator ruleActivator) { + public QProfileService(IndexClient index, RuleActivator ruleActivator, QProfileBackuper backuper) { this.index = index; this.ruleActivator = ruleActivator; + this.backuper = backuper; } @CheckForNull @@ -59,6 +68,7 @@ public class QProfileService implements ServerComponent { * activated. */ public List activate(RuleActivation activation) { + verifyAdminPermission(); return ruleActivator.activate(activation); } @@ -67,15 +77,89 @@ public class QProfileService implements ServerComponent { * fails (fast) if the rule or the profile does not exist. */ public List deactivate(ActiveRuleKey key) { + verifyAdminPermission(); return ruleActivator.deactivate(key); } public Multimap bulkActivate(RuleQuery ruleQuery, QualityProfileKey profile) { + verifyAdminPermission(); return ruleActivator.bulkActivate(ruleQuery, profile); } public Multimap bulkDeactivate(RuleQuery ruleQuery, QualityProfileKey profile) { + verifyAdminPermission(); return ruleActivator.bulkDeactivate(ruleQuery, profile); } + + public void backup(QualityProfileKey key, Writer writer) { + // Allowed to non-admin users (see http://jira.codehaus.org/browse/SONAR-2039) + backuper.backup(key, writer); + } + + /** + * @deprecated used only by Ruby on Rails. Use {@link #backup(org.sonar.core.qualityprofile.db.QualityProfileKey, java.io.Writer)} + */ + @Deprecated + public String backup(QualityProfileKey key) { + StringWriter output = new StringWriter(); + backup(key, output); + return output.toString(); + } + + public void restore(Reader backup) { + verifyAdminPermission(); + backuper.restore(backup); + } + + /** + * @deprecated used only by Ruby on Rails. Use {@link #restore(java.io.Reader)} + */ + @Deprecated + public void restore(String backup) { + restore(new StringReader(backup)); + } + + public void resetForLang(String lang) { + // TODO + verifyAdminPermission(); + } + + public void copy(QualityProfileKey key, String newName) { + // TODO + verifyAdminPermission(); + } + + public void delete(QualityProfileKey key) { + // TODO + verifyAdminPermission(); + } + + public void rename(QualityProfileKey key, String newName) { + // TODO + verifyAdminPermission(); + } + + //public void create(NewQualityProfile newProfile) { + // TODO + //verifyAdminPermission(); + //} + + public void setParent(QualityProfileKey key, @Nullable QualityProfileKey parent) { + // TODO + verifyAdminPermission(); + } + + /** + * Set the given quality profile as default for the related language + */ + public void setDefault(QualityProfileKey key) { + // TODO + verifyAdminPermission(); + } + + private void verifyAdminPermission() { + UserSession.get().checkLoggedIn(); + UserSession.get().checkGlobalPermission(GlobalPermissions.QUALITY_PROFILE_ADMIN); + } } diff --git a/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivationContext.java b/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivationContext.java index 687575078fc..25ba2e92a45 100644 --- a/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivationContext.java +++ b/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivationContext.java @@ -20,6 +20,7 @@ package org.sonar.server.qualityprofile; import com.google.common.collect.Maps; +import org.apache.commons.lang.StringUtils; import org.sonar.core.qualityprofile.db.ActiveRuleDto; import org.sonar.core.qualityprofile.db.ActiveRuleParamDto; import org.sonar.core.qualityprofile.db.QualityProfileDto; @@ -29,7 +30,6 @@ import org.sonar.core.rule.RuleParamDto; import javax.annotation.CheckForNull; import javax.annotation.Nullable; import java.util.Collection; -import java.util.HashMap; import java.util.Map; class RuleActivationContext { @@ -94,11 +94,6 @@ class RuleActivationContext { return this; } - @CheckForNull - ActiveRuleDto parentActiveRule() { - return parentActiveRule; - } - RuleActivationContext setParentActiveRule(@Nullable ActiveRuleDto a) { this.parentActiveRule = a; return this; @@ -109,9 +104,8 @@ class RuleActivationContext { return activeRuleParams; } - @CheckForNull Map parentActiveRuleParamsAsStringMap() { - Map params = new HashMap(); + Map params = Maps.newHashMap(); for (Map.Entry param : parentActiveRuleParams.entrySet()) { params.put(param.getKey(), param.getValue().getValue()); } @@ -159,4 +153,20 @@ class RuleActivationContext { } return ruleParam.getDefaultValue(); } + + /** + * True if trying to override an inherited rule but with exactly the same values + */ + boolean isSameAsParent(RuleActivation activation) { + if (parentActiveRule == null) { + return false; + } + if (activation.isReset()) { + return true; + } + if (StringUtils.equals(activation.getSeverity(), parentActiveRule.getSeverityString())) { + return Maps.difference(activation.getParameters(), parentActiveRuleParamsAsStringMap()).areEqual(); + } + return false; + } } diff --git a/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivationContextFactory.java b/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivationContextFactory.java index c4710af8171..5188850c22a 100644 --- a/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivationContextFactory.java +++ b/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivationContextFactory.java @@ -31,6 +31,7 @@ import org.sonar.core.qualityprofile.db.QualityProfileDto; import org.sonar.core.qualityprofile.db.QualityProfileKey; import org.sonar.core.rule.RuleDto; import org.sonar.server.db.DbClient; +import org.sonar.server.rule.Rule; import java.util.Collection; @@ -71,7 +72,10 @@ public class RuleActivationContextFactory implements ServerComponent { throw new IllegalArgumentException("Rule was removed: " + ruleKey); } if (Cardinality.MULTIPLE.equals(rule.getCardinality())) { - throw new IllegalArgumentException("A rule template can't be activated on a Quality profile: " + ruleKey); + throw new IllegalArgumentException("Rule template can't be activated on a Quality profile: " + ruleKey); + } + if (Rule.MANUAL_REPOSITORY_KEY.equals(rule.getRepositoryKey())) { + throw new IllegalArgumentException("Manual rule can't be activated on a Quality profile: " + ruleKey); } context.setRule(rule); context.setRuleParams(db.ruleDao().findRuleParamsByRuleKey(dbSession, rule.getKey())); diff --git a/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivator.java b/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivator.java index 19701f3d022..0f4b3bbd094 100644 --- a/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivator.java +++ b/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivator.java @@ -27,7 +27,6 @@ import com.google.common.collect.Multimap; import org.apache.commons.lang.StringUtils; import org.sonar.api.ServerComponent; import org.sonar.api.server.rule.RuleParamType; -import org.sonar.core.permission.GlobalPermissions; import org.sonar.core.persistence.DbSession; import org.sonar.core.preview.PreviewCache; import org.sonar.core.qualityprofile.db.ActiveRuleDto; @@ -40,12 +39,10 @@ import org.sonar.server.db.DbClient; import org.sonar.server.qualityprofile.db.ActiveRuleDao; import org.sonar.server.rule.Rule; import org.sonar.server.rule.index.RuleIndex; -import org.sonar.server.rule.index.RuleNormalizer; import org.sonar.server.rule.index.RuleQuery; import org.sonar.server.rule.index.RuleResult; import org.sonar.server.search.IndexClient; import org.sonar.server.search.QueryOptions; -import org.sonar.server.user.UserSession; import org.sonar.server.util.TypeValidations; import javax.annotation.Nullable; @@ -80,8 +77,7 @@ public class RuleActivator implements ServerComponent { * Activate a rule on a Quality profile. Update configuration (severity/parameters) if the rule is already * activated. */ - public List activate(RuleActivation activation) { - verifyPermission(UserSession.get()); + List activate(RuleActivation activation) { DbSession dbSession = db.openSession(false); try { List changes = activate(dbSession, activation); @@ -96,7 +92,7 @@ public class RuleActivator implements ServerComponent { } /** - * Activate the rule WITHOUT committing db session and WITHOUT checking permissions + * Activate the rule WITHOUT committing db session */ List activate(DbSession dbSession, RuleActivation activation) { @@ -107,7 +103,7 @@ public class RuleActivator implements ServerComponent { change = new ActiveRuleChange(ActiveRuleChange.Type.ACTIVATED, activation.getKey()); //Rules crated by default Inheritance - if (activation.isCascade()) { + if (activation.isCascade() || context.isSameAsParent(activation)) { change.setInheritance(ActiveRule.Inheritance.INHERITED); } } else { @@ -119,7 +115,7 @@ public class RuleActivator implements ServerComponent { //Updates on rule that exists with a valid parent switch them to OVERRIDE if (!activation.isCascade() && context.parentProfile() != null) { - change.setInheritance(activation.isReset() ? ActiveRule.Inheritance.INHERITED : ActiveRule.Inheritance.OVERRIDES); + change.setInheritance(context.isSameAsParent(activation) ? ActiveRule.Inheritance.INHERITED : ActiveRule.Inheritance.OVERRIDES); } } @@ -220,8 +216,7 @@ public class RuleActivator implements ServerComponent { * Deactivate a rule on a Quality profile. Does nothing if the rule is not activated, but * fails (fast) if the rule or the profile does not exist. */ - public List deactivate(ActiveRuleKey key) { - verifyPermission(UserSession.get()); + List deactivate(ActiveRuleKey key) { DbSession dbSession = db.openSession(false); List changes = Lists.newArrayList(); try { @@ -236,17 +231,18 @@ public class RuleActivator implements ServerComponent { /** * Deactivate a rule on a Quality profile WITHOUT committing db session and WITHOUT checking permissions */ - public List deactivate(ActiveRuleKey key, DbSession dbSession) { + List deactivate(ActiveRuleKey key, DbSession dbSession) { return cascadeDeactivation(key, dbSession, false); } private List cascadeDeactivation(ActiveRuleKey key, DbSession dbSession, boolean isCascade) { List changes = Lists.newArrayList(); RuleActivationContext context = contextFactory.create(key, dbSession); - ActiveRuleChange change = null; + ActiveRuleChange change; if (context.activeRule() == null) { return changes; - } else if (!isCascade && (context.activeRule().isInherited() || + } + if (!isCascade && (context.activeRule().isInherited() || context.activeRule().doesOverride())) { throw new IllegalStateException("Cannot deactivate inherited rule '" + key.ruleKey() + "'"); } @@ -268,11 +264,6 @@ public class RuleActivator implements ServerComponent { } - private void verifyPermission(UserSession userSession) { - userSession.checkLoggedIn(); - userSession.checkGlobalPermission(GlobalPermissions.QUALITY_PROFILE_ADMIN); - } - private void verifyParam(RuleParamDto ruleParam, @Nullable String value) { if (value != null) { RuleParamType ruleParamType = RuleParamType.parse(ruleParam.getType()); @@ -285,12 +276,7 @@ public class RuleActivator implements ServerComponent { } } - public Multimap bulkActivate(RuleQuery ruleQuery, QualityProfileKey profile) { - return bulkActivate(ruleQuery, profile, null); - } - - public Multimap bulkActivate(RuleQuery ruleQuery, QualityProfileKey profile, @Nullable String severity) { - verifyPermission(UserSession.get()); + Multimap bulkActivate(RuleQuery ruleQuery, QualityProfileKey profile) { RuleIndex ruleIndex = index.get(RuleIndex.class); Multimap results = ArrayListMultimap.create(); DbSession dbSession = db.openSession(false); @@ -326,8 +312,7 @@ public class RuleActivator implements ServerComponent { return results; } - public Multimap bulkDeactivate(RuleQuery ruleQuery, QualityProfileKey profile) { - verifyPermission(UserSession.get()); + Multimap bulkDeactivate(RuleQuery ruleQuery, QualityProfileKey profile) { RuleIndex ruleIndex = index.get(RuleIndex.class); Multimap results = ArrayListMultimap.create(); DbSession dbSession = db.openSession(false); diff --git a/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/BulkRuleActivationActions.java b/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/BulkRuleActivationActions.java index 750c094d3c5..c90473c652f 100644 --- a/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/BulkRuleActivationActions.java +++ b/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/BulkRuleActivationActions.java @@ -29,7 +29,6 @@ import org.sonar.api.server.ws.WebService; import org.sonar.api.utils.text.JsonWriter; import org.sonar.core.qualityprofile.db.QualityProfileKey; import org.sonar.server.qualityprofile.QProfileService; -import org.sonar.server.qualityprofile.RuleActivator; import org.sonar.server.rule.RuleService; import org.sonar.server.rule.ws.SearchAction; @@ -114,13 +113,13 @@ public class BulkRuleActivationActions implements ServerComponent { writeResponse(results, response); } - private void writeResponse(Multimap results, Response response){ + private void writeResponse(Multimap results, Response response) { JsonWriter json = response.newJsonWriter().beginObject(); - for(String action:results.keySet()){ + for (String action : results.keySet()) { json.name(action).beginArray(); - for(String key:results.get(action)){ + for (String key : results.get(action)) { json.beginObject() - .prop("key",key) + .prop("key", key) .endObject(); } json.endArray(); diff --git a/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ProfilesWs.java b/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ProfilesWs.java index 1baaccc40c3..b7eb98ccc5e 100644 --- a/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ProfilesWs.java +++ b/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ProfilesWs.java @@ -92,7 +92,6 @@ public class ProfilesWs implements WebService { action.createParam("name") .setDescription("Profile name. If not set, the default profile for the selected language is used") .setExampleValue("Sonar way"); - RailsHandler.addFormatParam(action); } private void defineRestoreAction(NewController controller) { @@ -105,7 +104,6 @@ public class ProfilesWs implements WebService { action.createParam("backup") .setRequired(true) .setDescription("Path to the file containing the backup (HTML format)"); - RailsHandler.addJsonOnlyFormatParam(action); } private void defineDestroyAction(NewController controller) { diff --git a/sonar-server/src/main/java/org/sonar/server/rule/RegisterRules.java b/sonar-server/src/main/java/org/sonar/server/rule/RegisterRules.java index 436759e135c..8846b04f764 100644 --- a/sonar-server/src/main/java/org/sonar/server/rule/RegisterRules.java +++ b/sonar-server/src/main/java/org/sonar/server/rule/RegisterRules.java @@ -41,7 +41,8 @@ import org.sonar.core.rule.RuleParamDto; import org.sonar.core.technicaldebt.db.CharacteristicDao; import org.sonar.core.technicaldebt.db.CharacteristicDto; import org.sonar.server.db.DbClient; -import org.sonar.server.qualityprofile.ProfilesManager; +import org.sonar.server.qualityprofile.ActiveRule; +import org.sonar.server.qualityprofile.QProfileService; import org.sonar.server.search.IndexDefinition; import org.sonar.server.search.action.EmbeddedIndexAction; import org.sonar.server.search.action.IndexAction; @@ -65,22 +66,22 @@ public class RegisterRules implements Startable { private static final Logger LOG = LoggerFactory.getLogger(RegisterRules.class); private final RuleDefinitionsLoader defLoader; - private final ProfilesManager profilesManager; + private final QProfileService profileService; private final DbClient dbClient; private final CharacteristicDao characteristicDao; - public RegisterRules(RuleDefinitionsLoader defLoader, ProfilesManager profilesManager, + public RegisterRules(RuleDefinitionsLoader defLoader, QProfileService profileService, DbClient dbClient) { - this(defLoader, profilesManager, dbClient, System2.INSTANCE); + this(defLoader, profileService, dbClient, System2.INSTANCE); } @VisibleForTesting - RegisterRules(RuleDefinitionsLoader defLoader, ProfilesManager profilesManager, + RegisterRules(RuleDefinitionsLoader defLoader, QProfileService profileService, DbClient dbClient, System2 system) { this.defLoader = defLoader; - this.profilesManager = profilesManager; + this.profileService = profileService; this.dbClient = dbClient; this.characteristicDao = dbClient.debtCharacteristicDao(); } @@ -395,7 +396,10 @@ public class RegisterRules implements Startable { for (RuleDto rule : removedRules) { // SONAR-4642 Remove active rules only when repository still exists if (repositoryKeys.contains(rule.getRepositoryKey())) { - profilesManager.removeActivatedRules(rule.getId()); + List activeRules = profileService.findActiveRulesByRule(rule.getKey()); + for (ActiveRule activeRule : activeRules) { + profileService.deactivate(activeRule.key()); + } } } } diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/api/profiles_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/api/profiles_controller.rb index c4781bf2f39..7a44ddd906a 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/api/profiles_controller.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/api/profiles_controller.rb @@ -135,8 +135,10 @@ class Api::ProfilesController < Api::ApiController else profile = Internal.quality_profiles.profile(params[:name], params[:language]) end - not_found('Profile not found') unless profile - backup = Internal.profile_backup.backupProfile(profile) + + profile_key=Java::OrgSonarCoreQualityprofileDb::QualityProfileKey.of(profile.name, profile.language) + backup = Internal.component(Java::OrgSonarServerQualityprofile::QProfileService.java_class).backup(profile_key) + respond_to do |format| format.xml { render :xml => backup } format.json { render :json => jsonp({:backup => backup}) } @@ -150,10 +152,12 @@ class Api::ProfilesController < Api::ApiController verify_post_request require_parameters :backup - result = Internal.profile_backup.restore(Api::Utils.read_post_request_param(params[:backup]), true) + backup = Api::Utils.read_post_request_param(params[:backup]) + Internal.component(Java::OrgSonarServerQualityprofile::QProfileService.java_class).restore(backup) respond_to do |format| - format.json { render :json => jsonp(validation_result_to_json(result)), :status => 200 } + #TODO format.json { render :json => jsonp(validation_result_to_json(result)), :status => 200 } + format.json { render :json => jsonp({}), :status => 200 } end end diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/profiles_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/profiles_controller.rb index aba0138c600..11dbb691da3 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/profiles_controller.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/profiles_controller.rb @@ -144,11 +144,11 @@ class ProfilesController < ApplicationController verify_post_request require_parameters 'id' - profile = Internal.quality_profiles.profile(params[:id].to_i) - not_found('Profile not found') unless profile - xml = Internal.profile_backup.backupProfile(profile) - filename = profile.name().gsub(' ', '_') - send_data(xml, :type => 'text/xml', :disposition => "attachment; filename=#{filename}_#{profile.language()}.xml") + profile_key=profile_id_to_key(params[:id].to_i) + + xml = Internal.component(Java::OrgSonarServerQualityprofile::QProfileService.java_class).backup(profile_key) + filename = profile_key.toString().gsub(' ', '_') + send_data(xml, :type => 'text/xml', :disposition => "attachment; filename=#{filename}.xml") end @@ -165,8 +165,9 @@ class ProfilesController < ApplicationController flash[:warning] = message('quality_profiles.please_upload_backup_file') else call_backend do - result = Internal.profile_backup.restore(Api::Utils.read_post_request_param(params[:backup]), false) - flash_result(result) + xml=Api::Utils.read_post_request_param(params[:backup]) + Internal.component(Java::OrgSonarServerQualityprofile::QProfileService.java_class).restore(xml) + #flash_result(result) end end redirect_to :action => 'index' @@ -551,4 +552,10 @@ class ProfilesController < ApplicationController def set_profile_breadcrumbs add_breadcrumbs ProfilesController::root_breadcrumb, Api::Utils.language_name(@profile.language), {:name => @profile.name, :url => {:controller => 'rules_configuration', :action => 'index', :id => @profile.id}} end + + def profile_id_to_key(profile_id) + profile = Profile.find(profile_id) + not_found('Profile not found') unless profile + Java::OrgSonarCoreQualityprofileDb::QualityProfileKey.of(profile.name, profile.language) + end end diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/internal.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/internal.rb index c4091a7798b..a0a74561c59 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/models/internal.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/models/internal.rb @@ -90,8 +90,6 @@ class Internal component(Java::OrgSonarServerUi::JRubyI18n.java_class) end - private - def self.component(component_java_class) Java::OrgSonarServerPlatform::Platform.component(component_java_class) end diff --git a/sonar-server/src/test/java/org/sonar/server/qualityprofile/ProfilesManagerTest.java b/sonar-server/src/test/java/org/sonar/server/qualityprofile/ProfilesManagerTest.java index 9d82a650a78..c201dbc64eb 100644 --- a/sonar-server/src/test/java/org/sonar/server/qualityprofile/ProfilesManagerTest.java +++ b/sonar-server/src/test/java/org/sonar/server/qualityprofile/ProfilesManagerTest.java @@ -20,15 +20,9 @@ package org.sonar.server.qualityprofile; import org.junit.Before; -import org.junit.Test; -import org.sonar.api.profiles.RulesProfile; -import org.sonar.api.rules.ActiveRule; -import org.sonar.api.rules.Rule; -import org.sonar.api.rules.RulePriority; import org.sonar.core.preview.PreviewCache; import org.sonar.jpa.test.AbstractDbUnitTestCase; -import static org.fest.assertions.Assertions.assertThat; import static org.mockito.Mockito.mock; public class ProfilesManagerTest extends AbstractDbUnitTestCase { @@ -40,21 +34,4 @@ public class ProfilesManagerTest extends AbstractDbUnitTestCase { manager = new ProfilesManager(getSession(), null, mock(PreviewCache.class)); } - @Test - public void remove_activated_rules() { - Rule rule1 = Rule.create("repo", "key"); - - RulesProfile profile1 = RulesProfile.create("profile1", "xoo"); - ActiveRule activeRule1 = new ActiveRule(profile1, rule1, RulePriority.BLOCKER); - - RulesProfile profile2 = RulesProfile.create("profile2", "foo"); - ActiveRule activeRule2 = new ActiveRule(profile2, rule1, RulePriority.BLOCKER); - - getSession().save(profile1, rule1, activeRule1, profile2, activeRule2); - - manager.removeActivatedRules(rule1.getId()); - - assertThat(getHQLCount(ActiveRule.class)).isEqualTo(0); - } - } 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 5e9effdcab6..27f77ac8cd7 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 @@ -24,14 +24,9 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.invocation.InvocationOnMock; import org.mockito.runners.MockitoJUnitRunner; -import org.mockito.stubbing.Answer; -import org.sonar.api.database.DatabaseSession; import org.sonar.api.profiles.ProfileDefinition; import org.sonar.api.profiles.RulesProfile; -import org.sonar.api.profiles.XMLProfileParser; -import org.sonar.api.profiles.XMLProfileSerializer; import org.sonar.api.rule.RuleKey; import org.sonar.api.rules.ActiveRule; import org.sonar.api.rules.Rule; @@ -44,16 +39,11 @@ import org.sonar.core.preview.PreviewCache; import org.sonar.core.qualityprofile.db.ActiveRuleDto; import org.sonar.core.qualityprofile.db.QualityProfileKey; 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.rule.db.RuleDao; import org.sonar.server.user.MockUserSession; import org.sonar.server.user.UserSession; -import java.io.Reader; -import java.io.Writer; import java.util.Collection; import java.util.List; @@ -61,40 +51,18 @@ import static com.google.common.collect.Lists.newArrayList; import static org.fest.assertions.Assertions.assertThat; 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 { - @Mock - DatabaseSessionFactory sessionFactory; - - @Mock - DatabaseSession hibernateSession; - @Mock MyBatis myBatis; @Mock DbSession session; - @Mock - XMLProfileParser xmlProfileParser; - - @Mock - XMLProfileSerializer xmlProfileSerializer; - - @Mock - QProfileLookup qProfileLookup; - @Mock QProfileOperations qProfileOperations; @@ -116,191 +84,15 @@ public class QProfileBackupTest { @Before public void setUp() throws Exception { when(myBatis.openSession(false)).thenReturn(session); - when(sessionFactory.getSession()).thenReturn(hibernateSession); definitions = newArrayList(); - backup = new QProfileBackup(sessionFactory, xmlProfileParser, xmlProfileSerializer, myBatis, qProfileLookup, qProfileOperations, qProfileActiveRuleOperations, ruleDao, + backup = new QProfileBackup(myBatis, qProfileOperations, qProfileActiveRuleOperations, ruleDao, definitions, defaultProfilesCache, dryRunCache); MockUserSession.set().setLogin("nicolas").setName("Nicolas").setGlobalPermissions(GlobalPermissions.QUALITY_PROFILE_ADMIN); } - @Test - public void backup() throws Exception { - RulesProfile profile = mock(RulesProfile.class); - when(profile.getId()).thenReturn(1); - when(hibernateSession.getSingleResult(any(Class.class), eq("id"), eq(1))).thenReturn(profile); - - backup.backupProfile(new QProfile().setId(1)); - - verify(xmlProfileSerializer).write(eq(profile), any(Writer.class)); - } - - @Test - public void restore() throws Exception { - RulesProfile profile = mock(RulesProfile.class); - when(profile.getName()).thenReturn("Default"); - when(profile.getLanguage()).thenReturn("java"); - when(profile.getId()).thenReturn(1); - when(xmlProfileParser.parse(any(Reader.class), any(ValidationMessages.class))).thenReturn(profile); - when(hibernateSession.getSingleResult(any(Class.class), eq("name"), eq("Default"), eq("language"), eq("java"))).thenReturn(null); - when(qProfileLookup.profile(anyInt(), eq(session))).thenReturn(new QProfile().setId(1)); - - QProfileResult result = backup.restore("", false); - - assertThat(result.profile()).isNotNull(); - verify(hibernateSession).saveWithoutFlush(profile); - verify(dryRunCache).reportGlobalModification(session); - verify(session).commit(); - } - - @Test - public void fail_to_restore_without_profile_admin_permission() throws Exception { - try { - MockUserSession.set().setLogin("nicolas").setName("Nicolas"); - backup.restore("", false); - fail(); - } catch (Exception e) { - assertThat(e).isInstanceOf(ForbiddenException.class); - } - verify(hibernateSession, never()).saveWithoutFlush(any(RulesProfile.class)); - verifyZeroInteractions(dryRunCache); - } - - @Test - public void fail_to_restore_if_profile_already_exist() throws Exception { - RulesProfile profile = mock(RulesProfile.class); - when(profile.getName()).thenReturn("Default"); - when(profile.getLanguage()).thenReturn("java"); - when(xmlProfileParser.parse(any(Reader.class), any(ValidationMessages.class))).thenReturn(profile); - when(hibernateSession.getSingleResult(any(Class.class), eq("name"), eq("Default"), eq("language"), eq("java"))).thenReturn(RulesProfile.create("Default", "java")); - when(qProfileLookup.profile(anyInt())).thenReturn(new QProfile().setId(1)); - - try { - backup.restore("", false); - fail(); - } catch (Exception e) { - assertThat(e).isInstanceOf(BadRequestException.class).hasMessage("The profile [name=Default,language=java] already exists. Please delete it before restoring."); - } - - verify(hibernateSession, never()).saveWithoutFlush(any(RulesProfile.class)); - verifyZeroInteractions(dryRunCache); - } - - @Test - public void restore_should_delete_existing_profile() throws Exception { - RulesProfile profile = mock(RulesProfile.class); - when(profile.getName()).thenReturn("Default"); - when(profile.getLanguage()).thenReturn("java"); - when(profile.getId()).thenReturn(1); - when(xmlProfileParser.parse(any(Reader.class), any(ValidationMessages.class))).thenReturn(profile); - - RulesProfile existingProfile = mock(RulesProfile.class); - when(existingProfile.getId()).thenReturn(1); - when(hibernateSession.getSingleResult(any(Class.class), eq("name"), eq("Default"), eq("language"), eq("java"))).thenReturn(existingProfile); - when(qProfileLookup.profile(anyInt(), eq(session))).thenReturn(new QProfile().setId(1)); - - QProfileResult result = backup.restore("", true); - - assertThat(result.profile()).isNotNull(); - verify(hibernateSession).removeWithoutFlush(eq(existingProfile)); - verify(dryRunCache).reportGlobalModification(session); - verify(session).commit(); - } - - @Test - public void restore_should_add_warnings_and_infos_from_xml_parsing() throws Exception { - final RulesProfile profile = mock(RulesProfile.class); - when(profile.getName()).thenReturn("Default"); - when(profile.getLanguage()).thenReturn("java"); - when(profile.getId()).thenReturn(1); - doAnswer(new Answer() { - public Object answer(InvocationOnMock invocation) { - Object[] args = invocation.getArguments(); - ValidationMessages validationMessages = (ValidationMessages) args[1]; - validationMessages.addInfoText("an info message"); - validationMessages.addWarningText("a warning message"); - return profile; - } - }).when(xmlProfileParser).parse(any(Reader.class), any(ValidationMessages.class)); - - when(hibernateSession.getSingleResult(any(Class.class), eq("name"), eq("Default"), eq("language"), eq("java"))).thenReturn(null); - when(qProfileLookup.profile(anyInt(), eq(session))).thenReturn(new QProfile().setId(1)); - - QProfileResult result = backup.restore("", true); - - assertThat(result.profile()).isNotNull(); - assertThat(result.warnings()).isNotEmpty(); - assertThat(result.infos()).isNotEmpty(); - } - - @Test - public void restore_should_fail_if_errors_when_parsing_xml() throws Exception { - final RulesProfile profile = mock(RulesProfile.class); - when(profile.getName()).thenReturn("Default"); - when(profile.getLanguage()).thenReturn("java"); - when(profile.getId()).thenReturn(1); - doAnswer(new Answer() { - public Object answer(InvocationOnMock invocation) { - Object[] args = invocation.getArguments(); - ValidationMessages validationMessages = (ValidationMessages) args[1]; - validationMessages.addErrorText("error!"); - return profile; - } - }).when(xmlProfileParser).parse(any(Reader.class), any(ValidationMessages.class)); - - when(hibernateSession.getSingleResult(any(Class.class), eq("name"), eq("Default"), eq("language"), eq("java"))).thenReturn(null); - when(qProfileLookup.profile(anyInt(), eq(session))).thenReturn(new QProfile().setId(1)); - - try { - backup.restore("", false); - fail(); - } catch (Exception e) { - assertThat(e).isInstanceOf(BadRequestException.class).hasMessage("Fail to restore profile"); - BadRequestException badRequestException = (BadRequestException) e; - assertThat(badRequestException.errors()).hasSize(1); - assertThat(badRequestException.errors().get(0).text()).isEqualTo("error!"); - } - - verify(hibernateSession, never()).saveWithoutFlush(any(RulesProfile.class)); - verifyZeroInteractions(dryRunCache); - } - - @Test - public void do_not_restore_if_xml_is_empty() throws Exception { - when(xmlProfileParser.parse(any(Reader.class), any(ValidationMessages.class))).thenReturn(null); - when(hibernateSession.getSingleResult(any(Class.class), eq("name"), eq("Default"), eq("language"), eq("java"))).thenReturn(null); - when(qProfileLookup.profile(anyInt(), eq(session))).thenReturn(new QProfile().setId(1)); - - QProfileResult result = backup.restore("", false); - - assertThat(result.profile()).isNull(); - verify(hibernateSession, never()).saveWithoutFlush(any(RulesProfile.class)); - verifyZeroInteractions(dryRunCache); - } - - @Test - public void do_not_restore_if_new_profile_is_null_after_import() throws Exception { - RulesProfile profile = mock(RulesProfile.class); - when(profile.getName()).thenReturn("Default"); - when(profile.getLanguage()).thenReturn("java"); - when(profile.getId()).thenReturn(1); - when(xmlProfileParser.parse(any(Reader.class), any(ValidationMessages.class))).thenReturn(profile); - - when(hibernateSession.getSingleResult(any(Class.class), eq("name"), eq("Default"), eq("language"), eq("java"))).thenReturn(null); - when(qProfileLookup.profile(anyInt(), eq(session))).thenReturn(null); - - try { - backup.restore("", false); - fail(); - } catch (Exception e) { - assertThat(e).isInstanceOf(BadRequestException.class).hasMessage("Restore of the profile has failed."); - } - - verifyZeroInteractions(dryRunCache); - } - @Test public void recreate_built_in_profiles_from_language() throws Exception { String name = "Default"; diff --git a/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileBackuperMediumTest.java b/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileBackuperMediumTest.java new file mode 100644 index 00000000000..bae892c59f7 --- /dev/null +++ b/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileBackuperMediumTest.java @@ -0,0 +1,263 @@ +/* + * 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.base.Charsets; +import com.google.common.io.Resources; +import org.custommonkey.xmlunit.Diff; +import org.custommonkey.xmlunit.XMLUnit; +import org.junit.After; +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Test; +import org.sonar.api.rule.RuleKey; +import org.sonar.api.rule.Severity; +import org.sonar.api.server.rule.RuleParamType; +import org.sonar.core.persistence.DbSession; +import org.sonar.core.qualityprofile.db.ActiveRuleKey; +import org.sonar.core.qualityprofile.db.QualityProfileDto; +import org.sonar.core.qualityprofile.db.QualityProfileKey; +import org.sonar.core.rule.RuleDto; +import org.sonar.core.rule.RuleParamDto; +import org.sonar.server.db.DbClient; +import org.sonar.server.rule.RuleTesting; +import org.sonar.server.tester.ServerTester; + +import javax.xml.stream.XMLStreamException; +import java.io.StringReader; +import java.io.StringWriter; +import java.util.List; + +import static org.fest.assertions.Assertions.assertThat; +import static org.fest.assertions.Fail.fail; + +public class QProfileBackuperMediumTest { + + static final QualityProfileKey XOO_PROFILE_KEY = QualityProfileKey.of("P1", "xoo"); + static final QualityProfileKey XOO_CHILD_PROFILE_KEY = QualityProfileKey.of("P2", "xoo"); + + @ClassRule + public static ServerTester tester = new ServerTester(); + + DbClient db; + DbSession dbSession; + + @Before + public void before() { + tester.clearDbAndIndexes(); + db = tester.get(DbClient.class); + dbSession = db.openSession(false); + + // create pre-defined rules + RuleDto xooRule1 = RuleTesting.newDto(RuleKey.of("xoo", "x1")) + .setSeverity("MINOR").setLanguage("xoo"); + RuleDto xooRule2 = RuleTesting.newDto(RuleKey.of("xoo", "x2")) + .setSeverity("MAJOR").setLanguage("xoo"); + db.ruleDao().insert(dbSession, xooRule1, xooRule2); + db.ruleDao().addRuleParam(dbSession, xooRule1, RuleParamDto.createFor(xooRule1) + .setName("max").setDefaultValue("10").setType(RuleParamType.INTEGER.type())); + dbSession.commit(); + dbSession.clearCache(); + } + + @After + public void after() throws Exception { + dbSession.close(); + } + + @Test + public void backup() throws Exception { + // create profile with rule x1 activated + db.qualityProfileDao().insert(dbSession, QualityProfileDto.createFor(XOO_PROFILE_KEY)); + RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, RuleKey.of("xoo", "x1"))); + activation.setSeverity(Severity.BLOCKER); + activation.setParameter("max", "7"); + tester.get(RuleActivator.class).activate(dbSession, activation); + dbSession.commit(); + dbSession.clearCache(); + + StringWriter output = new StringWriter(); + tester.get(QProfileBackuper.class).backup(XOO_PROFILE_KEY, output); + + XMLUnit.setIgnoreWhitespace(true); + Diff diff = XMLUnit.compareXML(output.toString(), + Resources.toString(getClass().getResource("QProfileBackuperMediumTest/expected-backup.xml"), Charsets.UTF_8)); + + assertThat(diff.identical()).as(diff.toString()).isTrue(); + } + + @Test + public void fail_to_backup_unknown_profile() throws Exception { + try { + tester.get(QProfileBackuper.class).backup(QualityProfileKey.of("unknown", "xoo"), new StringWriter()); + fail(); + } catch (IllegalArgumentException e) { + assertThat(e).hasMessage("Quality profile does not exist: unknown:xoo"); + } + } + + @Test + public void restore_and_create_profile() throws Exception { + tester.get(QProfileBackuper.class).restore(new StringReader( + Resources.toString(getClass().getResource("QProfileBackuperMediumTest/restore.xml"), Charsets.UTF_8))); + + List activeRules = tester.get(QProfileService.class).findActiveRulesByProfile(XOO_PROFILE_KEY); + assertThat(activeRules).hasSize(1); + assertThat(activeRules.get(0).severity()).isEqualTo("BLOCKER"); + assertThat(activeRules.get(0).inheritance()).isEqualTo(ActiveRule.Inheritance.NONE); + assertThat(activeRules.get(0).params().get("max")).isEqualTo("7"); + } + + @Test + public void restore_and_update_profile() throws Exception { + // create profile with rules x1 and x2 activated + db.qualityProfileDao().insert(dbSession, QualityProfileDto.createFor(XOO_PROFILE_KEY)); + RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, RuleKey.of("xoo", "x1"))); + activation.setSeverity(Severity.INFO); + activation.setParameter("max", "10"); + tester.get(RuleActivator.class).activate(dbSession, activation); + + activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, RuleKey.of("xoo", "x2"))); + activation.setSeverity(Severity.INFO); + tester.get(RuleActivator.class).activate(dbSession, activation); + dbSession.commit(); + dbSession.clearCache(); + + // restore backup, which activates only x1 + // -> update x1 and deactivate x2 + tester.get(QProfileBackuper.class).restore(new StringReader( + Resources.toString(getClass().getResource("QProfileBackuperMediumTest/restore.xml"), Charsets.UTF_8))); + + + List activeRules = tester.get(QProfileService.class).findActiveRulesByProfile(XOO_PROFILE_KEY); + assertThat(activeRules).hasSize(1); + assertThat(activeRules.get(0).severity()).isEqualTo("BLOCKER"); + assertThat(activeRules.get(0).inheritance()).isEqualTo(ActiveRule.Inheritance.NONE); + assertThat(activeRules.get(0).params().get("max")).isEqualTo("7"); + } + + @Test + public void restore_child_profile() throws Exception { + // define two parent/child profiles + db.qualityProfileDao().insert(dbSession, + QualityProfileDto.createFor(XOO_PROFILE_KEY), + QualityProfileDto.createFor(XOO_CHILD_PROFILE_KEY).setParent(XOO_PROFILE_KEY.name())); + dbSession.commit(); + + // rule x1 is activated on parent profile (so inherited by child profile) + RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, RuleKey.of("xoo", "x1"))); + activation.setSeverity(Severity.INFO); + activation.setParameter("max", "10"); + tester.get(RuleActivator.class).activate(dbSession, activation); + dbSession.commit(); + dbSession.clearCache(); + + // restore backup of child profile -> overrides x1 + tester.get(QProfileBackuper.class).restore(new StringReader( + Resources.toString(getClass().getResource("QProfileBackuperMediumTest/restore-child.xml"), Charsets.UTF_8))); + + // parent profile is unchanged + List activeRules = tester.get(QProfileService.class).findActiveRulesByProfile(XOO_PROFILE_KEY); + assertThat(activeRules).hasSize(1); + assertThat(activeRules.get(0).severity()).isEqualTo("INFO"); + assertThat(activeRules.get(0).inheritance()).isEqualTo(ActiveRule.Inheritance.NONE); + assertThat(activeRules.get(0).params().get("max")).isEqualTo("10"); + + // child profile overrides parent + activeRules = tester.get(QProfileService.class).findActiveRulesByProfile(XOO_CHILD_PROFILE_KEY); + assertThat(activeRules).hasSize(1); + assertThat(activeRules.get(0).severity()).isEqualTo("BLOCKER"); + assertThat(activeRules.get(0).inheritance()).isEqualTo(ActiveRule.Inheritance.OVERRIDES); + assertThat(activeRules.get(0).params().get("max")).isEqualTo("7"); + } + + @Test + public void restore_parent_profile() throws Exception { + // define two parent/child profiles + db.qualityProfileDao().insert(dbSession, + QualityProfileDto.createFor(XOO_PROFILE_KEY), + QualityProfileDto.createFor(XOO_CHILD_PROFILE_KEY).setParent(XOO_PROFILE_KEY.name())); + dbSession.commit(); + + // rule x1 is activated on parent profile (so inherited by child profile) + RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, RuleKey.of("xoo", "x1"))); + activation.setSeverity(Severity.INFO); + activation.setParameter("max", "10"); + tester.get(RuleActivator.class).activate(dbSession, activation); + dbSession.commit(); + dbSession.clearCache(); + + // restore backup of parent profile -> update x1 and propagates to child + tester.get(QProfileBackuper.class).restore(new StringReader( + Resources.toString(getClass().getResource("QProfileBackuperMediumTest/restore-parent.xml"), Charsets.UTF_8))); + + // parent profile is updated + List activeRules = tester.get(QProfileService.class).findActiveRulesByProfile(XOO_PROFILE_KEY); + assertThat(activeRules).hasSize(1); + assertThat(activeRules.get(0).severity()).isEqualTo("BLOCKER"); + assertThat(activeRules.get(0).inheritance()).isEqualTo(ActiveRule.Inheritance.NONE); + assertThat(activeRules.get(0).params().get("max")).isEqualTo("7"); + + // child profile is inherited + activeRules = tester.get(QProfileService.class).findActiveRulesByProfile(XOO_CHILD_PROFILE_KEY); + assertThat(activeRules).hasSize(1); + assertThat(activeRules.get(0).severity()).isEqualTo("BLOCKER"); + assertThat(activeRules.get(0).inheritance()).isEqualTo(ActiveRule.Inheritance.INHERITED); + assertThat(activeRules.get(0).params().get("max")).isEqualTo("7"); + } + + @Test + public void restore_fails_to_deactivate_inherited_rule() throws Exception { + // define two parent/child profiles + db.qualityProfileDao().insert(dbSession, + QualityProfileDto.createFor(XOO_PROFILE_KEY), + QualityProfileDto.createFor(XOO_CHILD_PROFILE_KEY).setParent(XOO_PROFILE_KEY.name())); + dbSession.commit(); + + // rule x1 is activated on parent profile (so inherited by child profile) + RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, RuleKey.of("xoo", "x1"))); + activation.setSeverity(Severity.INFO); + activation.setParameter("max", "10"); + tester.get(RuleActivator.class).activate(dbSession, activation); + dbSession.commit(); + dbSession.clearCache(); + + // backup of child profile does not contain x1 + try { + tester.get(QProfileBackuper.class).restore(new StringReader( + Resources.toString(getClass().getResource("QProfileBackuperMediumTest/restore_fails_to_deactivate_inherited_rule.xml"), Charsets.UTF_8))); + fail(); + } catch (IllegalStateException e) { + assertThat(e).hasMessage("Cannot deactivate inherited rule 'xoo:x1'"); + } + } + + @Test + public void fail_to_restore_if_not_xml_backup() throws Exception { + try { + tester.get(QProfileBackuper.class).restore(new StringReader( + Resources.toString(getClass().getResource("QProfileBackuperMediumTest/not-xml-backup.txt"), Charsets.UTF_8))); + fail(); + } catch (IllegalStateException e) { + assertThat(e).hasMessage("Fail to restore Quality profile backup"); + assertThat(e.getCause()).isInstanceOf(XMLStreamException.class); + } + } +} diff --git a/sonar-server/src/test/java/org/sonar/server/qualityprofile/RuleActivatorMediumTest.java b/sonar-server/src/test/java/org/sonar/server/qualityprofile/RuleActivatorMediumTest.java index 23956e86477..d50466f20a3 100644 --- a/sonar-server/src/test/java/org/sonar/server/qualityprofile/RuleActivatorMediumTest.java +++ b/sonar-server/src/test/java/org/sonar/server/qualityprofile/RuleActivatorMediumTest.java @@ -25,10 +25,10 @@ import org.junit.Before; import org.junit.ClassRule; import org.junit.Test; import org.sonar.api.rule.RuleKey; +import org.sonar.api.rule.RuleStatus; import org.sonar.api.rule.Severity; import org.sonar.api.server.rule.RuleParamType; import org.sonar.check.Cardinality; -import org.sonar.core.permission.GlobalPermissions; import org.sonar.core.persistence.DbSession; import org.sonar.core.qualityprofile.db.ActiveRuleDto; import org.sonar.core.qualityprofile.db.ActiveRuleKey; @@ -39,11 +39,10 @@ import org.sonar.core.rule.RuleDto; import org.sonar.core.rule.RuleParamDto; import org.sonar.server.db.DbClient; import org.sonar.server.exceptions.BadRequestException; -import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.qualityprofile.index.ActiveRuleIndex; +import org.sonar.server.rule.Rule; import org.sonar.server.rule.RuleTesting; import org.sonar.server.tester.ServerTester; -import org.sonar.server.user.MockUserSession; import javax.annotation.Nullable; import java.util.List; @@ -57,6 +56,8 @@ public class RuleActivatorMediumTest { static final QualityProfileKey XOO_PROFILE_KEY = QualityProfileKey.of("P1", "xoo"); static final QualityProfileKey XOO_CHILD_PROFILE_KEY = QualityProfileKey.of("P2", "xoo"); static final QualityProfileKey XOO_GRAND_CHILD_PROFILE_KEY = QualityProfileKey.of("P3", "xoo"); + static final RuleKey MANUAL_RULE_KEY = RuleKey.of(Rule.MANUAL_REPOSITORY_KEY, "m1"); + static final RuleKey XOO_RULE_1 = RuleKey.of("xoo", "x1"); @ClassRule public static ServerTester tester = new ServerTester(); @@ -77,11 +78,12 @@ public class RuleActivatorMediumTest { // create pre-defined rules RuleDto javaRule = RuleTesting.newDto(RuleKey.of("squid", "j1")) .setSeverity("MAJOR").setLanguage("java"); - RuleDto xooRule1 = RuleTesting.newDto(RuleKey.of("xoo", "x1")) + RuleDto xooRule1 = RuleTesting.newDto(XOO_RULE_1) .setSeverity("MINOR").setLanguage("xoo"); RuleDto xooTemplateRule1 = RuleTesting.newDto(RuleKey.of("xoo", "template1")) .setSeverity("MINOR").setLanguage("xoo").setCardinality(Cardinality.MULTIPLE); - db.ruleDao().insert(dbSession, javaRule, xooRule1, xooTemplateRule1); + RuleDto manualRule = RuleTesting.newDto(MANUAL_RULE_KEY); + db.ruleDao().insert(dbSession, javaRule, xooRule1, xooTemplateRule1, manualRule); db.ruleDao().addRuleParam(dbSession, xooRule1, RuleParamDto.createFor(xooRule1) .setName("max").setDefaultValue("10").setType(RuleParamType.INTEGER.type())); @@ -99,9 +101,7 @@ public class RuleActivatorMediumTest { @Test public void activate() throws Exception { - grantPermission(); - - RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, RuleKey.of("xoo", "x1"))); + RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, XOO_RULE_1)); activation.setSeverity(Severity.BLOCKER); activation.setParameter("max", "7"); ruleActivator.activate(activation); @@ -111,8 +111,16 @@ public class RuleActivatorMediumTest { @Test public void activate_with_default_severity_and_parameter() throws Exception { - grantPermission(); - RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, RuleKey.of("xoo", "x1"))); + RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, XOO_RULE_1)); + ruleActivator.activate(activation); + + verifyOneActiveRule(XOO_PROFILE_KEY, Severity.MINOR, null, ImmutableMap.of("max", "10")); + } + + @Test + public void activation_ignores_unsupported_parameters() throws Exception { + RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, XOO_RULE_1)); + activation.setParameter("xxx", "yyy"); ruleActivator.activate(activation); verifyOneActiveRule(XOO_PROFILE_KEY, Severity.MINOR, null, ImmutableMap.of("max", "10")); @@ -121,13 +129,12 @@ public class RuleActivatorMediumTest { @Test public void update_activation_severity_and_parameters() throws Exception { // initial activation - grantPermission(); - RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, RuleKey.of("xoo", "x1"))); + RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, XOO_RULE_1)); activation.setSeverity(Severity.BLOCKER); ruleActivator.activate(activation); // update - RuleActivation update = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, RuleKey.of("xoo", "x1"))); + RuleActivation update = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, XOO_RULE_1)); update.setSeverity(Severity.CRITICAL); update.setParameter("max", "42"); ruleActivator.activate(update); @@ -138,8 +145,7 @@ public class RuleActivatorMediumTest { @Test public void update_activation_but_new_parameter() throws Exception { // initial activation - grantPermission(); - ActiveRuleKey activeRuleKey = ActiveRuleKey.of(XOO_PROFILE_KEY, RuleKey.of("xoo", "x1")); + ActiveRuleKey activeRuleKey = ActiveRuleKey.of(XOO_PROFILE_KEY, XOO_RULE_1); RuleActivation activation = new RuleActivation(activeRuleKey); activation.setSeverity(Severity.BLOCKER); ruleActivator.activate(activation); @@ -152,7 +158,7 @@ public class RuleActivatorMediumTest { dbSession.clearCache(); // update - RuleActivation update = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, RuleKey.of("xoo", "x1"))); + RuleActivation update = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, XOO_RULE_1)); update.setSeverity(Severity.CRITICAL); update.setParameter("max", "42"); // contrary to activerule, the param 'max' is supposed to be inserted but not updated @@ -164,42 +170,27 @@ public class RuleActivatorMediumTest { @Test public void revert_activation_to_default_severity_and_parameters() throws Exception { // initial activation - grantPermission(); - RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, RuleKey.of("xoo", "x1"))); + RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, XOO_RULE_1)); activation.setSeverity(Severity.BLOCKER); activation.setParameter("max", "7"); ruleActivator.activate(activation); // update - RuleActivation update = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, RuleKey.of("xoo", "x1"))); + RuleActivation update = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, XOO_RULE_1)); ruleActivator.activate(update); verifyOneActiveRule(XOO_PROFILE_KEY, Severity.MINOR, null, ImmutableMap.of("max", "10")); } - @Test - public void fail_to_activate_if_not_granted() throws Exception { - MockUserSession.set().setLogin("marius"); - RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, RuleKey.of("xoo", "x1"))); - - try { - ruleActivator.activate(activation); - fail(); - } catch (ForbiddenException e) { - verifyZeroActiveRules(XOO_PROFILE_KEY); - } - } - @Test public void fail_to_activate_if_template() throws Exception { - grantPermission(); RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, RuleKey.of("xoo", "template1"))); try { ruleActivator.activate(activation); fail(); } catch (IllegalArgumentException e) { - assertThat(e).hasMessage("A rule template can't be activated on a Quality profile: xoo:template1"); + assertThat(e).hasMessage("Rule template can't be activated on a Quality profile: xoo:template1"); verifyZeroActiveRules(XOO_PROFILE_KEY); } } @@ -207,7 +198,6 @@ public class RuleActivatorMediumTest { @Test public void fail_to_activate_if_different_languages() throws Exception { // profile and rule have different languages - grantPermission(); RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, RuleKey.of("squid", "j1"))); try { @@ -222,7 +212,6 @@ public class RuleActivatorMediumTest { @Test public void fail_to_activate_if_unknown_rule() throws Exception { // profile and rule have different languages - grantPermission(); RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, RuleKey.of("xoo", "x3"))); try { @@ -234,11 +223,42 @@ public class RuleActivatorMediumTest { } } + @Test + public void fail_to_activate_if_rule_with_removed_status() throws Exception { + RuleDto ruleDto = db.ruleDao().getByKey(dbSession, XOO_RULE_1); + ruleDto.setStatus(RuleStatus.REMOVED); + db.ruleDao().update(dbSession, ruleDto); + dbSession.commit(); + dbSession.clearCache(); + + RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, XOO_RULE_1)); + + try { + ruleActivator.activate(activation); + fail(); + } catch (IllegalArgumentException e) { + assertThat(e).hasMessage("Rule was removed: xoo:x1"); + verifyZeroActiveRules(XOO_PROFILE_KEY); + } + } + + @Test + public void fail_to_activate_if_manual_rule() throws Exception { + RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, MANUAL_RULE_KEY)); + + try { + ruleActivator.activate(activation); + fail(); + } catch (IllegalArgumentException e) { + assertThat(e).hasMessage("Manual rule can't be activated on a Quality profile: manual:m1"); + verifyZeroActiveRules(XOO_PROFILE_KEY); + } + } + @Test public void fail_to_activate_if_unknown_profile() throws Exception { // profile and rule have different languages - grantPermission(); - RuleActivation activation = new RuleActivation(ActiveRuleKey.of(QualityProfileKey.of("other", "js"), RuleKey.of("xoo", "x1"))); + RuleActivation activation = new RuleActivation(ActiveRuleKey.of(QualityProfileKey.of("other", "js"), XOO_RULE_1)); try { ruleActivator.activate(activation); @@ -250,8 +270,7 @@ public class RuleActivatorMediumTest { @Test public void fail_to_activate_if_invalid_parameter() throws Exception { - grantPermission(); - RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, RuleKey.of("xoo", "x1"))); + RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, XOO_RULE_1)); activation.setParameter("max", "foo"); try { @@ -266,8 +285,7 @@ public class RuleActivatorMediumTest { @Test public void deactivate() throws Exception { // activation - grantPermission(); - ActiveRuleKey key = ActiveRuleKey.of(XOO_PROFILE_KEY, RuleKey.of("xoo", "x1")); + ActiveRuleKey key = ActiveRuleKey.of(XOO_PROFILE_KEY, XOO_RULE_1); RuleActivation activation = new RuleActivation(key); activation.setSeverity(Severity.BLOCKER); activation.setParameter("max", "7"); @@ -281,10 +299,8 @@ public class RuleActivatorMediumTest { @Test public void ignore_deactivation_if_rule_not_activated() throws Exception { - grantPermission(); - // deactivation - ActiveRuleKey key = ActiveRuleKey.of(XOO_PROFILE_KEY, RuleKey.of("xoo", "x1")); + ActiveRuleKey key = ActiveRuleKey.of(XOO_PROFILE_KEY, XOO_RULE_1); ruleActivator.deactivate(key); verifyZeroActiveRules(XOO_PROFILE_KEY); @@ -292,7 +308,6 @@ public class RuleActivatorMediumTest { @Test public void deactivation_fails_if_rule_not_found() throws Exception { - grantPermission(); ActiveRuleKey key = ActiveRuleKey.of(XOO_PROFILE_KEY, RuleKey.of("xoo", "x3")); try { ruleActivator.deactivate(key); @@ -305,8 +320,7 @@ public class RuleActivatorMediumTest { @Test public void deactivation_fails_if_profile_not_found() throws Exception { - grantPermission(); - ActiveRuleKey key = ActiveRuleKey.of(QualityProfileKey.of("other", "js"), RuleKey.of("xoo", "x1")); + ActiveRuleKey key = ActiveRuleKey.of(QualityProfileKey.of("other", "js"), XOO_RULE_1); try { ruleActivator.deactivate(key); fail(); @@ -318,11 +332,10 @@ public class RuleActivatorMediumTest { // INHERITANCE OF PROFILES @Test public void activate_on_child_profile() throws Exception { - grantPermission(); createChildProfiles(); // activate on child profile, but not on root - RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_CHILD_PROFILE_KEY, RuleKey.of("xoo", "x1"))); + RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_CHILD_PROFILE_KEY, XOO_RULE_1)); activation.setSeverity(Severity.BLOCKER); activation.setParameter("max", "7"); ruleActivator.activate(activation); @@ -334,11 +347,10 @@ public class RuleActivatorMediumTest { @Test public void propagate_activation_on_child_profiles() throws Exception { - grantPermission(); createChildProfiles(); // activate on root profile - RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, RuleKey.of("xoo", "x1"))); + RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, XOO_RULE_1)); activation.setSeverity(Severity.BLOCKER); activation.setParameter("max", "7"); ruleActivator.activate(activation); @@ -350,11 +362,10 @@ public class RuleActivatorMediumTest { @Test public void propagate_activation_update_on_child_profiles() throws Exception { - grantPermission(); createChildProfiles(); // activate on root profile - RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, RuleKey.of("xoo", "x1"))); + RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, XOO_RULE_1)); activation.setSeverity(Severity.BLOCKER); activation.setParameter("max", "7"); ruleActivator.activate(activation); @@ -363,7 +374,7 @@ public class RuleActivatorMediumTest { verifyOneActiveRule(XOO_GRAND_CHILD_PROFILE_KEY, Severity.BLOCKER, ActiveRuleDto.INHERITED, ImmutableMap.of("max", "7")); // update on parent - activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, RuleKey.of("xoo", "x1"))); + activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, XOO_RULE_1)); activation.setSeverity(Severity.INFO); activation.setParameter("max", "8"); ruleActivator.activate(activation); @@ -373,7 +384,7 @@ public class RuleActivatorMediumTest { verifyOneActiveRule(XOO_GRAND_CHILD_PROFILE_KEY, Severity.INFO, ActiveRuleDto.INHERITED, ImmutableMap.of("max", "8")); // update on child -> propagate on grand child only - activation = new RuleActivation(ActiveRuleKey.of(XOO_CHILD_PROFILE_KEY, RuleKey.of("xoo", "x1"))); + activation = new RuleActivation(ActiveRuleKey.of(XOO_CHILD_PROFILE_KEY, XOO_RULE_1)); activation.setSeverity(Severity.MINOR); activation.setParameter("max", "9"); ruleActivator.activate(activation); @@ -383,7 +394,7 @@ public class RuleActivatorMediumTest { verifyOneActiveRule(XOO_GRAND_CHILD_PROFILE_KEY, Severity.MINOR, ActiveRuleDto.INHERITED, ImmutableMap.of("max", "9")); // update on grand child - activation = new RuleActivation(ActiveRuleKey.of(XOO_GRAND_CHILD_PROFILE_KEY, RuleKey.of("xoo", "x1"))); + activation = new RuleActivation(ActiveRuleKey.of(XOO_GRAND_CHILD_PROFILE_KEY, XOO_RULE_1)); activation.setSeverity(Severity.BLOCKER); activation.setParameter("max", "10"); ruleActivator.activate(activation); @@ -395,11 +406,10 @@ public class RuleActivatorMediumTest { @Test public void do_not_propagate_activation_update_on_child_overrides() throws Exception { - grantPermission(); createChildProfiles(); // activate on root profile - RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, RuleKey.of("xoo", "x1"))); + RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, XOO_RULE_1)); activation.setSeverity(Severity.INFO); activation.setParameter("max", "7"); ruleActivator.activate(activation); @@ -408,7 +418,7 @@ public class RuleActivatorMediumTest { verifyOneActiveRule(XOO_GRAND_CHILD_PROFILE_KEY, Severity.INFO, ActiveRuleDto.INHERITED, ImmutableMap.of("max", "7")); // override on child - activation = new RuleActivation(ActiveRuleKey.of(XOO_CHILD_PROFILE_KEY, RuleKey.of("xoo", "x1"))); + activation = new RuleActivation(ActiveRuleKey.of(XOO_CHILD_PROFILE_KEY, XOO_RULE_1)); activation.setSeverity(Severity.BLOCKER); activation.setParameter("max", "8"); ruleActivator.activate(activation); @@ -418,7 +428,7 @@ public class RuleActivatorMediumTest { verifyOneActiveRule(XOO_GRAND_CHILD_PROFILE_KEY, Severity.BLOCKER, ActiveRuleDto.INHERITED, ImmutableMap.of("max", "8")); // change on parent -> do not propagate on children because they're overriding values - activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, RuleKey.of("xoo", "x1"))); + activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, XOO_RULE_1)); activation.setSeverity(Severity.CRITICAL); activation.setParameter("max", "10"); ruleActivator.activate(activation); @@ -428,13 +438,34 @@ public class RuleActivatorMediumTest { verifyOneActiveRule(XOO_GRAND_CHILD_PROFILE_KEY, Severity.BLOCKER, ActiveRuleDto.INHERITED, ImmutableMap.of("max", "8")); } + @Test + public void do_not_override_on_child_if_same_values() throws Exception { + createChildProfiles(); + + // activate on root profile + RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, XOO_RULE_1)); + activation.setSeverity(Severity.INFO); + activation.setParameter("max", "7"); + ruleActivator.activate(activation); + verifyOneActiveRule(XOO_PROFILE_KEY, Severity.INFO, null, ImmutableMap.of("max", "7")); + verifyOneActiveRule(XOO_CHILD_PROFILE_KEY, Severity.INFO, ActiveRuleDto.INHERITED, ImmutableMap.of("max", "7")); + + // override on child with same severity and params -> do nothing (still INHERITED but not OVERRIDDEN) + activation = new RuleActivation(ActiveRuleKey.of(XOO_CHILD_PROFILE_KEY, XOO_RULE_1)); + activation.setSeverity(Severity.INFO); + activation.setParameter("max", "7"); + ruleActivator.activate(activation); + dbSession.clearCache(); + verifyOneActiveRule(XOO_PROFILE_KEY, Severity.INFO, null, ImmutableMap.of("max", "7")); + verifyOneActiveRule(XOO_CHILD_PROFILE_KEY, Severity.INFO, ActiveRuleDto.INHERITED, ImmutableMap.of("max", "7")); + } + @Test public void propagate_deactivation_on_child_profiles() throws Exception { - grantPermission(); createChildProfiles(); // activate on root profile - RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, RuleKey.of("xoo", "x1"))); + RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, XOO_RULE_1)); activation.setSeverity(Severity.BLOCKER); activation.setParameter("max", "7"); ruleActivator.activate(activation); @@ -452,11 +483,10 @@ public class RuleActivatorMediumTest { @Test public void do_not_deactivate_inherited_or_overridden_rule() throws Exception { - grantPermission(); createChildProfiles(); // activate on root profile - RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, RuleKey.of("xoo", "x1"))); + RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, XOO_RULE_1)); activation.setSeverity(Severity.BLOCKER); activation.setParameter("max", "7"); ruleActivator.activate(activation); @@ -466,7 +496,7 @@ public class RuleActivatorMediumTest { // try to deactivate on child try { - ruleActivator.deactivate(ActiveRuleKey.of(XOO_CHILD_PROFILE_KEY, RuleKey.of("xoo", "x1"))); + ruleActivator.deactivate(ActiveRuleKey.of(XOO_CHILD_PROFILE_KEY, XOO_RULE_1)); fail(); } catch (IllegalStateException e) { assertThat(e).hasMessage("Cannot deactivate inherited rule 'xoo:x1'"); @@ -475,11 +505,10 @@ public class RuleActivatorMediumTest { @Test public void reset_activation_on_child_profile() throws Exception { - grantPermission(); createChildProfiles(); // activate on root profile - RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, RuleKey.of("xoo", "x1"))); + RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, XOO_RULE_1)); activation.setSeverity(Severity.BLOCKER); activation.setParameter("max", "7"); ruleActivator.activate(activation); @@ -488,7 +517,7 @@ public class RuleActivatorMediumTest { verifyOneActiveRule(XOO_GRAND_CHILD_PROFILE_KEY, Severity.BLOCKER, ActiveRuleDto.INHERITED, ImmutableMap.of("max", "7")); // override - activation = new RuleActivation(ActiveRuleKey.of(XOO_CHILD_PROFILE_KEY, RuleKey.of("xoo", "x1"))); + activation = new RuleActivation(ActiveRuleKey.of(XOO_CHILD_PROFILE_KEY, XOO_RULE_1)); activation.setSeverity(Severity.INFO); activation.setParameter("max", "10"); ruleActivator.activate(activation); @@ -498,7 +527,7 @@ public class RuleActivatorMediumTest { verifyOneActiveRule(XOO_GRAND_CHILD_PROFILE_KEY, Severity.INFO, ActiveRuleDto.INHERITED, ImmutableMap.of("max", "10")); // reset -> remove overridden values - activation = new RuleActivation(ActiveRuleKey.of(XOO_CHILD_PROFILE_KEY, RuleKey.of("xoo", "x1"))); + activation = new RuleActivation(ActiveRuleKey.of(XOO_CHILD_PROFILE_KEY, XOO_RULE_1)); ruleActivator.activate(activation); dbSession.clearCache(); verifyOneActiveRule(XOO_PROFILE_KEY, Severity.BLOCKER, null, ImmutableMap.of("max", "7")); @@ -508,11 +537,10 @@ public class RuleActivatorMediumTest { @Test public void activation_reset_does_not_propagate_to_child_overrides() throws Exception { - grantPermission(); createChildProfiles(); // activate on root profile - RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, RuleKey.of("xoo", "x1"))); + RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_KEY, XOO_RULE_1)); activation.setSeverity(Severity.BLOCKER); activation.setParameter("max", "7"); ruleActivator.activate(activation); @@ -521,7 +549,7 @@ public class RuleActivatorMediumTest { verifyOneActiveRule(XOO_GRAND_CHILD_PROFILE_KEY, Severity.BLOCKER, ActiveRuleDto.INHERITED, ImmutableMap.of("max", "7")); // override on child - activation = new RuleActivation(ActiveRuleKey.of(XOO_CHILD_PROFILE_KEY, RuleKey.of("xoo", "x1"))); + activation = new RuleActivation(ActiveRuleKey.of(XOO_CHILD_PROFILE_KEY, XOO_RULE_1)); activation.setSeverity(Severity.INFO); activation.setParameter("max", "10"); ruleActivator.activate(activation); @@ -531,7 +559,7 @@ public class RuleActivatorMediumTest { verifyOneActiveRule(XOO_GRAND_CHILD_PROFILE_KEY, Severity.INFO, ActiveRuleDto.INHERITED, ImmutableMap.of("max", "10")); // override on grand child - activation = new RuleActivation(ActiveRuleKey.of(XOO_GRAND_CHILD_PROFILE_KEY, RuleKey.of("xoo", "x1"))); + activation = new RuleActivation(ActiveRuleKey.of(XOO_GRAND_CHILD_PROFILE_KEY, XOO_RULE_1)); activation.setSeverity(Severity.MINOR); activation.setParameter("max", "20"); ruleActivator.activate(activation); @@ -541,7 +569,7 @@ public class RuleActivatorMediumTest { verifyOneActiveRule(XOO_GRAND_CHILD_PROFILE_KEY, Severity.MINOR, ActiveRuleDto.OVERRIDES, ImmutableMap.of("max", "20")); // reset child -> keep the overridden grand-child - activation = new RuleActivation(ActiveRuleKey.of(XOO_CHILD_PROFILE_KEY, RuleKey.of("xoo", "x1"))); + activation = new RuleActivation(ActiveRuleKey.of(XOO_CHILD_PROFILE_KEY, XOO_RULE_1)); ruleActivator.activate(activation); dbSession.clearCache(); verifyOneActiveRule(XOO_PROFILE_KEY, Severity.BLOCKER, null, ImmutableMap.of("max", "7")); @@ -591,10 +619,6 @@ public class RuleActivatorMediumTest { dbSession.commit(); } - private void grantPermission() { - MockUserSession.set().setGlobalPermissions(GlobalPermissions.QUALITY_PROFILE_ADMIN).setLogin("marius"); - } - private void verifyZeroActiveRules(QualityProfileKey key) { // verify db dbSession.clearCache(); diff --git a/sonar-server/src/test/java/org/sonar/server/qualityprofile/RuleChangeTest.java b/sonar-server/src/test/java/org/sonar/server/qualityprofile/RuleChangeTest.java index cde6ad18da4..194456efe1b 100644 --- a/sonar-server/src/test/java/org/sonar/server/qualityprofile/RuleChangeTest.java +++ b/sonar-server/src/test/java/org/sonar/server/qualityprofile/RuleChangeTest.java @@ -101,12 +101,4 @@ public class RuleChangeTest extends AbstractDbUnitTestCase { checkTables("changeParentProfile", new String[]{"change_date"}, "active_rule_changes"); } - @Test - public void should_track_remove_activated_rules() { - setupData("initialData"); - Rule rule = getSession().reattach(Rule.class, 1); - profilesManager.removeActivatedRules(rule.getId()); - checkTables("removeActivatedRules", new String[]{"change_date"}, "active_rule_changes", "active_rules"); - } - } diff --git a/sonar-server/src/test/java/org/sonar/server/rule/RegisterRulesTest.java b/sonar-server/src/test/java/org/sonar/server/rule/RegisterRulesTest.java index 77330f4a7ce..f4b55bfcbc0 100644 --- a/sonar-server/src/test/java/org/sonar/server/rule/RegisterRulesTest.java +++ b/sonar-server/src/test/java/org/sonar/server/rule/RegisterRulesTest.java @@ -36,7 +36,7 @@ import org.sonar.core.rule.RuleDto; import org.sonar.core.rule.RuleParamDto; import org.sonar.core.technicaldebt.db.CharacteristicDao; import org.sonar.server.db.DbClient; -import org.sonar.server.qualityprofile.ProfilesManager; +import org.sonar.server.qualityprofile.QProfileService; import org.sonar.server.qualityprofile.db.ActiveRuleDao; import org.sonar.server.rule.db.RuleDao; @@ -53,7 +53,7 @@ public class RegisterRulesTest extends AbstractDaoTestCase { static final Date DATE2 = DateUtils.parseDateTime("2014-02-01T12:10:03+0100"); static final Date DATE3 = DateUtils.parseDateTime("2014-03-01T12:10:03+0100"); - ProfilesManager profilesManager = mock(ProfilesManager.class); + QProfileService profileService = mock(QProfileService.class); System2 system; DbClient dbClient; DbSession dbSession; @@ -200,7 +200,7 @@ public class RegisterRulesTest extends AbstractDaoTestCase { private void execute(RulesDefinition... defs) { RuleDefinitionsLoader loader = new RuleDefinitionsLoader(mock(RuleRepositories.class), defs); - RegisterRules task = new RegisterRules(loader, profilesManager, dbClient, system); + RegisterRules task = new RegisterRules(loader, profileService, dbClient, system); task.start(); } diff --git a/sonar-server/src/test/java/org/sonar/server/rule/RuleBackendMediumTest.java b/sonar-server/src/test/java/org/sonar/server/rule/RuleBackendMediumTest.java index e146c532c95..b3944a21efe 100644 --- a/sonar-server/src/test/java/org/sonar/server/rule/RuleBackendMediumTest.java +++ b/sonar-server/src/test/java/org/sonar/server/rule/RuleBackendMediumTest.java @@ -299,13 +299,11 @@ public class RuleBackendMediumTest { @Test public void should_not_find_removed() { // insert db - RuleKey ruleKey = RuleKey.of("javascript", "S001"); - RuleDto ruleDto = newRuleDto(ruleKey).setStatus(RuleStatus.READY); - + RuleKey readyKey = RuleKey.of("javascript", "S001"); + RuleDto readyDto = RuleTesting.newDto(readyKey).setStatus(RuleStatus.READY); RuleKey removedKey = RuleKey.of("javascript", "S002"); - RuleDto removedDto = newRuleDto(removedKey).setStatus(RuleStatus.REMOVED); - dao.insert(dbSession, ruleDto); - dao.insert(dbSession, removedDto); + RuleDto removedDto = RuleTesting.newDto(removedKey).setStatus(RuleStatus.REMOVED); + dao.insert(dbSession, readyDto, removedDto); dbSession.commit(); // 0. Assert rules are in DB @@ -315,8 +313,9 @@ public class RuleBackendMediumTest { assertThat(index.getByKey(removedKey)).isNotNull(); // 2. assert find does not get REMOVED - assertThat(index.search(new RuleQuery(), QueryOptions.DEFAULT) - .getRules()).hasSize(1); + List rules = index.search(new RuleQuery(), QueryOptions.DEFAULT).getHits(); + assertThat(rules).hasSize(1); + assertThat(rules.get(0).key()).isEqualTo(readyKey); } private RuleDto newRuleDto(RuleKey ruleKey) { diff --git a/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileBackuperMediumTest/expected-backup.xml b/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileBackuperMediumTest/expected-backup.xml new file mode 100644 index 00000000000..1786ed941dd --- /dev/null +++ b/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileBackuperMediumTest/expected-backup.xml @@ -0,0 +1,18 @@ + + + P1 + xoo + + + xoo + x1 + BLOCKER + + + max + 7 + + + + + diff --git a/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileBackuperMediumTest/not-xml-backup.txt b/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileBackuperMediumTest/not-xml-backup.txt new file mode 100644 index 00000000000..53451f2e47b --- /dev/null +++ b/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileBackuperMediumTest/not-xml-backup.txt @@ -0,0 +1 @@ +invalid backup diff --git a/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileBackuperMediumTest/restore-child.xml b/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileBackuperMediumTest/restore-child.xml new file mode 100644 index 00000000000..94c63aa3a43 --- /dev/null +++ b/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileBackuperMediumTest/restore-child.xml @@ -0,0 +1,18 @@ + + + P2 + xoo + + + xoo + x1 + BLOCKER + + + max + 7 + + + + + diff --git a/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileBackuperMediumTest/restore-parent.xml b/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileBackuperMediumTest/restore-parent.xml new file mode 100644 index 00000000000..1786ed941dd --- /dev/null +++ b/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileBackuperMediumTest/restore-parent.xml @@ -0,0 +1,18 @@ + + + P1 + xoo + + + xoo + x1 + BLOCKER + + + max + 7 + + + + + diff --git a/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileBackuperMediumTest/restore.xml b/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileBackuperMediumTest/restore.xml new file mode 100644 index 00000000000..1786ed941dd --- /dev/null +++ b/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileBackuperMediumTest/restore.xml @@ -0,0 +1,18 @@ + + + P1 + xoo + + + xoo + x1 + BLOCKER + + + max + 7 + + + + + diff --git a/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileBackuperMediumTest/restore_fails_to_deactivate_inherited_rule.xml b/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileBackuperMediumTest/restore_fails_to_deactivate_inherited_rule.xml new file mode 100644 index 00000000000..368fa6cd456 --- /dev/null +++ b/sonar-server/src/test/resources/org/sonar/server/qualityprofile/QProfileBackuperMediumTest/restore_fails_to_deactivate_inherited_rule.xml @@ -0,0 +1,12 @@ + + + P2 + xoo + + + xoo + x2 + BLOCKER + + + -- 2.39.5