summaryrefslogtreecommitdiffstats
path: root/sonar-server
diff options
context:
space:
mode:
authorJulien Lancelot <julien.lancelot@sonarsource.com>2014-04-24 17:15:07 +0200
committerJulien Lancelot <julien.lancelot@sonarsource.com>2014-04-24 17:15:07 +0200
commit722b816695bbddcdc454063b0fc9386d8d1a2c4f (patch)
tree60e2692aa09dcea4307ed3f0a1f84c048b457b65 /sonar-server
parentec0f4a0b284b83d91fec2e3d9ce48e289ef6ae52 (diff)
downloadsonarqube-722b816695bbddcdc454063b0fc9386d8d1a2c4f.tar.gz
sonarqube-722b816695bbddcdc454063b0fc9386d8d1a2c4f.zip
SONAR-4764 Restore default profiles for a language (Server side, no ui)
Diffstat (limited to 'sonar-server')
-rw-r--r--sonar-server/src/main/java/org/sonar/server/platform/Platform.java4
-rw-r--r--sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java11
-rw-r--r--sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGates.java22
-rw-r--r--sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileActiveRuleOperations.java37
-rw-r--r--sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileBackup.java88
-rw-r--r--sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileLookup.java37
-rw-r--r--sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileOperations.java5
-rw-r--r--sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileRepositoryExporter.java6
-rw-r--r--sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileResult.java8
-rw-r--r--sonar-server/src/main/java/org/sonar/server/startup/RegisterQualityProfiles.java213
-rw-r--r--sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileActiveRuleOperationsTest.java64
-rw-r--r--sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileBackupTest.java97
-rw-r--r--sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileLookupTest.java7
-rw-r--r--sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileRepositoryExporterTest.java21
-rw-r--r--sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfilesMediumTest.java148
-rw-r--r--sonar-server/src/test/java/org/sonar/server/rule/RuleRegistryTest.java7
-rw-r--r--sonar-server/src/test/java/org/sonar/server/startup/RegisterQualityProfilesTest.java335
-rw-r--r--sonar-server/src/test/java/org/sonar/server/tester/ServerTester.java12
18 files changed, 943 insertions, 179 deletions
diff --git a/sonar-server/src/main/java/org/sonar/server/platform/Platform.java b/sonar-server/src/main/java/org/sonar/server/platform/Platform.java
index 510b3f6f620..ff19bc981f3 100644
--- a/sonar-server/src/main/java/org/sonar/server/platform/Platform.java
+++ b/sonar-server/src/main/java/org/sonar/server/platform/Platform.java
@@ -148,6 +148,10 @@ public class Platform {
}
}
+ public void addExtensions(Object... extensions){
+ serverComponents.addExtensions(extensions);
+ }
+
public ComponentContainer getContainer() {
return currentContainer;
}
diff --git a/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java b/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java
index 333305896a5..5d3c7fdcdc8 100644
--- a/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java
+++ b/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java
@@ -131,6 +131,7 @@ import java.util.List;
class ServerComponents {
private final Object[] rootComponents;
+ private Object[] extensions;
ServerComponents(Object... rootComponents) {
this.rootComponents = rootComponents;
@@ -392,6 +393,12 @@ class ServerComponents {
pico.addSingleton(StringTypeValidation.class);
pico.addSingleton(StringListTypeValidation.class);
+ if (extensions != null) {
+ for (Object extension : extensions) {
+ pico.addSingleton(extension);
+ }
+ }
+
ServerExtensionInstaller extensionRegistrar = pico.getComponentByType(ServerExtensionInstaller.class);
extensionRegistrar.installExtensions(pico);
@@ -399,6 +406,10 @@ class ServerComponents {
executeStartupTaks(pico);
}
+ void addExtensions(Object... extensions){
+ this.extensions = extensions;
+ }
+
private void executeStartupTaks(ComponentContainer pico) {
final ComponentContainer startupContainer = pico.createChild();
startupContainer.addSingleton(GwtPublisher.class);
diff --git a/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGates.java b/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGates.java
index 4d5b8b2a649..f8d8c64556f 100644
--- a/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGates.java
+++ b/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGates.java
@@ -25,7 +25,6 @@ import com.google.common.collect.Collections2;
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.ibatis.session.SqlSession;
-import org.elasticsearch.common.collect.Lists;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.measures.Metric;
import org.sonar.api.measures.Metric.ValueType;
@@ -77,7 +76,7 @@ public class QualityGates {
private final MyBatis myBatis;
public QualityGates(QualityGateDao dao, QualityGateConditionDao conditionDao, MetricFinder metricFinder, PropertiesDao propertiesDao, ComponentDao componentDao,
- MyBatis myBatis) {
+ MyBatis myBatis) {
this.dao = dao;
this.conditionDao = conditionDao;
this.metricFinder = metricFinder;
@@ -119,11 +118,12 @@ public class QualityGates {
SqlSession session = myBatis.openSession();
try {
dao.insert(destinationGate, session);
- for(QualityGateConditionDto sourceCondition: conditionDao.selectForQualityGate(sourceId, session)) {
+ for (QualityGateConditionDto sourceCondition : conditionDao.selectForQualityGate(sourceId, session)) {
conditionDao.insert(new QualityGateConditionDto().setQualityGateId(destinationGate.getId())
- .setMetricId(sourceCondition.getMetricId()).setOperator(sourceCondition.getOperator())
- .setWarningThreshold(sourceCondition.getWarningThreshold()).setErrorThreshold(sourceCondition.getErrorThreshold()).setPeriod(sourceCondition.getPeriod()),
- session);
+ .setMetricId(sourceCondition.getMetricId()).setOperator(sourceCondition.getOperator())
+ .setWarningThreshold(sourceCondition.getWarningThreshold()).setErrorThreshold(sourceCondition.getErrorThreshold()).setPeriod(sourceCondition.getPeriod()),
+ session
+ );
}
session.commit();
} finally {
@@ -174,7 +174,7 @@ public class QualityGates {
}
public QualityGateConditionDto createCondition(long qGateId, String metricKey, String operator,
- @Nullable String warningThreshold, @Nullable String errorThreshold, @Nullable Integer period) {
+ @Nullable String warningThreshold, @Nullable String errorThreshold, @Nullable Integer period) {
checkPermission(UserSession.get());
getNonNullQgate(qGateId);
Metric metric = getNonNullMetric(metricKey);
@@ -187,7 +187,7 @@ public class QualityGates {
}
public QualityGateConditionDto updateCondition(long condId, String metricKey, String operator,
- @Nullable String warningThreshold, @Nullable String errorThreshold, @Nullable Integer period) {
+ @Nullable String warningThreshold, @Nullable String errorThreshold, @Nullable Integer period) {
checkPermission(UserSession.get());
QualityGateConditionDto condition = getNonNullCondition(condId);
Metric metric = getNonNullMetric(metricKey);
@@ -200,7 +200,7 @@ public class QualityGates {
public Collection<QualityGateConditionDto> listConditions(long qGateId) {
Collection<QualityGateConditionDto> conditionsForGate = conditionDao.selectForQualityGate(qGateId);
- for (QualityGateConditionDto condition: conditionsForGate) {
+ for (QualityGateConditionDto condition : conditionsForGate) {
condition.setMetricKey(metricFinder.findById((int) condition.getMetricId()).getKey());
}
return conditionsForGate;
@@ -239,14 +239,14 @@ public class QualityGates {
try {
checkPermission(UserSession.get());
hasWritePermission = true;
- } catch(ServerException unallowed) {
+ } catch (ServerException unallowed) {
// Ignored
}
return hasWritePermission;
}
private void validateCondition(Metric metric, String operator, @Nullable String warningThreshold, @Nullable String errorThreshold, @Nullable Integer period) {
- List<Message> validationMessages = Lists.newArrayList();
+ List<Message> validationMessages = newArrayList();
validateMetric(metric, validationMessages);
validateOperator(metric, operator, validationMessages);
validateThresholds(warningThreshold, errorThreshold, validationMessages);
diff --git a/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileActiveRuleOperations.java b/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileActiveRuleOperations.java
index 70e344d77e8..b5b00e3b619 100644
--- a/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileActiveRuleOperations.java
+++ b/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileActiveRuleOperations.java
@@ -27,6 +27,7 @@ import org.apache.ibatis.session.SqlSession;
import org.elasticsearch.common.base.Predicate;
import org.elasticsearch.common.collect.Iterables;
import org.sonar.api.ServerComponent;
+import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.Severity;
import org.sonar.api.rules.RulePriority;
import org.sonar.api.server.rule.RuleParamType;
@@ -91,7 +92,7 @@ public class QProfileActiveRuleOperations implements ServerComponent {
RuleDto rule = findRuleNotNull(ruleId, session);
ActiveRuleDto activeRule = findActiveRule(profileId, ruleId, session);
if (activeRule == null) {
- createActiveRule(profile.getId(), rule.getId(), severity, userSession, session);
+ activateRule(profile.getId(), rule.getId(), severity, userSession, session);
} else {
updateSeverity(activeRule, severity, userSession, session);
}
@@ -100,7 +101,21 @@ public class QProfileActiveRuleOperations implements ServerComponent {
}
}
- private ActiveRuleDto createActiveRule(int profileId, int ruleId, String severity, UserSession userSession, SqlSession session) {
+ private ActiveRuleDto activateRule(int profileId, int ruleId, String severity, UserSession userSession, SqlSession session) {
+ ActiveRuleDto activeRule = createActiveRule(profileId, ruleId, severity, session);
+ session.commit();
+ ProfilesManager.RuleInheritanceActions actions = profilesManager.activated(profileId, activeRule.getId(), getLoggedName(userSession));
+ reindexInheritanceResult(actions, session);
+ return activeRule;
+ }
+
+ ActiveRuleDto createActiveRule(int profileId, RuleKey ruleKey, String severity, SqlSession session) {
+ RuleDto rule = ruleDao.selectByKey(ruleKey, session);
+ QProfileValidations.checkRuleIsNotNull(rule);
+ return createActiveRule(profileId, rule.getId(), severity, session);
+ }
+
+ private ActiveRuleDto createActiveRule(int profileId, int ruleId, String severity, SqlSession session) {
ActiveRuleDto activeRule = new ActiveRuleDto()
.setProfileId(profileId)
.setRuleId(ruleId)
@@ -118,9 +133,6 @@ public class QProfileActiveRuleOperations implements ServerComponent {
activeRuleParams.add(activeRuleParam);
activeRuleDao.insert(activeRuleParam, session);
}
- session.commit();
- ProfilesManager.RuleInheritanceActions actions = profilesManager.activated(profileId, activeRule.getId(), getLoggedName(userSession));
- reindexInheritanceResult(actions, session);
return activeRule;
}
@@ -141,7 +153,7 @@ public class QProfileActiveRuleOperations implements ServerComponent {
List<Integer> ruleIdsToActivate = rules.searchInactiveProfileRuleIds(query);
for (Integer ruleId : ruleIdsToActivate) {
RuleDto rule = findRuleNotNull(ruleId, session);
- createActiveRule(profileId, ruleId, rule.getSeverityString(), userSession, session);
+ activateRule(profileId, ruleId, rule.getSeverityString(), userSession, session);
}
return ruleIdsToActivate.size();
} finally {
@@ -203,11 +215,11 @@ public class QProfileActiveRuleOperations implements ServerComponent {
ActiveRuleParamDto activeRuleParam = findActiveRuleParam(activeRuleId, key, session);
ActiveRuleDto activeRule = findActiveRuleNotNull(activeRuleId, session);
if (activeRuleParam == null && sanitizedValue != null) {
- createActiveRuleParam(activeRule, key, value, userSession, session);
+ createActiveRuleParam(activeRule, key, sanitizedValue, userSession, session);
} else if (activeRuleParam != null && sanitizedValue == null) {
deleteActiveRuleParam(activeRule, activeRuleParam, userSession, session);
} else if (activeRuleParam != null) {
- updateActiveRuleParam(activeRule, activeRuleParam, value, userSession, session);
+ updateActiveRuleParam(activeRule, activeRuleParam, sanitizedValue, userSession, session);
}
// If no active rule param and no value -> do nothing
@@ -234,6 +246,15 @@ public class QProfileActiveRuleOperations implements ServerComponent {
notifyParamsDeleted(activeRule, newArrayList(activeRuleParam), session, userSession);
}
+ void updateActiveRuleParam(ActiveRuleDto activeRule, String key, String value, SqlSession session) {
+ RuleParamDto ruleParam = findRuleParamNotNull(activeRule.getRulId(), key, session);
+ ActiveRuleParamDto activeRuleParam = findActiveRuleParam(activeRule.getId(), key, session);
+ validateParam(ruleParam, value);
+
+ activeRuleParam.setValue(value);
+ activeRuleDao.update(activeRuleParam, session);
+ }
+
private void updateActiveRuleParam(ActiveRuleDto activeRule, ActiveRuleParamDto activeRuleParam, String value, UserSession userSession, SqlSession session) {
RuleParamDto ruleParam = findRuleParamNotNull(activeRule.getRulId(), activeRuleParam.getKey(), session);
validateParam(ruleParam, value);
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 2bc2c63b67b..c00e297cc86 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
@@ -20,16 +20,22 @@
package org.sonar.server.qualityprofile;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ListMultimap;
import org.apache.ibatis.session.SqlSession;
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;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.core.persistence.MyBatis;
import org.sonar.core.preview.PreviewCache;
+import org.sonar.core.qualityprofile.db.ActiveRuleDto;
import org.sonar.jpa.session.DatabaseSessionFactory;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.user.UserSession;
@@ -37,7 +43,10 @@ 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;
+import java.util.Map;
import static com.google.common.collect.Lists.newArrayList;
@@ -52,18 +61,31 @@ public class QProfileBackup implements ServerComponent {
private final MyBatis myBatis;
private final QProfileLookup qProfileLookup;
+ private final QProfileOperations qProfileOperations;
+ private final QProfileActiveRuleOperations qProfileActiveRuleOperations;
private final ESActiveRule esActiveRule;
+ private final List<ProfileDefinition> definitions;
private final PreviewCache dryRunCache;
public QProfileBackup(DatabaseSessionFactory sessionFactory, XMLProfileParser xmlProfileParser, XMLProfileSerializer xmlProfileSerializer, MyBatis myBatis,
- QProfileLookup qProfileLookup, ESActiveRule esActiveRule, PreviewCache dryRunCache) {
+ QProfileLookup qProfileLookup, QProfileOperations qProfileOperations, QProfileActiveRuleOperations qProfileActiveRuleOperations, ESActiveRule esActiveRule,
+ PreviewCache dryRunCache) {
+ this(sessionFactory, xmlProfileParser, xmlProfileSerializer, myBatis, qProfileLookup, qProfileOperations, qProfileActiveRuleOperations, esActiveRule,
+ Collections.<ProfileDefinition>emptyList(), dryRunCache);
+ }
+ public QProfileBackup(DatabaseSessionFactory sessionFactory, XMLProfileParser xmlProfileParser, XMLProfileSerializer xmlProfileSerializer, MyBatis myBatis,
+ QProfileLookup qProfileLookup, QProfileOperations qProfileOperations, QProfileActiveRuleOperations qProfileActiveRuleOperations, ESActiveRule esActiveRule,
+ List<ProfileDefinition> definitions, PreviewCache dryRunCache) {
this.sessionFactory = sessionFactory;
this.xmlProfileParser = xmlProfileParser;
this.xmlProfileSerializer = xmlProfileSerializer;
this.myBatis = myBatis;
this.qProfileLookup = qProfileLookup;
+ this.qProfileOperations = qProfileOperations;
+ this.qProfileActiveRuleOperations = qProfileActiveRuleOperations;
this.esActiveRule = esActiveRule;
+ this.definitions = definitions;
this.dryRunCache = dryRunCache;
}
@@ -76,8 +98,7 @@ public class QProfileBackup implements ServerComponent {
}
/**
- * @param deleteExisting is used to not fail if profile exist but to delete it first.
- * It's only used by WS, and it should should be soon removed
+ * @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());
@@ -109,6 +130,63 @@ public class QProfileBackup implements ServerComponent {
return result;
}
+ /**
+ * Restore default profile for a given language.
+ * If a profile with same name than default profile already exists, an exception will be thrown.
+ */
+ public QProfileResult restoreDefaultProfilesFromLanguage(String language) {
+ checkPermission(UserSession.get());
+ QProfileResult result = new QProfileResult();
+
+ SqlSession session = myBatis.openSession();
+ try {
+ ListMultimap<String, RulesProfile> profilesByName = profilesByName(language, result);
+ for (Map.Entry<String, Collection<RulesProfile>> entry : profilesByName.asMap().entrySet()) {
+ String name = entry.getKey();
+ QProfile profile = qProfileOperations.newProfile(name, language, true, UserSession.get(), session);
+ for (RulesProfile currentRulesProfile : entry.getValue()) {
+ restoreFromActiveRules(profile, currentRulesProfile, session);
+ }
+ esActiveRule.bulkIndexProfile(profile.id(), session);
+ }
+ dryRunCache.reportGlobalModification(session);
+ session.commit();
+ } finally {
+ MyBatis.closeQuietly(session);
+ }
+ return result;
+ }
+
+ private ListMultimap<String, RulesProfile> profilesByName(String language, QProfileResult result) {
+ ListMultimap<String, RulesProfile> profilesByName = ArrayListMultimap.create();
+ for (ProfileDefinition definition : definitions) {
+ ValidationMessages validation = ValidationMessages.create();
+ RulesProfile profile = definition.createProfile(validation);
+ if (language.equals(profile.getLanguage())) {
+ processValidationMessages(validation, result);
+ profilesByName.put(profile.getName(), profile);
+ }
+ }
+ return profilesByName;
+ }
+
+ /**
+ * Used by {@link org.sonar.server.startup.RegisterQualityProfiles}
+ */
+ public void restoreFromActiveRules(QProfile profile, RulesProfile rulesProfile, SqlSession session) {
+ for (org.sonar.api.rules.ActiveRule activeRule : rulesProfile.getActiveRules()) {
+ RuleKey ruleKey = RuleKey.of(activeRule.getRepositoryKey(), activeRule.getRuleKey());
+ ActiveRuleDto activeRuleDto = qProfileActiveRuleOperations.createActiveRule(profile.id(), ruleKey, activeRule.getSeverity().name(), session);
+ for (RuleParam param : activeRule.getRule().getParams()) {
+ String paramKey = param.getKey();
+ String value = activeRule.getParameter(param.getKey());
+ if (value != null) {
+ qProfileActiveRuleOperations.updateActiveRuleParam(activeRuleDto, paramKey, value, session);
+ }
+ }
+ }
+ }
+
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) {
@@ -130,8 +208,8 @@ public class QProfileBackup implements ServerComponent {
}
throw BadRequestException.of("Fail to restore profile", errors);
}
- result.setWarnings(messages.getWarnings());
- result.setInfos(messages.getInfos());
+ result.addWarnings(messages.getWarnings());
+ result.addInfos(messages.getInfos());
}
private void checkPermission(UserSession userSession) {
diff --git a/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileLookup.java b/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileLookup.java
index 48d7179a08a..1b38d2a35ec 100644
--- a/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileLookup.java
+++ b/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileLookup.java
@@ -29,6 +29,7 @@ import org.sonar.core.qualityprofile.db.QualityProfileDao;
import org.sonar.core.qualityprofile.db.QualityProfileDto;
import javax.annotation.CheckForNull;
+
import java.util.List;
import static com.google.common.collect.Lists.newArrayList;
@@ -70,9 +71,8 @@ public class QProfileLookup implements ServerComponent {
return null;
}
- @CheckForNull
- public QProfile profile(String name, String language) {
- QualityProfileDto dto = findQualityProfile(name, language);
+ public QProfile profile(String name, String language, SqlSession session) {
+ QualityProfileDto dto = findQualityProfile(name, language, session);
if (dto != null) {
return QProfile.from(dto);
}
@@ -80,6 +80,16 @@ public class QProfileLookup implements ServerComponent {
}
@CheckForNull
+ public QProfile profile(String name, String language) {
+ SqlSession session = myBatis.openSession();
+ try {
+ return profile(name, language, session);
+ } finally {
+ MyBatis.closeQuietly(session);
+ }
+ }
+
+ @CheckForNull
public QProfile defaultProfile(String language) {
SqlSession session = myBatis.openSession();
try {
@@ -100,14 +110,19 @@ public class QProfileLookup implements ServerComponent {
@CheckForNull
public QProfile parent(QProfile profile) {
- String parent = profile.parent();
- if (parent != null) {
- QualityProfileDto parentDto = findQualityProfile(parent, profile.language());
- if (parentDto != null) {
- return QProfile.from(parentDto);
+ SqlSession session = myBatis.openSession();
+ try {
+ String parent = profile.parent();
+ if (parent != null) {
+ QualityProfileDto parentDto = findQualityProfile(parent, profile.language(), session);
+ if (parentDto != null) {
+ return QProfile.from(parentDto);
+ }
}
+ return null;
+ } finally {
+ MyBatis.closeQuietly(session);
}
- return null;
}
public List<QProfile> children(QProfile profile) {
@@ -191,8 +206,8 @@ public class QProfileLookup implements ServerComponent {
}
@CheckForNull
- private QualityProfileDto findQualityProfile(String name, String language) {
- return dao.selectByNameAndLanguage(name, language);
+ private QualityProfileDto findQualityProfile(String name, String language, SqlSession session) {
+ return dao.selectByNameAndLanguage(name, language, session);
}
}
diff --git a/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileOperations.java b/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileOperations.java
index 5996a6984eb..114664637b1 100644
--- a/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileOperations.java
+++ b/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileOperations.java
@@ -131,15 +131,14 @@ public class QProfileOperations implements ServerComponent {
checkPermission(userSession);
SqlSession session = myBatis.openSession();
try {
- deleteProfile(profileId, userSession, session);
+ deleteProfile(profileId, session);
session.commit();
} finally {
MyBatis.closeQuietly(session);
}
}
- private void deleteProfile(int profileId, UserSession userSession, SqlSession session) {
- checkPermission(userSession);
+ public void deleteProfile(int profileId, SqlSession session) {
QualityProfileDto profile = findNotNull(profileId, session);
if (!profileLookup.isDeletable(QProfile.from(profile), session)) {
throw new BadRequestException("This profile can not be deleted");
diff --git a/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileRepositoryExporter.java b/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileRepositoryExporter.java
index dfbcf2a3c46..a6a5becc61b 100644
--- a/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileRepositoryExporter.java
+++ b/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileRepositoryExporter.java
@@ -90,7 +90,7 @@ public class QProfileRepositoryExporter implements ServerComponent {
public String exportToXml(QProfile profile, String pluginKey) {
DatabaseSession session = sessionFactory.getSession();
RulesProfile rulesProfile = session.getSingleResult(RulesProfile.class, "id", profile.id());
- if (profile == null) {
+ if (rulesProfile == null) {
throw new NotFoundException("This profile does not exists.");
}
ProfileExporter exporter = getProfileExporter(pluginKey);
@@ -127,8 +127,8 @@ public class QProfileRepositoryExporter implements ServerComponent {
}
throw BadRequestException.of("Fail to import profile", errors);
}
- result.setWarnings(messages.getWarnings());
- result.setInfos(messages.getInfos());
+ result.addWarnings(messages.getWarnings());
+ result.addInfos(messages.getInfos());
}
private ActiveRuleDto toActiveRuleDto(ActiveRule activeRule, int profileId) {
diff --git a/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileResult.java b/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileResult.java
index 96c47c98d3e..81fbb63faa3 100644
--- a/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileResult.java
+++ b/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileResult.java
@@ -40,8 +40,8 @@ public class QProfileResult {
return warnings;
}
- public QProfileResult setWarnings(List<String> warnings) {
- this.warnings = warnings;
+ public QProfileResult addWarnings(List<String> warnings) {
+ this.warnings.addAll(warnings);
return this;
}
@@ -49,8 +49,8 @@ public class QProfileResult {
return infos;
}
- public QProfileResult setInfos(List<String> infos) {
- this.infos = infos;
+ public QProfileResult addInfos(List<String> infos) {
+ this.infos.addAll(infos);
return this;
}
diff --git a/sonar-server/src/main/java/org/sonar/server/startup/RegisterQualityProfiles.java b/sonar-server/src/main/java/org/sonar/server/startup/RegisterQualityProfiles.java
index bf58747770f..1b76f943c65 100644
--- a/sonar-server/src/main/java/org/sonar/server/startup/RegisterQualityProfiles.java
+++ b/sonar-server/src/main/java/org/sonar/server/startup/RegisterQualityProfiles.java
@@ -25,21 +25,23 @@ import com.google.common.collect.ListMultimap;
import com.google.common.collect.Multimaps;
import com.google.common.collect.Sets;
import org.apache.commons.lang.StringUtils;
+import org.apache.ibatis.session.SqlSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.sonar.api.database.DatabaseSession;
import org.sonar.api.profiles.ProfileDefinition;
import org.sonar.api.profiles.RulesProfile;
-import org.sonar.api.rules.*;
import org.sonar.api.utils.SonarException;
import org.sonar.api.utils.TimeProfiler;
import org.sonar.api.utils.ValidationMessages;
+import org.sonar.core.persistence.MyBatis;
import org.sonar.core.template.LoadedTemplateDao;
import org.sonar.core.template.LoadedTemplateDto;
-import org.sonar.jpa.session.DatabaseSessionFactory;
import org.sonar.server.platform.PersistentSettings;
-import org.sonar.server.qualityprofile.ESActiveRule;
+import org.sonar.server.qualityprofile.*;
import org.sonar.server.rule.RegisterRules;
+import org.sonar.server.user.UserSession;
+
+import javax.annotation.Nullable;
import java.util.*;
@@ -48,115 +50,112 @@ public class RegisterQualityProfiles {
private static final Logger LOGGER = LoggerFactory.getLogger(RegisterQualityProfiles.class);
private static final String DEFAULT_PROFILE_NAME = "Sonar way";
- private final List<ProfileDefinition> definitions;
private final LoadedTemplateDao loadedTemplateDao;
- private final RuleFinder ruleFinder;
+ private final QProfileBackup qProfileBackup;
+ private final QProfileOperations qProfileOperations;
+ private final QProfileLookup qProfileLookup;
private final ESActiveRule esActiveRule;
- private final DatabaseSessionFactory sessionFactory;
private final PersistentSettings settings;
- private DatabaseSession session = null;
-
- public RegisterQualityProfiles(List<ProfileDefinition> definitions,
- PersistentSettings settings,
- RuleFinder ruleFinder,
- ESActiveRule esActiveRule,
- LoadedTemplateDao loadedTemplateDao,
- DatabaseSessionFactory sessionFactory,
- RegisterRules registerRulesBefore) {
+ private final List<ProfileDefinition> definitions;
+ private final MyBatis myBatis;
+
+ public RegisterQualityProfiles(MyBatis myBatis,
+ PersistentSettings settings,
+ ESActiveRule esActiveRule,
+ LoadedTemplateDao loadedTemplateDao,
+ QProfileBackup qProfileBackup,
+ QProfileOperations qProfileOperations,
+ QProfileLookup qProfileLookup,
+ RegisterRules registerRulesBefore) {
+ this(myBatis, settings, esActiveRule, loadedTemplateDao, qProfileBackup, qProfileOperations, qProfileLookup, registerRulesBefore,
+ Collections.<ProfileDefinition>emptyList());
+ }
+
+ public RegisterQualityProfiles(MyBatis myBatis,
+ PersistentSettings settings,
+ ESActiveRule esActiveRule,
+ LoadedTemplateDao loadedTemplateDao,
+ QProfileBackup qProfileBackup,
+ QProfileOperations qProfileOperations,
+ QProfileLookup qProfileLookup,
+ RegisterRules registerRulesBefore,
+ List<ProfileDefinition> definitions) {
+ this.myBatis = myBatis;
this.settings = settings;
- this.ruleFinder = ruleFinder;
this.esActiveRule = esActiveRule;
+ this.qProfileBackup = qProfileBackup;
+ this.qProfileOperations = qProfileOperations;
+ this.qProfileLookup = qProfileLookup;
this.definitions = definitions;
this.loadedTemplateDao = loadedTemplateDao;
- this.sessionFactory = sessionFactory;
- }
-
- public RegisterQualityProfiles(PersistentSettings settings,
- RuleFinder ruleFinder,
- ESActiveRule esActiveRule,
- LoadedTemplateDao loadedTemplateDao,
- DatabaseSessionFactory sessionFactory,
- RegisterRules registerRulesBefore) {
- this(Collections.<ProfileDefinition>emptyList(), settings, ruleFinder, esActiveRule, loadedTemplateDao, sessionFactory, registerRulesBefore);
}
public void start() {
TimeProfiler profiler = new TimeProfiler(LOGGER).start("Register Quality Profiles");
- session = sessionFactory.getSession();
-
- // hibernate session can contain an invalid cache of rules
- session.commit();
- ListMultimap<String, RulesProfile> profilesByLanguage = loadDefinitions();
- for (String language : profilesByLanguage.keySet()) {
- List<RulesProfile> profiles = profilesByLanguage.get(language);
- verifyLanguage(language, profiles);
-
- for (Map.Entry<String, Collection<RulesProfile>> entry : groupByName(profiles).entrySet()) {
- String name = entry.getKey();
- if (shouldRegister(language, name)) {
- register(language, name, entry.getValue());
+ SqlSession session = myBatis.openSession();
+ try {
+ ListMultimap<String, RulesProfile> profilesByLanguage = profilesByLanguage();
+ for (String language : profilesByLanguage.keySet()) {
+ List<RulesProfile> profiles = profilesByLanguage.get(language);
+ verifyLanguage(language, profiles);
+
+ for (Map.Entry<String, Collection<RulesProfile>> entry : profilesByName(profiles).entrySet()) {
+ String name = entry.getKey();
+ if (shouldRegister(language, name, session)) {
+ register(language, name, entry.getValue(), session);
+ }
}
+ setDefault(language, profiles, session);
}
-
- setDefault(language, profiles);
+ session.commit();
+ esActiveRule.bulkRegisterActiveRules();
+ } finally {
+ MyBatis.closeQuietly(session);
+ profiler.stop();
}
- session.commit();
- profiler.stop();
-
- esActiveRule.bulkRegisterActiveRules();
}
- private void setDefault(String language, List<RulesProfile> profiles) {
- String propertyKey = "sonar.profile." + language;
- if (settings.getString(propertyKey) == null) {
- String defaultProfileName = defaultProfileName(profiles);
- LOGGER.info("Set default " + language + " profile: " + defaultProfileName);
- settings.saveProperty(propertyKey, defaultProfileName);
+ private static void verifyLanguage(String language, List<RulesProfile> profiles) {
+ if (profiles.isEmpty()) {
+ LOGGER.warn("No Quality Profile defined for language: " + language);
}
- }
- private Map<String, Collection<RulesProfile>> groupByName(List<RulesProfile> profiles) {
- return Multimaps.index(profiles,
- new Function<RulesProfile, String>() {
- public String apply(RulesProfile profile) {
- return profile.getName();
- }
- }).asMap();
- }
-
- private boolean shouldRegister(String language, String profileName) {
- return loadedTemplateDao.countByTypeAndKey(LoadedTemplateDto.QUALITY_PROFILE_TYPE, templateKey(language, profileName)) == 0;
- }
-
- private static String templateKey(String language, String profileName) {
- return StringUtils.lowerCase(language) + ":" + profileName;
+ Set<String> defaultProfileNames = defaultProfileNames(profiles);
+ if (defaultProfileNames.size() > 1) {
+ throw new SonarException("Several Quality Profiles are flagged as default for the language " + language + ": " + defaultProfileNames);
+ }
}
- private void register(String language, String name, Collection<RulesProfile> profiles) {
+ private void register(String language, String name, Collection<RulesProfile> profiles, SqlSession session) {
LOGGER.info("Register " + language + " profile: " + name);
- clean(language, name);
- insert(language, name, profiles);
- loadedTemplateDao.insert(new LoadedTemplateDto(templateKey(language, name), LoadedTemplateDto.QUALITY_PROFILE_TYPE));
- }
+ QProfile profile = qProfileLookup.profile(name, language, session);
+ if (profile != null) {
+ qProfileOperations.deleteProfile(profile.id(), session);
+ }
+ profile = qProfileOperations.newProfile(name, language, true, UserSession.get(), session);
- private void verifyLanguage(String language, List<RulesProfile> profiles) {
- if (profiles.isEmpty()) {
- LOGGER.warn("No Quality Profile defined for language: " + language);
+ for (RulesProfile currentRulesProfile : profiles) {
+ qProfileBackup.restoreFromActiveRules(profile, currentRulesProfile, session);
}
- Set<String> defaultProfileNames = defaultProfileNames(profiles);
- if (defaultProfileNames.size() > 1) {
- throw new SonarException("Several Quality Profiles are flagged as default for the language " + language + ": " +
- defaultProfileNames);
+ loadedTemplateDao.insert(new LoadedTemplateDto(templateKey(language, name), LoadedTemplateDto.QUALITY_PROFILE_TYPE), session);
+ }
+
+ private void setDefault(String language, List<RulesProfile> profiles, SqlSession session) {
+ String propertyKey = "sonar.profile." + language;
+ if (settings.getString(propertyKey) == null) {
+ String defaultProfileName = defaultProfileName(profiles);
+ LOGGER.info("Set default " + language + " profile: " + defaultProfileName);
+ settings.saveProperty(propertyKey, defaultProfileName);
}
}
/**
* @return profiles by language
*/
- private ListMultimap<String, RulesProfile> loadDefinitions() {
+ private ListMultimap<String, RulesProfile> profilesByLanguage() {
ListMultimap<String, RulesProfile> byLang = ArrayListMultimap.create();
for (ProfileDefinition definition : definitions) {
ValidationMessages validation = ValidationMessages.create();
@@ -169,6 +168,14 @@ public class RegisterQualityProfiles {
return byLang;
}
+ private static Map<String, Collection<RulesProfile>> profilesByName(List<RulesProfile> profiles) {
+ return Multimaps.index(profiles, new Function<RulesProfile, String>() {
+ public String apply(@Nullable RulesProfile profile) {
+ return profile != null ? profile.getName() : null;
+ }
+ }).asMap();
+ }
+
private static String defaultProfileName(List<RulesProfile> profiles) {
String defaultName = null;
boolean hasSonarWay = false;
@@ -198,47 +205,11 @@ public class RegisterQualityProfiles {
return names;
}
- //
- // PERSISTENCE
- //
-
- private void insert(String language, String name, Collection<RulesProfile> profiles) {
- RulesProfile persisted = RulesProfile.create(name, language);
- for (RulesProfile profile : profiles) {
- for (ActiveRule activeRule : profile.getActiveRules()) {
- Rule rule = persistedRule(activeRule);
- ActiveRule persistedActiveRule = persisted.activateRule(rule, activeRule.getSeverity());
- for (RuleParam param : rule.getParams()) {
- String value = StringUtils.defaultString(activeRule.getParameter(param.getKey()), param.getDefaultValue());
- if (value != null) {
- persistedActiveRule.setParameter(param.getKey(), value);
- }
- }
- }
- }
- session.saveWithoutFlush(persisted);
+ private boolean shouldRegister(String language, String profileName, SqlSession session) {
+ return loadedTemplateDao.countByTypeAndKey(LoadedTemplateDto.QUALITY_PROFILE_TYPE, templateKey(language, profileName), session) == 0;
}
- private Rule persistedRule(ActiveRule activeRule) {
- Rule rule = activeRule.getRule();
- if (rule != null && rule.getId() == null) {
- if (rule.getKey() != null) {
- rule = ruleFinder.findByKey(rule.getRepositoryKey(), rule.getKey());
-
- } else if (rule.getConfigKey() != null) {
- rule = ruleFinder.find(RuleQuery.create().withRepositoryKey(rule.getRepositoryKey()).withConfigKey(rule.getConfigKey()));
- }
- }
- if (rule == null) {
- throw new IllegalStateException(String.format("Rule '%s' has not been found.", activeRule.getRule()));
- }
- return rule;
- }
-
- private void clean(String language, String name) {
- List<RulesProfile> existingProfiles = session.getResults(RulesProfile.class, "language", language, "name", name);
- for (RulesProfile profile : existingProfiles) {
- session.removeWithoutFlush(profile);
- }
+ private static String templateKey(String language, String profileName) {
+ return StringUtils.lowerCase(language) + ":" + profileName;
}
}
diff --git a/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileActiveRuleOperationsTest.java b/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileActiveRuleOperationsTest.java
index e917baa9c55..296436bfe3d 100644
--- a/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileActiveRuleOperationsTest.java
+++ b/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileActiveRuleOperationsTest.java
@@ -30,6 +30,7 @@ import org.mockito.invocation.InvocationOnMock;
import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
import org.sonar.api.PropertyType;
+import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.Severity;
import org.sonar.api.rules.RulePriority;
import org.sonar.api.server.rule.RuleParamType;
@@ -43,6 +44,7 @@ import org.sonar.core.rule.RuleDto;
import org.sonar.core.rule.RuleParamDto;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.user.MockUserSession;
import org.sonar.server.user.UserSession;
import org.sonar.server.util.TypeValidations;
@@ -162,6 +164,47 @@ public class QProfileActiveRuleOperationsTest {
}
@Test
+ public void create_active_rule() throws Exception {
+ RuleKey ruleKey = RuleKey.of("repo", "key");
+ when(ruleDao.selectByKey(ruleKey, session)).thenReturn(new RuleDto().setId(10));
+
+ when(ruleDao.selectParametersByRuleId(eq(10), eq(session))).thenReturn(newArrayList(new RuleParamDto().setId(20).setName("max").setDefaultValue("10")));
+
+ operations.createActiveRule(1, ruleKey, Severity.CRITICAL, session);
+
+ ArgumentCaptor<ActiveRuleDto> activeRuleArgument = ArgumentCaptor.forClass(ActiveRuleDto.class);
+ verify(activeRuleDao).insert(activeRuleArgument.capture(), eq(session));
+ assertThat(activeRuleArgument.getValue().getRulId()).isEqualTo(10);
+ assertThat(activeRuleArgument.getValue().getSeverityString()).isEqualTo(Severity.CRITICAL);
+
+ ArgumentCaptor<ActiveRuleParamDto> activeRuleParamArgument = ArgumentCaptor.forClass(ActiveRuleParamDto.class);
+ verify(activeRuleDao).insert(activeRuleParamArgument.capture(), eq(session));
+ assertThat(activeRuleParamArgument.getValue().getKey()).isEqualTo("max");
+ assertThat(activeRuleParamArgument.getValue().getValue()).isEqualTo("10");
+
+ verifyZeroInteractions(session);
+ verifyZeroInteractions(profilesManager);
+ verifyZeroInteractions(esActiveRule);
+ }
+
+ @Test
+ public void fail_create_active_rule_when_rule_does_not_exists() throws Exception {
+ RuleKey ruleKey = RuleKey.of("repo", "key");
+ when(ruleDao.selectByKey(ruleKey, session)).thenReturn(null);
+
+ try {
+ operations.createActiveRule(1, ruleKey, Severity.CRITICAL, session);
+ } catch(Exception e) {
+ assertThat(e).isInstanceOf(NotFoundException.class);
+ }
+
+ verifyZeroInteractions(session);
+ verifyZeroInteractions(activeRuleDao);
+ verifyZeroInteractions(profilesManager);
+ verifyZeroInteractions(esActiveRule);
+ }
+
+ @Test
public void update_severity() throws Exception {
when(profileDao.selectById(1, session)).thenReturn(new QualityProfileDto().setId(1).setName("Default").setLanguage("java"));
when(ruleDao.selectById(10, session)).thenReturn(new RuleDto().setId(10));
@@ -366,6 +409,27 @@ public class QProfileActiveRuleOperationsTest {
}
@Test
+ public void update_active_rule_param_from_active_rule() throws Exception {
+ ActiveRuleDto activeRule = new ActiveRuleDto().setId(5).setProfileId(1).setRuleId(10).setSeverity(Severity.MINOR);
+ RuleParamDto ruleParam = new RuleParamDto().setRuleId(10).setName("max").setDefaultValue("20").setType(PropertyType.INTEGER.name());
+ when(ruleDao.selectParamByRuleAndKey(10, "max", session)).thenReturn(ruleParam);
+ ActiveRuleParamDto activeRuleParam = new ActiveRuleParamDto().setId(100).setActiveRuleId(5).setKey("max").setValue("20");
+ when(activeRuleDao.selectParamByActiveRuleAndKey(5, "max", session)).thenReturn(activeRuleParam);
+
+ operations.updateActiveRuleParam(activeRule, "max", "30", session);
+
+ ArgumentCaptor<ActiveRuleParamDto> argumentCaptor = ArgumentCaptor.forClass(ActiveRuleParamDto.class);
+ verify(activeRuleDao).update(argumentCaptor.capture(), eq(session));
+ assertThat(argumentCaptor.getValue().getId()).isEqualTo(100);
+ assertThat(argumentCaptor.getValue().getValue()).isEqualTo("30");
+
+ verify(typeValidations).validate(eq("30"), eq("INTEGER"), anyList());
+ verifyZeroInteractions(session);
+ verifyZeroInteractions(profilesManager);
+ verifyZeroInteractions(esActiveRule);
+ }
+
+ @Test
public void remove_active_rule_param() throws Exception {
ActiveRuleDto activeRule = new ActiveRuleDto().setId(5).setProfileId(1).setRuleId(10).setSeverity(Severity.MINOR);
when(activeRuleDao.selectById(5, session)).thenReturn(activeRule);
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 790b3042433..725674ba53b 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
@@ -29,21 +29,30 @@ 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;
+import org.sonar.api.rules.RulePriority;
import org.sonar.api.utils.ValidationMessages;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.core.persistence.MyBatis;
import org.sonar.core.preview.PreviewCache;
+import org.sonar.core.qualityprofile.db.ActiveRuleDto;
import org.sonar.jpa.session.DatabaseSessionFactory;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.user.MockUserSession;
+import org.sonar.server.user.UserSession;
import java.io.Reader;
import java.io.Writer;
+import java.util.List;
+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;
@@ -70,17 +79,25 @@ public class QProfileBackupTest {
XMLProfileParser xmlProfileParser;
@Mock
- XMLProfileSerializer xmlProfileSerializer;;
+ XMLProfileSerializer xmlProfileSerializer;
@Mock
QProfileLookup qProfileLookup;
@Mock
+ QProfileOperations qProfileOperations;
+
+ @Mock
+ QProfileActiveRuleOperations qProfileActiveRuleOperations;
+
+ @Mock
ESActiveRule esActiveRule;
@Mock
PreviewCache dryRunCache;
+ List<ProfileDefinition> definitions;
+
QProfileBackup backup;
@Before
@@ -88,7 +105,10 @@ public class QProfileBackupTest {
when(myBatis.openSession()).thenReturn(session);
when(sessionFactory.getSession()).thenReturn(hibernateSession);
- backup = new QProfileBackup(sessionFactory, xmlProfileParser, xmlProfileSerializer, myBatis, qProfileLookup, esActiveRule, dryRunCache);
+ definitions = newArrayList();
+
+ backup = new QProfileBackup(sessionFactory, xmlProfileParser, xmlProfileSerializer, myBatis, qProfileLookup, qProfileOperations, qProfileActiveRuleOperations,
+ esActiveRule, definitions, dryRunCache);
MockUserSession.set().setLogin("nicolas").setName("Nicolas").setGlobalPermissions(GlobalPermissions.QUALITY_PROFILE_ADMIN);
}
@@ -275,4 +295,77 @@ public class QProfileBackupTest {
verifyZeroInteractions(esActiveRule);
verifyZeroInteractions(dryRunCache);
}
+
+ @Test
+ public void restore_default_profiles_from_language() throws Exception {
+ String name = "Default";
+ String language = "java";
+
+ RulesProfile profile = RulesProfile.create(name, language);
+ Rule rule = Rule.create("pmd", "rule");
+ rule.createParameter("max");
+ ActiveRule activeRule = profile.activateRule(rule, RulePriority.BLOCKER);
+ activeRule.setParameter("max", "10");
+
+ ProfileDefinition profileDefinition = mock(ProfileDefinition.class);
+ when(profileDefinition.createProfile(any(ValidationMessages.class))).thenReturn(profile);
+
+ definitions.add(profileDefinition);
+
+ when(qProfileOperations.newProfile(eq(name), eq(language), eq(true), any(UserSession.class), eq(session))).thenReturn(new QProfile().setId(1));
+
+ backup.restoreDefaultProfilesFromLanguage(language);
+
+ verify(qProfileActiveRuleOperations).createActiveRule(eq(1), eq(RuleKey.of("pmd", "rule")), eq("BLOCKER"), eq(session));
+ verify(qProfileActiveRuleOperations).updateActiveRuleParam(any(ActiveRuleDto.class), eq("max"), eq("10"), eq(session));
+ verifyNoMoreInteractions(qProfileActiveRuleOperations);
+
+ verify(esActiveRule).bulkIndexProfile(eq(1), eq(session));
+ verify(dryRunCache).reportGlobalModification(session);
+ verify(session).commit();
+ }
+
+ @Test
+ public void restore_default_profiles_from_language_with_multiple_profiles_with_same_name_and_same_language() throws Exception {
+ RulesProfile profile1 = RulesProfile.create("Default", "java");
+ profile1.activateRule(Rule.create("pmd", "rule").setSeverity(RulePriority.BLOCKER), null);
+ ProfileDefinition profileDefinition1 = mock(ProfileDefinition.class);
+ when(profileDefinition1.createProfile(any(ValidationMessages.class))).thenReturn(profile1);
+ definitions.add(profileDefinition1);
+
+ RulesProfile profile2 = RulesProfile.create("Default", "java");
+ profile2.activateRule(Rule.create("checkstyle", "rule").setSeverity(RulePriority.MAJOR), null);
+ ProfileDefinition profileDefinition2 = mock(ProfileDefinition.class);
+ when(profileDefinition2.createProfile(any(ValidationMessages.class))).thenReturn(profile2);
+ definitions.add(profileDefinition2);
+
+ when(qProfileOperations.newProfile(eq("Default"), eq("java"), eq(true), any(UserSession.class), eq(session))).thenReturn(new QProfile().setId(1));
+
+ backup.restoreDefaultProfilesFromLanguage("java");
+
+ verify(qProfileActiveRuleOperations).createActiveRule(eq(1), eq(RuleKey.of("pmd", "rule")), eq("BLOCKER"), eq(session));
+ verify(qProfileActiveRuleOperations).createActiveRule(eq(1), eq(RuleKey.of("checkstyle", "rule")), eq("MAJOR"), eq(session));
+ verifyNoMoreInteractions(qProfileActiveRuleOperations);
+
+ verify(esActiveRule).bulkIndexProfile(eq(1), eq(session));
+ verify(dryRunCache).reportGlobalModification(session);
+ verify(session).commit();
+ }
+
+ @Test
+ public void not_restore_default_profiles_from_another_language() throws Exception {
+ RulesProfile profile = RulesProfile.create("Default", "java");
+ profile.activateRule(Rule.create("pmd", "rule").setSeverity(RulePriority.BLOCKER), null);
+ ProfileDefinition profileDefinition = mock(ProfileDefinition.class);
+ when(profileDefinition.createProfile(any(ValidationMessages.class))).thenReturn(profile);
+
+ definitions.add(profileDefinition);
+
+ backup.restoreDefaultProfilesFromLanguage("js");
+
+ verifyZeroInteractions(qProfileOperations);
+ verifyZeroInteractions(qProfileActiveRuleOperations);
+
+ verifyZeroInteractions(esActiveRule);
+ }
}
diff --git a/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileLookupTest.java b/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileLookupTest.java
index c0c54d6484d..4a7b871165e 100644
--- a/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileLookupTest.java
+++ b/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileLookupTest.java
@@ -81,7 +81,7 @@ public class QProfileLookupTest {
@Test
public void find_by_name_and_language() throws Exception {
- when(dao.selectByNameAndLanguage("Sonar Way", "java")).thenReturn(new QualityProfileDto().setId(1).setName("Sonar Way").setLanguage("java"));
+ when(dao.selectByNameAndLanguage("Sonar Way", "java", session)).thenReturn(new QualityProfileDto().setId(1).setName("Sonar Way").setLanguage("java"));
assertThat(search.profile("Sonar Way", "java")).isNotNull();
}
@@ -115,12 +115,11 @@ public class QProfileLookupTest {
verify(dao).selectByLanguage("java");
}
-
@Test
public void find_parent() throws Exception {
- when(dao.selectByNameAndLanguage("Sonar Way", "java")).thenReturn(new QualityProfileDto().setId(1).setName("Sonar Way").setLanguage("java"));
+ when(dao.selectByNameAndLanguage("Sonar Way", "java", session)).thenReturn(new QualityProfileDto().setId(1).setName("Sonar Way").setLanguage("java"));
search.parent(new QProfile().setName("Sonar Way with Findbugs").setLanguage("java").setParent("Sonar Way"));
- verify(dao).selectByNameAndLanguage("Sonar Way", "java");
+ verify(dao).selectByNameAndLanguage("Sonar Way", "java", session);
}
@Test
diff --git a/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileRepositoryExporterTest.java b/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileRepositoryExporterTest.java
index 8c10a98a024..5aec9e51aa6 100644
--- a/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileRepositoryExporterTest.java
+++ b/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileRepositoryExporterTest.java
@@ -44,6 +44,7 @@ import org.sonar.core.qualityprofile.db.ActiveRuleDto;
import org.sonar.core.qualityprofile.db.ActiveRuleParamDto;
import org.sonar.jpa.session.DatabaseSessionFactory;
import org.sonar.server.exceptions.BadRequestException;
+import org.sonar.server.exceptions.NotFoundException;
import java.io.Reader;
import java.io.Writer;
@@ -247,6 +248,26 @@ public class QProfileRepositoryExporterTest {
}
@Test
+ public void fail_to_export_profile_when_profile_is_missing() throws Exception {
+ RulesProfile profile = mock(RulesProfile.class);
+ when(profile.getId()).thenReturn(1);
+ when(hibernateSession.getSingleResult(any(Class.class), eq("id"), eq(1))).thenReturn(null);
+
+ ProfileExporter exporter = mock(ProfileExporter.class);
+ when(exporter.getKey()).thenReturn("pmd");
+ exporters.add(exporter);
+
+ try {
+ operations.exportToXml(new QProfile().setId(1), "pmd");
+ fail();
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(NotFoundException.class).hasMessage("This profile does not exists.");
+ }
+
+ verify(exporter, never()).exportProfile(any(RulesProfile.class), any(Writer.class));
+ }
+
+ @Test
public void get_profile_exporter_mime_type() throws Exception {
ProfileExporter exporter = mock(ProfileExporter.class);
when(exporter.getKey()).thenReturn("pmd");
diff --git a/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfilesMediumTest.java b/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfilesMediumTest.java
new file mode 100644
index 00000000000..941c5859068
--- /dev/null
+++ b/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfilesMediumTest.java
@@ -0,0 +1,148 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.sonar.server.qualityprofile;
+
+import org.junit.Test;
+import org.sonar.api.profiles.ProfileDefinition;
+import org.sonar.api.profiles.RulesProfile;
+import org.sonar.api.rule.Severity;
+import org.sonar.api.rules.ActiveRule;
+import org.sonar.api.rules.RuleParam;
+import org.sonar.api.rules.RulePriority;
+import org.sonar.api.server.rule.RuleParamType;
+import org.sonar.api.server.rule.RulesDefinition;
+import org.sonar.api.utils.ValidationMessages;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.server.paging.Paging;
+import org.sonar.server.rule.Rule;
+import org.sonar.server.rule.RuleQuery;
+import org.sonar.server.rule.Rules;
+import org.sonar.server.tester.ServerTester;
+import org.sonar.server.user.MockUserSession;
+
+import java.util.List;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static org.fest.assertions.Assertions.assertThat;
+
+public class QProfilesMediumTest {
+
+ @org.junit.Rule
+ public ServerTester serverTester = new ServerTester().addExtensions(XooRulesDefinition.class, XooProfileDefinition.class);
+
+ @Test
+ public void register_profile_at_startup() throws Exception {
+ QProfiles qProfiles = serverTester.get(QProfiles.class);
+ List<QProfile> profiles = qProfiles.profilesByLanguage("xoo");
+ assertThat(profiles).hasSize(1);
+
+ QProfile profile = profiles.get(0);
+ assertThat(profile.id()).isNotNull();
+ assertThat(profile.name()).isEqualTo("Basic");
+ assertThat(profile.language()).isEqualTo("xoo");
+ assertThat(qProfiles.defaultProfile("xoo").name()).isEqualTo("Basic");
+
+ assertThat(qProfiles.searchProfileRules(ProfileRuleQuery.create(profile.id()), Paging.create(10, 1)).rules()).hasSize(2);
+
+ QProfileRule qProfileRule = qProfiles.searchProfileRules(ProfileRuleQuery.create(profile.id()).setNameOrKey("x1"), Paging.create(10, 1)).rules().get(0);
+ assertThat(qProfileRule.key()).isEqualTo("x1");
+ assertThat(qProfileRule.severity()).isEqualTo("MAJOR");
+ assertThat(qProfileRule.params()).hasSize(1);
+
+ QProfileRuleParam qProfileRuleParam = qProfileRule.params().get(0);
+ assertThat(qProfileRuleParam.key()).isEqualTo("acceptWhitespace");
+ assertThat(qProfileRuleParam.value()).isEqualTo("true");
+ }
+
+ @Test
+ public void restore_default_profile_from_language() throws Exception {
+ MockUserSession.set().setLogin("julien").setName("Julien").setGlobalPermissions(GlobalPermissions.QUALITY_PROFILE_ADMIN);
+
+ QProfiles qProfiles = serverTester.get(QProfiles.class);
+ QProfileBackup qProfileBackup = serverTester.get(QProfileBackup.class);
+ Rules rules = serverTester.get(Rules.class);
+
+ QProfile profile = qProfiles.profile("Basic", "xoo");
+
+ // Update rule x1 : update severity and update param value
+ Rule rule1 = rules.find(RuleQuery.builder().searchQuery("x1").build()).results().iterator().next();
+ qProfiles.updateActiveRuleParam(qProfiles.findByProfileAndRule(profile.id(), rule1.id()).activeRuleId(), "acceptWhitespace", "false");
+ qProfiles.activateRule(profile.id(), rule1.id(), "INFO");
+
+ // Disable rule x2
+ Rule rule2 = rules.find(RuleQuery.builder().searchQuery("x2").build()).results().iterator().next();
+ qProfiles.deactivateRule(qProfiles.profile("Basic", "xoo").id(), rule2.id());
+
+ // Renamed profile
+ qProfiles.renameProfile(profile.id(), "Old Basic");
+
+ // Restore default profiles of xoo
+ qProfileBackup.restoreDefaultProfilesFromLanguage("xoo");
+
+ // Reload profile
+ profile = qProfiles.profile("Basic", "xoo");
+
+ // Verify rule x1
+ QProfileRule qProfileRule = qProfiles.searchProfileRules(ProfileRuleQuery.create(profile.id()).setNameOrKey("x1"), Paging.create(10, 1)).rules().get(0);
+ assertThat(qProfileRule.severity()).isEqualTo("MAJOR");
+ QProfileRuleParam qProfileRuleParam = qProfileRule.params().get(0);
+ assertThat(qProfileRuleParam.key()).isEqualTo("acceptWhitespace");
+ assertThat(qProfileRuleParam.value()).isEqualTo("true");
+
+ // Verify rule x2
+ assertThat(qProfiles.searchProfileRules(ProfileRuleQuery.create(profile.id()).setNameOrKey("x2"), Paging.create(10, 1)).rules().get(0)).isNotNull();
+ }
+
+ public static class XooProfileDefinition extends ProfileDefinition {
+ @Override
+ public RulesProfile createProfile(ValidationMessages validation) {
+ final RulesProfile profile = RulesProfile.create("Basic", "xoo");
+ ActiveRule activeRule1 = profile.activateRule(
+ org.sonar.api.rules.Rule.create("xoo", "x1").setParams(newArrayList(new RuleParam().setKey("acceptWhitespace"))),
+ RulePriority.MAJOR);
+ activeRule1.setParameter("acceptWhitespace", "true");
+
+ profile.activateRule(org.sonar.api.rules.Rule.create("xoo", "x2"), RulePriority.BLOCKER);
+ return profile;
+ }
+ }
+
+ public static class XooRulesDefinition implements RulesDefinition {
+ @Override
+ public void define(Context context) {
+ NewRepository repository = context.createRepository("xoo", "xoo").setName("Xoo Repo");
+ repository.createRule("x1")
+ .setName("x1 name")
+ .setHtmlDescription("x1 desc")
+ .setSeverity(Severity.MINOR)
+ .createParam("acceptWhitespace")
+ .setDefaultValue("false")
+ .setType(RuleParamType.BOOLEAN)
+ .setDescription("Accept whitespaces on the line");
+
+ repository.createRule("x2")
+ .setName("x2 name")
+ .setHtmlDescription("x2 desc")
+ .setSeverity(Severity.MAJOR);
+ repository.done();
+ }
+ }
+}
diff --git a/sonar-server/src/test/java/org/sonar/server/rule/RuleRegistryTest.java b/sonar-server/src/test/java/org/sonar/server/rule/RuleRegistryTest.java
index 64a30746787..a30b1cd8da9 100644
--- a/sonar-server/src/test/java/org/sonar/server/rule/RuleRegistryTest.java
+++ b/sonar-server/src/test/java/org/sonar/server/rule/RuleRegistryTest.java
@@ -37,11 +37,7 @@ import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.Severity;
import org.sonar.core.persistence.MyBatis;
import org.sonar.core.profiling.Profiling;
-import org.sonar.core.rule.RuleDao;
-import org.sonar.core.rule.RuleDto;
-import org.sonar.core.rule.RuleParamDto;
-import org.sonar.core.rule.RuleRuleTagDto;
-import org.sonar.core.rule.RuleTagType;
+import org.sonar.core.rule.*;
import org.sonar.core.technicaldebt.db.CharacteristicDao;
import org.sonar.core.technicaldebt.db.CharacteristicDto;
import org.sonar.server.es.ESIndex;
@@ -490,7 +486,6 @@ public class RuleRegistryTest {
assertThat(registry.find(RuleQuery.builder().debtCharacteristics(newArrayList("MODULARITY")).build()).results()).hasSize(1);
assertThat(registry.find(RuleQuery.builder().debtCharacteristics(newArrayList("REUSABILITY")).build()).results()).hasSize(1);
assertThat(registry.find(RuleQuery.builder().debtCharacteristics(newArrayList("PORTABILITY")).build()).results()).hasSize(1);
- // FIXME query has to be updated
assertThat(registry.find(RuleQuery.builder().debtCharacteristics(newArrayList("MODULARITY", "PORTABILITY")).build()).results()).hasSize(2);
assertThat(registry.find(RuleQuery.builder().debtCharacteristics(newArrayList("MODULARITY", "REUSABILITY")).build()).results()).hasSize(1);
assertThat(registry.find(RuleQuery.builder().debtCharacteristics(newArrayList("unknown")).build()).results()).isEmpty();
diff --git a/sonar-server/src/test/java/org/sonar/server/startup/RegisterQualityProfilesTest.java b/sonar-server/src/test/java/org/sonar/server/startup/RegisterQualityProfilesTest.java
new file mode 100644
index 00000000000..41665aff4a0
--- /dev/null
+++ b/sonar-server/src/test/java/org/sonar/server/startup/RegisterQualityProfilesTest.java
@@ -0,0 +1,335 @@
+/*
+ * 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.startup;
+
+import org.apache.ibatis.session.SqlSession;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.sonar.api.profiles.ProfileDefinition;
+import org.sonar.api.profiles.RulesProfile;
+import org.sonar.api.utils.SonarException;
+import org.sonar.api.utils.ValidationMessages;
+import org.sonar.core.persistence.MyBatis;
+import org.sonar.core.qualityprofile.db.QualityProfileDao;
+import org.sonar.core.template.LoadedTemplateDao;
+import org.sonar.core.template.LoadedTemplateDto;
+import org.sonar.server.platform.PersistentSettings;
+import org.sonar.server.qualityprofile.*;
+import org.sonar.server.user.UserSession;
+
+import java.util.List;
+
+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.eq;
+import static org.mockito.Mockito.*;
+
+@RunWith(MockitoJUnitRunner.class)
+public class RegisterQualityProfilesTest {
+
+ @Mock
+ QualityProfileDao qualityProfileDao;
+
+ @Mock
+ LoadedTemplateDao loadedTemplateDao;
+
+ @Mock
+ QProfileBackup qProfileBackup;
+
+ @Mock
+ QProfileOperations qProfileOperations;
+
+ @Mock
+ QProfileLookup qProfileLookup;
+
+ @Mock
+ ESActiveRule esActiveRule;
+
+ @Mock
+ MyBatis myBatis;
+
+ @Mock
+ SqlSession session;
+
+ @Mock
+ PersistentSettings settings;
+
+ List<ProfileDefinition> definitions;
+
+ RegisterQualityProfiles registerQualityProfiles;
+
+ @Before
+ public void setUp() throws Exception {
+ when(myBatis.openSession()).thenReturn(session);
+
+ definitions = newArrayList();
+ registerQualityProfiles = new RegisterQualityProfiles(myBatis, settings, esActiveRule, loadedTemplateDao, qProfileBackup, qProfileOperations, qProfileLookup, null, definitions);
+ }
+
+ @Test
+ public void register_profile() throws Exception {
+ RulesProfile rulesProfile = RulesProfile.create("Default", "java");
+ ProfileDefinition profileDefinition = mock(ProfileDefinition.class);
+ when(profileDefinition.createProfile(any(ValidationMessages.class))).thenReturn(rulesProfile);
+ definitions.add(profileDefinition);
+
+ QProfile profile = new QProfile();
+ when(qProfileOperations.newProfile(eq("Default"), eq("java"), eq(true), any(UserSession.class), eq(session))).thenReturn(profile);
+
+ registerQualityProfiles.start();
+
+ verify(qProfileBackup).restoreFromActiveRules(eq(profile), eq(rulesProfile), eq(session));
+
+ ArgumentCaptor<LoadedTemplateDto> templateCaptor = ArgumentCaptor.forClass(LoadedTemplateDto.class);
+ verify(loadedTemplateDao).insert(templateCaptor.capture(), eq(session));
+ assertThat(templateCaptor.getValue().getKey()).isEqualTo("java:Default");
+ assertThat(templateCaptor.getValue().getType()).isEqualTo("QUALITY_PROFILE");
+
+ verify(settings).saveProperty("sonar.profile.java", "Default");
+
+ verify(session).commit();
+
+ verify(esActiveRule).bulkRegisterActiveRules();
+ }
+
+ @Test
+ public void register_profiles_with_different_languages() throws Exception {
+ RulesProfile rulesProfile1 = RulesProfile.create("Default", "java");
+ ProfileDefinition profileDefinition1 = mock(ProfileDefinition.class);
+ when(profileDefinition1.createProfile(any(ValidationMessages.class))).thenReturn(rulesProfile1);
+ definitions.add(profileDefinition1);
+
+ RulesProfile rulesProfile2 = RulesProfile.create("Default", "js");
+ ProfileDefinition profileDefinition2 = mock(ProfileDefinition.class);
+ when(profileDefinition2.createProfile(any(ValidationMessages.class))).thenReturn(rulesProfile2);
+ definitions.add(profileDefinition2);
+
+ QProfile profile1 = new QProfile();
+ when(qProfileOperations.newProfile(eq("Default"), eq("java"), eq(true), any(UserSession.class), eq(session))).thenReturn(profile1);
+
+ QProfile profile2 = new QProfile();
+ when(qProfileOperations.newProfile(eq("Default"), eq("js"), eq(true), any(UserSession.class), eq(session))).thenReturn(profile2);
+
+ registerQualityProfiles.start();
+
+ verify(qProfileBackup).restoreFromActiveRules(eq(profile1), eq(rulesProfile1), eq(session));
+ verify(qProfileBackup).restoreFromActiveRules(eq(profile2), eq(rulesProfile2), eq(session));
+ verify(loadedTemplateDao, times(2)).insert(any(LoadedTemplateDto.class), eq(session));
+ verify(session).commit();
+
+ verify(settings).saveProperty("sonar.profile.java", "Default");
+ verify(settings).saveProperty("sonar.profile.js", "Default");
+ }
+
+ @Test
+ public void register_two_profiles_with_one_rules_profile_being_default() throws Exception {
+ RulesProfile rulesProfile1 = RulesProfile.create("Basic", "java");
+ ProfileDefinition profileDefinition1 = mock(ProfileDefinition.class);
+ when(profileDefinition1.createProfile(any(ValidationMessages.class))).thenReturn(rulesProfile1);
+ definitions.add(profileDefinition1);
+
+ // Default profile for java
+ RulesProfile rulesProfile2 = RulesProfile.create("Default", "java");
+ rulesProfile2.setDefaultProfile(true);
+ ProfileDefinition profileDefinition2 = mock(ProfileDefinition.class);
+ when(profileDefinition2.createProfile(any(ValidationMessages.class))).thenReturn(rulesProfile2);
+ definitions.add(profileDefinition2);
+
+ QProfile profile1 = new QProfile();
+ when(qProfileOperations.newProfile(eq("Basic"), eq("java"), eq(true), any(UserSession.class), eq(session))).thenReturn(profile1);
+
+ QProfile profile2 = new QProfile();
+ when(qProfileOperations.newProfile(eq("Default"), eq("java"), eq(true), any(UserSession.class), eq(session))).thenReturn(profile2);
+
+ registerQualityProfiles.start();
+
+ verify(settings).saveProperty("sonar.profile.java", "Default");
+ }
+
+ @Test
+ public void register_two_profiles_with_no_rules_profile_being_default() throws Exception {
+ RulesProfile rulesProfile1 = RulesProfile.create("Basic", "java");
+ ProfileDefinition profileDefinition1 = mock(ProfileDefinition.class);
+ when(profileDefinition1.createProfile(any(ValidationMessages.class))).thenReturn(rulesProfile1);
+ definitions.add(profileDefinition1);
+
+ RulesProfile rulesProfile2 = RulesProfile.create("Default", "java");
+ ProfileDefinition profileDefinition2 = mock(ProfileDefinition.class);
+ when(profileDefinition2.createProfile(any(ValidationMessages.class))).thenReturn(rulesProfile2);
+ definitions.add(profileDefinition2);
+
+ QProfile profile1 = new QProfile();
+ when(qProfileOperations.newProfile(eq("Basic"), eq("java"), eq(true), any(UserSession.class), eq(session))).thenReturn(profile1);
+
+ QProfile profile2 = new QProfile();
+ when(qProfileOperations.newProfile(eq("Default"), eq("java"), eq(true), any(UserSession.class), eq(session))).thenReturn(profile2);
+
+ registerQualityProfiles.start();
+
+ // No rules profile is defined as default, first one will be the default one
+ verify(settings).saveProperty("sonar.profile.java", "Basic");
+ }
+
+ @Test
+ public void register_two_profiles_with_one_rules_profile_name_using_sonar_way() throws Exception {
+ RulesProfile rulesProfile1 = RulesProfile.create("Basic", "java");
+ ProfileDefinition profileDefinition1 = mock(ProfileDefinition.class);
+ when(profileDefinition1.createProfile(any(ValidationMessages.class))).thenReturn(rulesProfile1);
+ definitions.add(profileDefinition1);
+
+ // This profile is using 'Sonar way' name, it will be the default one
+ RulesProfile rulesProfile2 = RulesProfile.create("Sonar way", "java");
+ ProfileDefinition profileDefinition2 = mock(ProfileDefinition.class);
+ when(profileDefinition2.createProfile(any(ValidationMessages.class))).thenReturn(rulesProfile2);
+ definitions.add(profileDefinition2);
+
+ QProfile profile1 = new QProfile();
+ when(qProfileOperations.newProfile(eq("Basic"), eq("java"), eq(true), any(UserSession.class), eq(session))).thenReturn(profile1);
+
+ QProfile profile2 = new QProfile();
+ when(qProfileOperations.newProfile(eq("Sonar way"), eq("java"), eq(true), any(UserSession.class), eq(session))).thenReturn(profile2);
+
+ registerQualityProfiles.start();
+
+ verify(settings).saveProperty("sonar.profile.java", "Sonar way");
+ }
+
+ @Test
+ public void fail_to_register_two_profiles_both_being_default() throws Exception {
+ RulesProfile rulesProfile1 = RulesProfile.create("Basic", "java");
+ rulesProfile1.setDefaultProfile(true);
+ ProfileDefinition profileDefinition1 = mock(ProfileDefinition.class);
+ when(profileDefinition1.createProfile(any(ValidationMessages.class))).thenReturn(rulesProfile1);
+ definitions.add(profileDefinition1);
+
+ RulesProfile rulesProfile2 = RulesProfile.create("Default", "java");
+ rulesProfile2.setDefaultProfile(true);
+ ProfileDefinition profileDefinition2 = mock(ProfileDefinition.class);
+ when(profileDefinition2.createProfile(any(ValidationMessages.class))).thenReturn(rulesProfile2);
+ definitions.add(profileDefinition2);
+
+ try {
+ registerQualityProfiles.start();
+ fail();
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(SonarException.class);
+ }
+
+ verifyZeroInteractions(qProfileLookup);
+ verifyZeroInteractions(qProfileBackup);
+ verifyZeroInteractions(qProfileOperations);
+ verifyZeroInteractions(settings);
+ }
+
+ @Test
+ public void register_profile_from_multiple_rule_profiles_with_same_name_and_language() throws Exception {
+ RulesProfile rulesProfile1 = RulesProfile.create("Default", "java");
+ ProfileDefinition profileDefinition1 = mock(ProfileDefinition.class);
+ when(profileDefinition1.createProfile(any(ValidationMessages.class))).thenReturn(rulesProfile1);
+ definitions.add(profileDefinition1);
+
+ RulesProfile rulesProfile2 = RulesProfile.create("Default", "java");
+ ProfileDefinition profileDefinition2 = mock(ProfileDefinition.class);
+ when(profileDefinition2.createProfile(any(ValidationMessages.class))).thenReturn(rulesProfile2);
+ definitions.add(profileDefinition2);
+
+ QProfile profile = new QProfile();
+ when(qProfileOperations.newProfile(eq("Default"), eq("java"), eq(true), any(UserSession.class), eq(session))).thenReturn(profile);
+
+ registerQualityProfiles.start();
+
+ ArgumentCaptor<RulesProfile> rulesProfileCaptor = ArgumentCaptor.forClass(RulesProfile.class);
+ verify(qProfileBackup, times(2)).restoreFromActiveRules(eq(profile), rulesProfileCaptor.capture(), eq(session));
+ assertThat(rulesProfileCaptor.getAllValues().get(0)).isEqualTo(rulesProfile1);
+ assertThat(rulesProfileCaptor.getAllValues().get(1)).isEqualTo(rulesProfile2);
+
+ verify(session).commit();
+ }
+
+ @Test
+ public void not_register_already_registered_profile() throws Exception {
+ ProfileDefinition profileDefinition = mock(ProfileDefinition.class);
+ when(profileDefinition.createProfile(any(ValidationMessages.class))).thenReturn(RulesProfile.create("Default", "java"));
+ definitions.add(profileDefinition);
+
+ when(loadedTemplateDao.countByTypeAndKey(anyString(), anyString(), eq(session))).thenReturn(1);
+
+ registerQualityProfiles.start();
+
+ verify(loadedTemplateDao, never()).insert(any(LoadedTemplateDto.class), eq(session));
+ verifyZeroInteractions(qProfileBackup);
+ verifyZeroInteractions(qProfileOperations);
+
+ verify(settings).saveProperty("sonar.profile.java", "Default");
+ }
+
+ @Test
+ public void not_set_profile_as_default_if_language_has_already_a_default_profile() throws Exception {
+ ProfileDefinition profileDefinition = mock(ProfileDefinition.class);
+ when(profileDefinition.createProfile(any(ValidationMessages.class))).thenReturn(RulesProfile.create("Default", "java"));
+ definitions.add(profileDefinition);
+
+ QProfile profile = new QProfile();
+ when(qProfileOperations.newProfile(eq("Default"), eq("java"), eq(true), any(UserSession.class), eq(session))).thenReturn(profile);
+
+ when(settings.getString(eq("sonar.profile.java"))).thenReturn("Existing Default Profile");
+
+ registerQualityProfiles.start();
+
+ verify(settings, never()).saveProperty(anyString(), anyString());
+ }
+
+ @Test
+ public void delete_existing_profile_if_template_is_empty() throws Exception {
+ RulesProfile rulesProfile = RulesProfile.create("Default", "java");
+ ProfileDefinition profileDefinition = mock(ProfileDefinition.class);
+ when(profileDefinition.createProfile(any(ValidationMessages.class))).thenReturn(rulesProfile);
+ definitions.add(profileDefinition);
+
+ QProfile profile = new QProfile();
+ when(qProfileLookup.profile(eq("Default"), eq("java"), eq(session))).thenReturn(new QProfile());
+ when(qProfileOperations.newProfile(eq("Default"), eq("java"), eq(true), any(UserSession.class), eq(session))).thenReturn(profile);
+
+ when(loadedTemplateDao.countByTypeAndKey(anyString(), anyString(), eq(session))).thenReturn(0);
+
+ registerQualityProfiles.start();
+
+ verify(qProfileOperations).deleteProfile(anyInt(), eq(session));
+ verify(qProfileBackup).restoreFromActiveRules(eq(profile), eq(rulesProfile), eq(session));
+ verify(session).commit();
+ }
+
+ @Test
+ public void not_fail_if_no_profile() throws Exception {
+ registerQualityProfiles.start();
+
+ verifyZeroInteractions(qProfileLookup);
+ verifyZeroInteractions(qProfileBackup);
+ verifyZeroInteractions(qProfileOperations);
+ verifyZeroInteractions(settings);
+ }
+}
diff --git a/sonar-server/src/test/java/org/sonar/server/tester/ServerTester.java b/sonar-server/src/test/java/org/sonar/server/tester/ServerTester.java
index ff439395243..f5a443491dd 100644
--- a/sonar-server/src/test/java/org/sonar/server/tester/ServerTester.java
+++ b/sonar-server/src/test/java/org/sonar/server/tester/ServerTester.java
@@ -38,6 +38,8 @@ public class ServerTester extends ExternalResource {
private File tempDir;
private Platform platform;
+ private Object[] extensions;
+
@Override
protected void before() {
tempDir = createTempDir();
@@ -47,7 +49,7 @@ public class ServerTester extends ExternalResource {
properties.setProperty(DatabaseProperties.PROP_URL, "jdbc:h2:" + tempDir.getAbsolutePath() + "/h2");
platform = new Platform();
platform.init(properties);
-
+ platform.addExtensions(extensions);
platform.doStart();
}
@@ -70,6 +72,14 @@ public class ServerTester extends ExternalResource {
FileUtils.deleteQuietly(tempDir);
}
+ public ServerTester addExtensions(Object... extensions) {
+ this.extensions = extensions;
+ return this;
+ }
+
+ /**
+ * Get a component from the platform
+ */
public <C> C get(Class<C> component) {
if (platform == null) {
throw new IllegalStateException("Not started");