aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-server
diff options
context:
space:
mode:
authorJulien Lancelot <julien.lancelot@sonarsource.com>2014-03-24 13:28:04 +0100
committerJulien Lancelot <julien.lancelot@sonarsource.com>2014-03-24 13:28:13 +0100
commit15f82899fb01062f6fe511ca4f18e1aa55690d47 (patch)
treee631ef51f39cf1da6eb0893434acf0ea2943e345 /sonar-server
parent2a3aba9720dd5c2afa717ec30b479402c1058c59 (diff)
downloadsonarqube-15f82899fb01062f6fe511ca4f18e1aa55690d47.tar.gz
sonarqube-15f82899fb01062f6fe511ca4f18e1aa55690d47.zip
SONAR-5121 Add restore from XMl actions
Diffstat (limited to 'sonar-server')
-rw-r--r--sonar-server/src/main/java/org/sonar/server/debt/DebtModelRestore.java142
-rw-r--r--sonar-server/src/main/java/org/sonar/server/debt/DebtModelService.java23
-rw-r--r--sonar-server/src/main/java/org/sonar/server/debt/DebtModelSynchronizer.java1
-rw-r--r--sonar-server/src/main/java/org/sonar/server/debt/DebtRulesXMLImporter.java51
-rw-r--r--sonar-server/src/main/java/org/sonar/server/rule/DeprecatedRulesDefinition.java14
-rw-r--r--sonar-server/src/test/java/org/sonar/server/debt/DebtModelRestoreTest.java285
-rw-r--r--sonar-server/src/test/java/org/sonar/server/debt/DebtModelServiceTest.java14
-rw-r--r--sonar-server/src/test/java/org/sonar/server/debt/DebtRulesXMLImporterTest.java57
-rw-r--r--sonar-server/src/test/java/org/sonar/server/rule/DeprecatedRulesDefinitionTest.java6
9 files changed, 482 insertions, 111 deletions
diff --git a/sonar-server/src/main/java/org/sonar/server/debt/DebtModelRestore.java b/sonar-server/src/main/java/org/sonar/server/debt/DebtModelRestore.java
index 380d4d5a379..205850d4f67 100644
--- a/sonar-server/src/main/java/org/sonar/server/debt/DebtModelRestore.java
+++ b/sonar-server/src/main/java/org/sonar/server/debt/DebtModelRestore.java
@@ -25,10 +25,12 @@ import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.ObjectUtils;
+import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.ibatis.session.SqlSession;
import org.sonar.api.ServerComponent;
import org.sonar.api.server.debt.DebtCharacteristic;
import org.sonar.api.utils.System2;
+import org.sonar.api.utils.ValidationMessages;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.core.persistence.MyBatis;
import org.sonar.core.rule.RuleDao;
@@ -58,17 +60,18 @@ public class DebtModelRestore implements ServerComponent {
private final DebtModelOperations debtModelOperations;
private final TechnicalDebtModelRepository debtModelPluginRepository;
private final RuleRepositories ruleRepositories;
- private final DebtCharacteristicsXMLImporter importer;
+ private final DebtCharacteristicsXMLImporter characteristicsXMLImporter;
+ private final DebtRulesXMLImporter rulesXMLImporter;
private final System2 system2;
public DebtModelRestore(MyBatis mybatis, CharacteristicDao dao, RuleDao ruleDao, DebtModelOperations debtModelOperations, TechnicalDebtModelRepository debtModelPluginRepository,
- RuleRepositories ruleRepositories, DebtCharacteristicsXMLImporter importer) {
- this(mybatis, dao, ruleDao, debtModelOperations, debtModelPluginRepository, ruleRepositories, importer, System2.INSTANCE);
+ RuleRepositories ruleRepositories, DebtCharacteristicsXMLImporter characteristicsXMLImporter, DebtRulesXMLImporter rulesXMLImporter) {
+ this(mybatis, dao, ruleDao, debtModelOperations, debtModelPluginRepository, ruleRepositories, characteristicsXMLImporter, rulesXMLImporter, System2.INSTANCE);
}
@VisibleForTesting
DebtModelRestore(MyBatis mybatis, CharacteristicDao dao, RuleDao ruleDao, DebtModelOperations debtModelOperations, TechnicalDebtModelRepository debtModelPluginRepository,
- RuleRepositories ruleRepositories, DebtCharacteristicsXMLImporter importer,
+ RuleRepositories ruleRepositories, DebtCharacteristicsXMLImporter characteristicsXMLImporter, DebtRulesXMLImporter rulesXMLImporter,
System2 system2) {
this.mybatis = mybatis;
this.dao = dao;
@@ -76,34 +79,63 @@ public class DebtModelRestore implements ServerComponent {
this.debtModelOperations = debtModelOperations;
this.debtModelPluginRepository = debtModelPluginRepository;
this.ruleRepositories = ruleRepositories;
- this.importer = importer;
+ this.characteristicsXMLImporter = characteristicsXMLImporter;
+ this.rulesXMLImporter = rulesXMLImporter;
this.system2 = system2;
}
/**
* Restore from provided model
*/
- public void restore() {
- restore(Collections.<RuleRepositories.Repository>emptyList());
+ public ValidationMessages restore() {
+ ValidationMessages validationMessages = ValidationMessages.create();
+ restore(loadModelFromPlugin(TechnicalDebtModelRepository.DEFAULT_MODEL), Collections.<DebtRulesXMLImporter.RuleDebt>emptyList(),
+ Collections.<RuleRepositories.Repository>emptyList(), false, validationMessages);
+ return validationMessages;
}
/**
* Restore from plugins providing rules for a given language
*/
- public void restore(String languageKey) {
- restore(ruleRepositories.repositoriesForLang(languageKey));
+ public ValidationMessages restore(String languageKey) {
+ ValidationMessages validationMessages = ValidationMessages.create();
+ restore(loadModelFromPlugin(TechnicalDebtModelRepository.DEFAULT_MODEL), Collections.<DebtRulesXMLImporter.RuleDebt>emptyList(),
+ ruleRepositories.repositoriesForLang(languageKey), false, validationMessages);
+ return validationMessages;
}
- private void restore(Collection<RuleRepositories.Repository> repositories) {
+ /**
+ * Restore model from a given XML model
+ */
+ public ValidationMessages restoreFromXml(String xml) {
+ DebtModel debtModel = characteristicsXMLImporter.importXML(xml);
+ ValidationMessages validationMessages = ValidationMessages.create();
+ List<DebtRulesXMLImporter.RuleDebt> ruleDebts = rulesXMLImporter.importXML(xml, validationMessages);
+ restore(debtModel, ruleDebts, Collections.<RuleRepositories.Repository>emptyList(), true, validationMessages);
+ return validationMessages;
+ }
+
+ /**
+ * Restore model from a given XML model and a given language
+ */
+ public ValidationMessages restoreFromXml(String xml, String languageKey) {
+ DebtModel debtModel = characteristicsXMLImporter.importXML(xml);
+ ValidationMessages validationMessages = ValidationMessages.create();
+ List<DebtRulesXMLImporter.RuleDebt> ruleDebts = rulesXMLImporter.importXML(xml, validationMessages);
+ restore(debtModel, ruleDebts, ruleRepositories.repositoriesForLang(languageKey), true, validationMessages);
+ return validationMessages;
+ }
+
+ private void restore(DebtModel modelToImport, List<DebtRulesXMLImporter.RuleDebt> ruleDebts, Collection<RuleRepositories.Repository> repositories,
+ boolean disableCharacteristicWhenRuleNotFound, ValidationMessages validationMessages) {
checkPermission();
Date updateDate = new Date(system2.now());
SqlSession session = mybatis.openSession();
try {
List<CharacteristicDto> persisted = dao.selectEnabledCharacteristics();
- DebtModel providedModel = loadModelFromXml(TechnicalDebtModelRepository.DEFAULT_MODEL);
- restoreCharacteristics(providedModel, persisted, updateDate, session);
- resetOverridingRuleDebt(repositories, updateDate, session);
+ List<CharacteristicDto> characteristicDtos = restoreCharacteristics(modelToImport, persisted, updateDate, session);
+ restoreRules(characteristicDtos, repositories, ruleDebts, disableCharacteristicWhenRuleNotFound, validationMessages, updateDate, session);
session.commit();
} finally {
@@ -111,31 +143,64 @@ public class DebtModelRestore implements ServerComponent {
}
}
- private void resetOverridingRuleDebt(Collection<RuleRepositories.Repository> repositories, Date updateDate, SqlSession session) {
+ private void restoreRules(List<CharacteristicDto> characteristicDtos, Collection<RuleRepositories.Repository> repositories, List<DebtRulesXMLImporter.RuleDebt> ruleDebts,
+ boolean disableCharacteristicWhenRuleNotFound, ValidationMessages validationMessages, Date updateDate, SqlSession session) {
List<String> repositoryKeys = newArrayList(Iterables.transform(repositories, new Function<RuleRepositories.Repository, String>() {
@Override
public String apply(RuleRepositories.Repository input) {
return input.getKey();
}
}));
- for (RuleDto rule : ruleDao.selectOverridingDebt(repositoryKeys, session)) {
- rule.setCharacteristicId(null);
- rule.setRemediationFunction(null);
- rule.setRemediationFactor(null);
- rule.setRemediationOffset(null);
- rule.setUpdatedAt(updateDate);
- ruleDao.update(rule, session);
- // TODO index rules in E/S
+ for (RuleDto rule : ruleDao.selectEnablesAndNonManual(session)) {
+ if (repositories.isEmpty() || repositoryKeys.contains(rule.getRepositoryKey())) {
+ DebtRulesXMLImporter.RuleDebt ruleDebt = ruleDebtByRule(rule, ruleDebts);
+ if (ruleDebt == null) {
+ rule.setCharacteristicId(disableCharacteristicWhenRuleNotFound ? RuleDto.DISABLED_CHARACTERISTIC_ID : null);
+ rule.setRemediationFunction(null);
+ rule.setRemediationFactor(null);
+ rule.setRemediationOffset(null);
+ } else {
+ CharacteristicDto characteristicDto = characteristicByKey(ruleDebt.characteristicKey(), characteristicDtos, false);
+ // Characteristic cannot be null as it has been created just before
+
+ boolean isSameCharacteristic = characteristicDto.getId().equals(rule.getDefaultCharacteristicId());
+ boolean isSameFunction = isSameRemediationFunction(ruleDebt, rule);
+ rule.setCharacteristicId((!isSameCharacteristic ? characteristicDto.getId() : null));
+ rule.setRemediationFunction((!isSameFunction ? ruleDebt.function().name() : null));
+ rule.setRemediationFactor((!isSameFunction ? ruleDebt.factor() : null));
+ rule.setRemediationOffset((!isSameFunction ? ruleDebt.offset() : null));
+ }
+
+ ruleDebts.remove(ruleDebt);
+ rule.setUpdatedAt(updateDate);
+ ruleDao.update(rule, session);
+ // TODO index rules in E/S
+ }
+ }
+
+ for (DebtRulesXMLImporter.RuleDebt ruleDebt : ruleDebts) {
+ validationMessages.addWarningText(String.format("The rule '%s' does not exist.", ruleDebt.ruleKey()));
}
}
+ static boolean isSameRemediationFunction(DebtRulesXMLImporter.RuleDebt ruleDebt, RuleDto rule) {
+ return new EqualsBuilder()
+ .append(ruleDebt.function().name(), rule.getDefaultRemediationFunction())
+ .append(ruleDebt.factor(), rule.getDefaultRemediationFactor())
+ .append(ruleDebt.offset(), rule.getDefaultRemediationOffset())
+ .isEquals();
+ }
+
@VisibleForTesting
- void restoreCharacteristics(DebtModel targetModel, List<CharacteristicDto> sourceCharacteristics, Date updateDate, SqlSession session) {
+ List<CharacteristicDto> restoreCharacteristics(DebtModel targetModel, List<CharacteristicDto> sourceCharacteristics, Date updateDate, SqlSession session) {
+ List<CharacteristicDto> result = newArrayList();
+
// Restore not existing characteristics
for (DebtCharacteristic characteristic : targetModel.rootCharacteristics()) {
CharacteristicDto rootCharacteristicDto = restoreCharacteristic(characteristic, null, sourceCharacteristics, updateDate, session);
+ result.add(rootCharacteristicDto);
for (DebtCharacteristic subCharacteristic : targetModel.subCharacteristics(characteristic.key())) {
- restoreCharacteristic(subCharacteristic, rootCharacteristicDto.getId(), sourceCharacteristics, updateDate, session);
+ result.add(restoreCharacteristic(subCharacteristic, rootCharacteristicDto.getId(), sourceCharacteristics, updateDate, session));
}
}
// Disable no more existing characteristics
@@ -144,11 +209,12 @@ public class DebtModelRestore implements ServerComponent {
debtModelOperations.disableCharacteristic(sourceCharacteristic, updateDate, session);
}
}
+ return result;
}
private CharacteristicDto restoreCharacteristic(DebtCharacteristic targetCharacteristic, @Nullable Integer parentId, List<CharacteristicDto> sourceCharacteristics,
Date updateDate, SqlSession session) {
- CharacteristicDto sourceCharacteristic = dtoByKey(sourceCharacteristics, targetCharacteristic.key());
+ CharacteristicDto sourceCharacteristic = characteristicByKey(targetCharacteristic.key(), sourceCharacteristics, true);
if (sourceCharacteristic == null) {
CharacteristicDto newCharacteristic = toDto(targetCharacteristic, parentId).setCreatedAt(updateDate);
dao.insert(newCharacteristic, session);
@@ -166,24 +232,40 @@ public class DebtModelRestore implements ServerComponent {
}
}
- private DebtModel loadModelFromXml(String pluginKey) {
+ private DebtModel loadModelFromPlugin(String pluginKey) {
Reader xmlFileReader = null;
try {
xmlFileReader = debtModelPluginRepository.createReaderForXMLFile(pluginKey);
- return importer.importXML(xmlFileReader);
+ return characteristicsXMLImporter.importXML(xmlFileReader);
} finally {
IOUtils.closeQuietly(xmlFileReader);
}
}
- @CheckForNull
- private CharacteristicDto dtoByKey(List<CharacteristicDto> existingModel, final String key) {
- return Iterables.find(existingModel, new Predicate<CharacteristicDto>() {
+ private CharacteristicDto characteristicByKey(final String key, List<CharacteristicDto> existingModel, boolean canByNull) {
+ CharacteristicDto dto = Iterables.find(existingModel, new Predicate<CharacteristicDto>() {
@Override
public boolean apply(CharacteristicDto input) {
return key.equals(input.getKey());
}
}, null);
+ if (dto == null && !canByNull) {
+ throw new IllegalStateException(String.format("Characteristic with key '%s' has not been found ", key));
+ }
+ return dto;
+ }
+
+ @CheckForNull
+ private DebtRulesXMLImporter.RuleDebt ruleDebtByRule(final RuleDto rule, List<DebtRulesXMLImporter.RuleDebt> ruleDebts) {
+ if (ruleDebts.isEmpty()) {
+ return null;
+ }
+ return Iterables.find(ruleDebts, new Predicate<DebtRulesXMLImporter.RuleDebt>() {
+ @Override
+ public boolean apply(DebtRulesXMLImporter.RuleDebt input) {
+ return rule.getRepositoryKey().equals(input.ruleKey().repository()) && rule.getRuleKey().equals(input.ruleKey().rule());
+ }
+ }, null);
}
private static CharacteristicDto toDto(DebtCharacteristic characteristic, @Nullable Integer parentId) {
diff --git a/sonar-server/src/main/java/org/sonar/server/debt/DebtModelService.java b/sonar-server/src/main/java/org/sonar/server/debt/DebtModelService.java
index 483f4fa5c28..a0777d8f528 100644
--- a/sonar-server/src/main/java/org/sonar/server/debt/DebtModelService.java
+++ b/sonar-server/src/main/java/org/sonar/server/debt/DebtModelService.java
@@ -22,6 +22,7 @@ package org.sonar.server.debt;
import org.sonar.api.server.debt.DebtCharacteristic;
import org.sonar.api.server.debt.DebtModel;
+import org.sonar.api.utils.ValidationMessages;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
@@ -84,15 +85,29 @@ public class DebtModelService implements DebtModel {
/**
* Restore from provided model
*/
- public void restore(){
- debtModelRestore.restore();
+ public ValidationMessages restore(){
+ return debtModelRestore.restore();
}
/**
* Restore from plugins providing rules for a given language
*/
- public void restore(String languageKey) {
- debtModelRestore.restore(languageKey);
+ public ValidationMessages restoreFromLanguage(String languageKey) {
+ return debtModelRestore.restore(languageKey);
+ }
+
+ /**
+ * Restore from XML
+ */
+ public ValidationMessages restoreFromXml(String xml){
+ return debtModelRestore.restoreFromXml(xml);
+ }
+
+ /**
+ * Restore from XML and a given language
+ */
+ public ValidationMessages restoreFromXmlAndLanguage(String xml, String languageKey) {
+ return debtModelRestore.restoreFromXml(xml, languageKey);
}
}
diff --git a/sonar-server/src/main/java/org/sonar/server/debt/DebtModelSynchronizer.java b/sonar-server/src/main/java/org/sonar/server/debt/DebtModelSynchronizer.java
index e8ea229be18..f6e3f8b331c 100644
--- a/sonar-server/src/main/java/org/sonar/server/debt/DebtModelSynchronizer.java
+++ b/sonar-server/src/main/java/org/sonar/server/debt/DebtModelSynchronizer.java
@@ -36,6 +36,7 @@ import java.util.List;
import static com.google.common.collect.Lists.newArrayList;
+// TODO replace this by DebtModelRestore
public class DebtModelSynchronizer implements ServerExtension {
private final MyBatis mybatis;
diff --git a/sonar-server/src/main/java/org/sonar/server/debt/DebtRulesXMLImporter.java b/sonar-server/src/main/java/org/sonar/server/debt/DebtRulesXMLImporter.java
index fb08a965599..762b11deacb 100644
--- a/sonar-server/src/main/java/org/sonar/server/debt/DebtRulesXMLImporter.java
+++ b/sonar-server/src/main/java/org/sonar/server/debt/DebtRulesXMLImporter.java
@@ -29,12 +29,11 @@ import org.codehaus.stax2.XMLInputFactory2;
import org.codehaus.staxmate.SMInputFactory;
import org.codehaus.staxmate.in.SMHierarchicCursor;
import org.codehaus.staxmate.in.SMInputCursor;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.sonar.api.ServerExtension;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.server.rule.DebtRemediationFunction;
import org.sonar.api.utils.Duration;
+import org.sonar.api.utils.ValidationMessages;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
@@ -49,8 +48,6 @@ import static com.google.common.collect.Lists.newArrayList;
public class DebtRulesXMLImporter implements ServerExtension {
- private static final Logger LOG = LoggerFactory.getLogger(DebtRulesXMLImporter.class);
-
public static final String CHARACTERISTIC = "chc";
public static final String CHARACTERISTIC_KEY = "key";
public static final String PROPERTY = "prop";
@@ -66,11 +63,11 @@ public class DebtRulesXMLImporter implements ServerExtension {
public static final String PROPERTY_FACTOR = "remediationFactor";
public static final String PROPERTY_OFFSET = "offset";
- public List<RuleDebt> importXML(String xml) {
- return importXML(new StringReader(xml));
+ public List<RuleDebt> importXML(String xml, ValidationMessages validationMessages) {
+ return importXML(new StringReader(xml), validationMessages);
}
- public List<RuleDebt> importXML(Reader xml) {
+ public List<RuleDebt> importXML(Reader xml, ValidationMessages validationMessages) {
List<RuleDebt> ruleDebts = newArrayList();
try {
SMInputFactory inputFactory = initStax();
@@ -80,7 +77,7 @@ public class DebtRulesXMLImporter implements ServerExtension {
cursor.advance();
SMInputCursor rootCursor = cursor.childElementCursor(CHARACTERISTIC);
while (rootCursor.getNext() != null) {
- process(ruleDebts, null, null, rootCursor);
+ process(ruleDebts, null, null, validationMessages, rootCursor);
}
cursor.getStreamReader().closeCompletely();
@@ -99,7 +96,7 @@ public class DebtRulesXMLImporter implements ServerExtension {
return new SMInputFactory(xmlFactory);
}
- private void process(List<RuleDebt> ruleDebts, @Nullable String rootKey, @Nullable String parentKey, SMInputCursor chcCursor) throws XMLStreamException {
+ private void process(List<RuleDebt> ruleDebts, @Nullable String rootKey, @Nullable String parentKey, ValidationMessages validationMessages, SMInputCursor chcCursor) throws XMLStreamException {
String currentCharacteristicKey = null;
SMInputCursor cursor = chcCursor.childElementCursor();
while (cursor.getNext() != null) {
@@ -107,15 +104,15 @@ public class DebtRulesXMLImporter implements ServerExtension {
if (StringUtils.equals(node, CHARACTERISTIC_KEY)) {
currentCharacteristicKey = cursor.collectDescendantText().trim();
} else if (StringUtils.equals(node, CHARACTERISTIC)) {
- process(ruleDebts, parentKey, currentCharacteristicKey, cursor);
+ process(ruleDebts, parentKey, currentCharacteristicKey, validationMessages, cursor);
} else if (StringUtils.equals(node, REPOSITORY_KEY)) {
- RuleDebt ruleDebt = processRule(cursor);
+ RuleDebt ruleDebt = processRule(validationMessages, cursor);
if (ruleDebt != null) {
if (rootKey != null) {
ruleDebt.characteristicKey = parentKey;
ruleDebts.add(ruleDebt);
} else {
- LOG.warn("Rule '" + ruleDebt.ruleKey + "' is ignored because it's defined directly under a root characteristic.");
+ validationMessages.addWarningText("Rule '" + ruleDebt.ruleKey + "' is ignored because it's defined directly under a root characteristic.");
}
}
}
@@ -123,7 +120,7 @@ public class DebtRulesXMLImporter implements ServerExtension {
}
@CheckForNull
- private RuleDebt processRule(SMInputCursor cursor) throws XMLStreamException {
+ private RuleDebt processRule(ValidationMessages validationMessages, SMInputCursor cursor) throws XMLStreamException {
String ruleRepositoryKey = cursor.collectDescendantText().trim();
String ruleKey = null;
@@ -131,18 +128,18 @@ public class DebtRulesXMLImporter implements ServerExtension {
while (cursor.getNext() != null) {
String node = cursor.getLocalName();
if (StringUtils.equals(node, PROPERTY)) {
- properties.add(processProperty(cursor));
+ properties.add(processProperty(validationMessages, cursor));
} else if (StringUtils.equals(node, RULE_KEY)) {
ruleKey = cursor.collectDescendantText().trim();
}
}
if (StringUtils.isNotBlank(ruleRepositoryKey) && StringUtils.isNotBlank(ruleKey)) {
- return createRule(RuleKey.of(ruleRepositoryKey, ruleKey), properties);
+ return createRule(RuleKey.of(ruleRepositoryKey, ruleKey), properties, validationMessages);
}
return null;
}
- private Property processProperty(SMInputCursor cursor) throws XMLStreamException {
+ private Property processProperty(ValidationMessages validationMessages, SMInputCursor cursor) throws XMLStreamException {
SMInputCursor c = cursor.childElementCursor();
String key = null;
int value = 0;
@@ -158,7 +155,7 @@ public class DebtRulesXMLImporter implements ServerExtension {
Double valueDouble = NumberUtils.createDouble(s);
value = valueDouble.intValue();
} catch (NumberFormatException ex) {
- LOG.error(String.format("Cannot import value '%s' for field %s - Expected a numeric value instead", s, key));
+ validationMessages.addErrorText(String.format("Cannot import value '%s' for field %s - Expected a numeric value instead", s, key));
}
} else if (StringUtils.equals(node, PROPERTY_TEXT_VALUE)) {
textValue = c.collectDescendantText().trim();
@@ -169,7 +166,7 @@ public class DebtRulesXMLImporter implements ServerExtension {
}
@CheckForNull
- private RuleDebt createRule(RuleKey ruleKey, Properties properties) {
+ private RuleDebt createRule(RuleKey ruleKey, Properties properties, ValidationMessages validationMessages) {
Property function = properties.function();
if (function != null) {
@@ -178,22 +175,22 @@ public class DebtRulesXMLImporter implements ServerExtension {
Property offsetProperty = properties.offset();
String offset = offsetProperty != null ? offsetProperty.toDuration() : null;
- return createRuleDebt(ruleKey, function.getTextValue(), factor, offset);
+ return createRuleDebt(ruleKey, function.getTextValue(), factor, offset, validationMessages);
}
return null;
}
@CheckForNull
- private RuleDebt createRuleDebt(RuleKey ruleKey, String function, @Nullable String factor, @Nullable String offset) {
+ private RuleDebt createRuleDebt(RuleKey ruleKey, String function, @Nullable String factor, @Nullable String offset, ValidationMessages validationMessages) {
if ("linear_threshold".equals(function) && factor != null) {
- LOG.warn(String.format("Linear with threshold function is no longer used, remediation function of '%s' is replaced by linear.", ruleKey));
- return new RuleDebt().setRuleKey(ruleKey).setType(DebtRemediationFunction.Type.LINEAR).setFactor(factor);
+ validationMessages.addWarningText(String.format("Linear with threshold function is no longer used, remediation function of '%s' is replaced by linear.", ruleKey));
+ return new RuleDebt().setRuleKey(ruleKey).setFunction(DebtRemediationFunction.Type.LINEAR).setFactor(factor);
} else if ("constant_resource".equals(function)) {
- LOG.warn(String.format("Constant/file function is no longer used, technical debt definitions on '%s' are ignored.", ruleKey));
+ validationMessages.addWarningText(String.format("Constant/file function is no longer used, technical debt definitions on '%s' are ignored.", ruleKey));
} else if (DebtRemediationFunction.Type.CONSTANT_ISSUE.name().equalsIgnoreCase(function) && factor != null && offset == null) {
- return new RuleDebt().setRuleKey(ruleKey).setType(DebtRemediationFunction.Type.CONSTANT_ISSUE).setOffset(factor);
+ return new RuleDebt().setRuleKey(ruleKey).setFunction(DebtRemediationFunction.Type.CONSTANT_ISSUE).setOffset(factor);
} else {
- return new RuleDebt().setRuleKey(ruleKey).setType(DebtRemediationFunction.Type.valueOf(function.toUpperCase())).setFactor(factor).setOffset(offset);
+ return new RuleDebt().setRuleKey(ruleKey).setFunction(DebtRemediationFunction.Type.valueOf(function.toUpperCase())).setFactor(factor).setOffset(offset);
}
return null;
}
@@ -291,11 +288,11 @@ public class DebtRulesXMLImporter implements ServerExtension {
return this;
}
- public DebtRemediationFunction.Type type() {
+ public DebtRemediationFunction.Type function() {
return type;
}
- public RuleDebt setType(DebtRemediationFunction.Type type) {
+ public RuleDebt setFunction(DebtRemediationFunction.Type type) {
this.type = type;
return this;
}
diff --git a/sonar-server/src/main/java/org/sonar/server/rule/DeprecatedRulesDefinition.java b/sonar-server/src/main/java/org/sonar/server/rule/DeprecatedRulesDefinition.java
index 84c0d5b7c60..59b8b8f0a58 100644
--- a/sonar-server/src/main/java/org/sonar/server/rule/DeprecatedRulesDefinition.java
+++ b/sonar-server/src/main/java/org/sonar/server/rule/DeprecatedRulesDefinition.java
@@ -23,12 +23,15 @@ import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.rules.RuleParam;
import org.sonar.api.rules.RuleRepository;
import org.sonar.api.server.rule.RuleParamType;
import org.sonar.api.server.rule.RulesDefinition;
+import org.sonar.api.utils.ValidationMessages;
import org.sonar.check.Cardinality;
import org.sonar.core.i18n.RuleI18nManager;
import org.sonar.core.technicaldebt.TechnicalDebtModelRepository;
@@ -49,6 +52,8 @@ import static com.google.common.collect.Lists.newArrayList;
*/
public class DeprecatedRulesDefinition implements RulesDefinition {
+ private static final Logger LOG = LoggerFactory.getLogger(DeprecatedRulesDefinition.class);
+
private final RuleI18nManager i18n;
private final RuleRepository[] repositories;
@@ -105,7 +110,7 @@ public class DeprecatedRulesDefinition implements RulesDefinition {
DebtRulesXMLImporter.RuleDebt ruleDebt = findRequirement(ruleDebts, repoKey, ruleKey);
if (ruleDebt != null) {
newRule.setDebtCharacteristic(ruleDebt.characteristicKey());
- switch (ruleDebt.type()) {
+ switch (ruleDebt.function()) {
case LINEAR :
newRule.setDebtRemediationFunction(newRule.debtRemediationFunctions().linear(ruleDebt.factor()));
break;
@@ -116,7 +121,7 @@ public class DeprecatedRulesDefinition implements RulesDefinition {
newRule.setDebtRemediationFunction(newRule.debtRemediationFunctions().constantPerIssue(ruleDebt.offset()));
break;
default :
- throw new IllegalArgumentException(String.format("The type '%s' is unknown", ruleDebt.type()));
+ throw new IllegalArgumentException(String.format("The type '%s' is unknown", ruleDebt.function()));
}
}
}
@@ -160,7 +165,10 @@ public class DeprecatedRulesDefinition implements RulesDefinition {
Reader xmlFileReader = null;
try {
xmlFileReader = languageModelFinder.createReaderForXMLFile(pluginKey);
- return importer.importXML(xmlFileReader);
+ ValidationMessages validationMessages = ValidationMessages.create();
+ List<DebtRulesXMLImporter.RuleDebt> rules = importer.importXML(xmlFileReader, validationMessages);
+ validationMessages.log(LOG);
+ return rules;
} finally {
IOUtils.closeQuietly(xmlFileReader);
}
diff --git a/sonar-server/src/test/java/org/sonar/server/debt/DebtModelRestoreTest.java b/sonar-server/src/test/java/org/sonar/server/debt/DebtModelRestoreTest.java
index 4c96c20172e..05b8ac50a92 100644
--- a/sonar-server/src/test/java/org/sonar/server/debt/DebtModelRestoreTest.java
+++ b/sonar-server/src/test/java/org/sonar/server/debt/DebtModelRestoreTest.java
@@ -29,9 +29,12 @@ import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
+import org.sonar.api.rule.RuleKey;
import org.sonar.api.server.debt.internal.DefaultDebtCharacteristic;
+import org.sonar.api.server.rule.DebtRemediationFunction;
import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.System2;
+import org.sonar.api.utils.ValidationMessages;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.core.persistence.MyBatis;
import org.sonar.core.rule.RuleDao;
@@ -45,6 +48,7 @@ import org.sonar.server.user.MockUserSession;
import java.io.Reader;
import java.util.Collections;
import java.util.Date;
+import java.util.List;
import static com.google.common.collect.Lists.newArrayList;
import static org.fest.assertions.Assertions.assertThat;
@@ -77,6 +81,9 @@ public class DebtModelRestoreTest {
DebtCharacteristicsXMLImporter characteristicsXMLImporter;
@Mock
+ DebtRulesXMLImporter rulesXMLImporter;
+
+ @Mock
RuleRepositories ruleRepositories;
@Mock
@@ -86,7 +93,8 @@ public class DebtModelRestoreTest {
int currentId;
- DebtModel defaultModel = new DebtModel();
+ DebtModel characteristics = new DebtModel();
+ List<DebtRulesXMLImporter.RuleDebt> rules = newArrayList();
DebtModelRestore debtModelRestore;
@@ -111,9 +119,12 @@ public class DebtModelRestoreTest {
Reader defaultModelReader = mock(Reader.class);
when(debtModelPluginRepository.createReaderForXMLFile("technical-debt")).thenReturn(defaultModelReader);
- when(characteristicsXMLImporter.importXML(eq(defaultModelReader))).thenReturn(defaultModel);
+ when(characteristicsXMLImporter.importXML(eq(defaultModelReader))).thenReturn(characteristics);
+ when(characteristicsXMLImporter.importXML(anyString())).thenReturn(characteristics);
+ when(rulesXMLImporter.importXML(anyString(), any(ValidationMessages.class))).thenReturn(rules);
- debtModelRestore = new DebtModelRestore(myBatis, dao, ruleDao, debtModelOperations, debtModelPluginRepository, ruleRepositories, characteristicsXMLImporter, system2);
+ debtModelRestore = new DebtModelRestore(myBatis, dao, ruleDao, debtModelOperations, debtModelPluginRepository, ruleRepositories, characteristicsXMLImporter, rulesXMLImporter,
+ system2);
}
@Test
@@ -121,7 +132,7 @@ public class DebtModelRestoreTest {
debtModelRestore.restoreCharacteristics(
new DebtModel()
.addRootCharacteristic(new DefaultDebtCharacteristic().setKey("PORTABILITY").setName("Portability").setOrder(1))
- .addSubCharacteristic(new DefaultDebtCharacteristic().setKey("COMPILER_RELATED_PORTABILITY").setName("Compiler"), "PORTABILITY"),
+ .addSubCharacteristic(new DefaultDebtCharacteristic().setKey("COMPILER").setName("Compiler"), "PORTABILITY"),
Collections.<CharacteristicDto>emptyList(),
now,
session
@@ -141,7 +152,7 @@ public class DebtModelRestoreTest {
CharacteristicDto dto2 = characteristicArgument.getAllValues().get(1);
assertThat(dto2.getId()).isEqualTo(11);
- assertThat(dto2.getKey()).isEqualTo("COMPILER_RELATED_PORTABILITY");
+ assertThat(dto2.getKey()).isEqualTo("COMPILER");
assertThat(dto2.getName()).isEqualTo("Compiler");
assertThat(dto2.getParentId()).isEqualTo(10);
assertThat(dto2.getOrder()).isNull();
@@ -156,10 +167,10 @@ public class DebtModelRestoreTest {
debtModelRestore.restoreCharacteristics(
new DebtModel()
.addRootCharacteristic(new DefaultDebtCharacteristic().setKey("PORTABILITY").setName("Portability").setOrder(1))
- .addSubCharacteristic(new DefaultDebtCharacteristic().setKey("COMPILER_RELATED_PORTABILITY").setName("Compiler"), "PORTABILITY"),
+ .addSubCharacteristic(new DefaultDebtCharacteristic().setKey("COMPILER").setName("Compiler"), "PORTABILITY"),
newArrayList(
new CharacteristicDto().setId(1).setKey("PORTABILITY").setName("Portability updated").setOrder(2).setCreatedAt(oldDate).setUpdatedAt(oldDate),
- new CharacteristicDto().setId(2).setKey("COMPILER_RELATED_PORTABILITY").setName("Compiler updated").setParentId(1).setCreatedAt(oldDate).setUpdatedAt(oldDate)
+ new CharacteristicDto().setId(2).setKey("COMPILER").setName("Compiler updated").setParentId(1).setCreatedAt(oldDate).setUpdatedAt(oldDate)
),
now,
session
@@ -179,7 +190,7 @@ public class DebtModelRestoreTest {
CharacteristicDto dto2 = characteristicArgument.getAllValues().get(1);
assertThat(dto2.getId()).isEqualTo(2);
- assertThat(dto2.getKey()).isEqualTo("COMPILER_RELATED_PORTABILITY");
+ assertThat(dto2.getKey()).isEqualTo("COMPILER");
assertThat(dto2.getName()).isEqualTo("Compiler");
assertThat(dto2.getParentId()).isEqualTo(1);
assertThat(dto2.getOrder()).isNull();
@@ -190,7 +201,7 @@ public class DebtModelRestoreTest {
@Test
public void disable_no_more_existing_characteristics_when_restoring_characteristics() throws Exception {
CharacteristicDto dto1 = new CharacteristicDto().setId(1).setKey("PORTABILITY").setName("Portability").setOrder(1);
- CharacteristicDto dto2 = new CharacteristicDto().setId(2).setKey("COMPILER_RELATED_PORTABILITY").setName("Compiler").setParentId(1);
+ CharacteristicDto dto2 = new CharacteristicDto().setId(2).setKey("COMPILER").setName("Compiler").setParentId(1);
debtModelRestore.restoreCharacteristics(new DebtModel(), newArrayList(dto1, dto2), now, session);
@@ -202,17 +213,17 @@ public class DebtModelRestoreTest {
public void restore_from_provided_model() throws Exception {
Date oldDate = DateUtils.parseDate("2014-01-01");
- defaultModel
+ characteristics
.addRootCharacteristic(new DefaultDebtCharacteristic().setKey("PORTABILITY").setName("Portability").setOrder(1))
- .addSubCharacteristic(new DefaultDebtCharacteristic().setKey("COMPILER_RELATED_PORTABILITY").setName("Compiler"), "PORTABILITY");
+ .addSubCharacteristic(new DefaultDebtCharacteristic().setKey("COMPILER").setName("Compiler"), "PORTABILITY");
when(dao.selectEnabledCharacteristics()).thenReturn(newArrayList(
new CharacteristicDto().setId(1).setKey("PORTABILITY").setName("Portability updated").setOrder(2).setCreatedAt(oldDate),
- new CharacteristicDto().setId(2).setKey("COMPILER_RELATED_PORTABILITY").setName("Compiler updated").setParentId(1).setCreatedAt(oldDate)
+ new CharacteristicDto().setId(2).setKey("COMPILER").setName("Compiler updated").setParentId(1).setCreatedAt(oldDate)
));
- when(ruleDao.selectOverridingDebt(Collections.<String>emptyList(), session)).thenReturn(newArrayList(
- new RuleDto().setCharacteristicId(10).setRemediationFunction("LINEAR_OFFSET").setRemediationFactor("2h").setRemediationOffset("15min")
+ when(ruleDao.selectEnablesAndNonManual(session)).thenReturn(newArrayList(
+ new RuleDto().setRepositoryKey("squid").setCharacteristicId(2).setRemediationFunction("LINEAR_OFFSET").setRemediationFactor("2h").setRemediationOffset("15min")
.setCreatedAt(oldDate).setUpdatedAt(oldDate)
));
@@ -222,7 +233,7 @@ public class DebtModelRestoreTest {
verify(dao, times(2)).update(any(CharacteristicDto.class), eq(session));
verifyNoMoreInteractions(dao);
- verify(ruleDao).selectOverridingDebt(Collections.<String>emptyList(), session);
+ verify(ruleDao).selectEnablesAndNonManual(session);
ArgumentCaptor<RuleDto> ruleArgument = ArgumentCaptor.forClass(RuleDto.class);
verify(ruleDao).update(ruleArgument.capture(), eq(session));
verifyNoMoreInteractions(ruleDao);
@@ -241,18 +252,22 @@ public class DebtModelRestoreTest {
public void restore_from_language() throws Exception {
Date oldDate = DateUtils.parseDate("2014-01-01");
- defaultModel
+ characteristics
.addRootCharacteristic(new DefaultDebtCharacteristic().setKey("PORTABILITY").setName("Portability").setOrder(1))
- .addSubCharacteristic(new DefaultDebtCharacteristic().setKey("COMPILER_RELATED_PORTABILITY").setName("Compiler"), "PORTABILITY");
+ .addSubCharacteristic(new DefaultDebtCharacteristic().setKey("COMPILER").setName("Compiler"), "PORTABILITY");
when(dao.selectEnabledCharacteristics()).thenReturn(newArrayList(
new CharacteristicDto().setId(1).setKey("PORTABILITY").setName("Portability updated").setOrder(2).setCreatedAt(oldDate),
- new CharacteristicDto().setId(2).setKey("COMPILER_RELATED_PORTABILITY").setName("Compiler updated").setParentId(1).setCreatedAt(oldDate)
+ new CharacteristicDto().setId(2).setKey("COMPILER").setName("Compiler updated").setParentId(1).setCreatedAt(oldDate)
));
- when(ruleDao.selectOverridingDebt(newArrayList("squid"), session)).thenReturn(newArrayList(
- new RuleDto().setRepositoryKey("squid")
- .setCharacteristicId(10).setRemediationFunction("LINEAR_OFFSET").setRemediationFactor("2h").setRemediationOffset("15min")
+ when(ruleDao.selectEnablesAndNonManual(session)).thenReturn(newArrayList(
+ new RuleDto().setId(1).setRepositoryKey("squid")
+ .setCharacteristicId(2).setRemediationFunction("LINEAR_OFFSET").setRemediationFactor("2h").setRemediationOffset("15min")
+ .setCreatedAt(oldDate).setUpdatedAt(oldDate),
+ // Should be ignored
+ new RuleDto().setId(2).setRepositoryKey("checkstyle")
+ .setCharacteristicId(3).setRemediationFunction("LINEAR").setRemediationFactor("2h")
.setCreatedAt(oldDate).setUpdatedAt(oldDate)
));
@@ -266,11 +281,237 @@ public class DebtModelRestoreTest {
verify(dao, times(2)).update(any(CharacteristicDto.class), eq(session));
verifyNoMoreInteractions(dao);
- verify(ruleDao).selectOverridingDebt(newArrayList("squid"), session);
+ verify(ruleDao).selectEnablesAndNonManual(session);
+ ArgumentCaptor<RuleDto> ruleArgument = ArgumentCaptor.forClass(RuleDto.class);
+ verify(ruleDao).update(ruleArgument.capture(), eq(session));
+ verifyNoMoreInteractions(ruleDao);
+
+ RuleDto rule = ruleArgument.getValue();
+ assertThat(rule.getId()).isEqualTo(1);
+
+ verify(session).commit();
+ }
+
+ @Test
+ public void restore_from_xml_with_different_characteristic_and_same_function() throws Exception {
+ Date oldDate = DateUtils.parseDate("2014-01-01");
+
+ characteristics
+ .addRootCharacteristic(new DefaultDebtCharacteristic().setKey("PORTABILITY").setName("Portability").setOrder(1))
+ .addSubCharacteristic(new DefaultDebtCharacteristic().setKey("COMPILER").setName("Compiler"), "PORTABILITY");
+
+ when(dao.selectEnabledCharacteristics()).thenReturn(newArrayList(
+ new CharacteristicDto().setId(1).setKey("PORTABILITY").setName("Portability").setOrder(1).setCreatedAt(oldDate),
+ new CharacteristicDto().setId(2).setKey("COMPILER").setName("Compiler").setParentId(1).setCreatedAt(oldDate)));
+
+ rules.add(new DebtRulesXMLImporter.RuleDebt()
+ .setRuleKey(RuleKey.of("squid", "UselessImportCheck")).setCharacteristicKey("COMPILER").setFunction(DebtRemediationFunction.Type.LINEAR).setFactor("2h"));
+
+ when(ruleDao.selectEnablesAndNonManual(session)).thenReturn(newArrayList(
+ new RuleDto().setId(1).setRepositoryKey("squid").setRuleKey("UselessImportCheck")
+ .setDefaultCharacteristicId(10).setDefaultRemediationFunction("LINEAR").setDefaultRemediationFactor("2h")
+ .setCreatedAt(oldDate).setUpdatedAt(oldDate)
+ ));
+
+ debtModelRestore.restoreFromXml("<xml/>");
+
+ verify(ruleDao).selectEnablesAndNonManual(session);
+ ArgumentCaptor<RuleDto> ruleArgument = ArgumentCaptor.forClass(RuleDto.class);
+ verify(ruleDao).update(ruleArgument.capture(), eq(session));
+ verifyNoMoreInteractions(ruleDao);
+
+ RuleDto rule = ruleArgument.getValue();
+ assertThat(rule.getId()).isEqualTo(1);
+ assertThat(rule.getCharacteristicId()).isEqualTo(2);
+ assertThat(rule.getRemediationFunction()).isNull();
+ assertThat(rule.getRemediationFactor()).isNull();
+ assertThat(rule.getRemediationOffset()).isNull();
+ assertThat(rule.getUpdatedAt()).isEqualTo(now);
+
+ verify(session).commit();
+ }
+
+ @Test
+ public void restore_from_xml_with_same_characteristic_and_different_function() throws Exception {
+ Date oldDate = DateUtils.parseDate("2014-01-01");
+
+ characteristics
+ .addRootCharacteristic(new DefaultDebtCharacteristic().setKey("PORTABILITY").setName("Portability").setOrder(1))
+ .addSubCharacteristic(new DefaultDebtCharacteristic().setKey("COMPILER").setName("Compiler"), "PORTABILITY");
+
+ when(dao.selectEnabledCharacteristics()).thenReturn(newArrayList(
+ new CharacteristicDto().setId(1).setKey("PORTABILITY").setName("Portability").setOrder(1).setCreatedAt(oldDate),
+ new CharacteristicDto().setId(2).setKey("COMPILER").setName("Compiler").setParentId(1).setCreatedAt(oldDate)));
+
+ rules.add(new DebtRulesXMLImporter.RuleDebt()
+ .setRuleKey(RuleKey.of("squid", "UselessImportCheck")).setCharacteristicKey("COMPILER").setFunction(DebtRemediationFunction.Type.LINEAR_OFFSET).setFactor("12h").setOffset("11min"));
+
+ when(ruleDao.selectEnablesAndNonManual(session)).thenReturn(newArrayList(
+ new RuleDto().setId(1).setRepositoryKey("squid").setRuleKey("UselessImportCheck")
+ .setDefaultCharacteristicId(2).setDefaultRemediationFunction("LINEAR").setDefaultRemediationFactor("2h")
+ .setCreatedAt(oldDate).setUpdatedAt(oldDate)
+ ));
+
+ debtModelRestore.restoreFromXml("<xml/>");
+
+ verify(ruleDao).selectEnablesAndNonManual(session);
+ ArgumentCaptor<RuleDto> ruleArgument = ArgumentCaptor.forClass(RuleDto.class);
+ verify(ruleDao).update(ruleArgument.capture(), eq(session));
+ verifyNoMoreInteractions(ruleDao);
+
+ RuleDto rule = ruleArgument.getValue();
+ assertThat(rule.getId()).isEqualTo(1);
+ assertThat(rule.getCharacteristicId()).isNull();
+ assertThat(rule.getRemediationFunction()).isEqualTo("LINEAR_OFFSET");
+ assertThat(rule.getRemediationFactor()).isEqualTo("12h");
+ assertThat(rule.getRemediationOffset()).isEqualTo("11min");
+ assertThat(rule.getUpdatedAt()).isEqualTo(now);
+
+ verify(session).commit();
+ }
+
+ @Test
+ public void restore_from_xml_with_same_characteristic_and_same_function() throws Exception {
+ Date oldDate = DateUtils.parseDate("2014-01-01");
+
+ characteristics
+ .addRootCharacteristic(new DefaultDebtCharacteristic().setKey("PORTABILITY").setName("Portability").setOrder(1))
+ .addSubCharacteristic(new DefaultDebtCharacteristic().setKey("COMPILER").setName("Compiler"), "PORTABILITY");
+
+ when(dao.selectEnabledCharacteristics()).thenReturn(newArrayList(
+ new CharacteristicDto().setId(1).setKey("PORTABILITY").setName("Portability").setOrder(1).setCreatedAt(oldDate),
+ new CharacteristicDto().setId(2).setKey("COMPILER").setName("Compiler").setParentId(1).setCreatedAt(oldDate)));
+
+ rules.add(new DebtRulesXMLImporter.RuleDebt()
+ .setRuleKey(RuleKey.of("squid", "UselessImportCheck")).setCharacteristicKey("COMPILER").setFunction(DebtRemediationFunction.Type.LINEAR_OFFSET).setFactor("2h").setOffset("15min"));
+
+ when(ruleDao.selectEnablesAndNonManual(session)).thenReturn(newArrayList(
+ new RuleDto().setId(1).setRepositoryKey("squid").setRuleKey("UselessImportCheck")
+ .setDefaultCharacteristicId(2).setDefaultRemediationFunction("LINEAR_OFFSET").setDefaultRemediationFactor("2h").setDefaultRemediationOffset("15min")
+ .setCreatedAt(oldDate).setUpdatedAt(oldDate)
+ ));
+
+ debtModelRestore.restoreFromXml("<xml/>");
+
+ verify(ruleDao).selectEnablesAndNonManual(session);
ArgumentCaptor<RuleDto> ruleArgument = ArgumentCaptor.forClass(RuleDto.class);
verify(ruleDao).update(ruleArgument.capture(), eq(session));
verifyNoMoreInteractions(ruleDao);
+ RuleDto rule = ruleArgument.getValue();
+ assertThat(rule.getId()).isEqualTo(1);
+ assertThat(rule.getCharacteristicId()).isNull();
+ assertThat(rule.getRemediationFunction()).isNull();
+ assertThat(rule.getRemediationFactor()).isNull();
+ assertThat(rule.getRemediationOffset()).isNull();
+ assertThat(rule.getUpdatedAt()).isEqualTo(now);
+
+ verify(session).commit();
+ }
+
+ @Test
+ public void restore_from_xml_disable_rule_debt_when_not_in_xml() throws Exception {
+ Date oldDate = DateUtils.parseDate("2014-01-01");
+
+ characteristics
+ .addRootCharacteristic(new DefaultDebtCharacteristic().setKey("PORTABILITY").setName("Portability").setOrder(1))
+ .addSubCharacteristic(new DefaultDebtCharacteristic().setKey("COMPILER").setName("Compiler"), "PORTABILITY");
+
+ when(dao.selectEnabledCharacteristics()).thenReturn(newArrayList(
+ new CharacteristicDto().setId(1).setKey("PORTABILITY").setName("Portability").setOrder(1).setCreatedAt(oldDate),
+ new CharacteristicDto().setId(2).setKey("COMPILER").setName("Compiler").setParentId(1).setCreatedAt(oldDate)));
+
+ when(ruleDao.selectEnablesAndNonManual(session)).thenReturn(newArrayList(
+ new RuleDto().setId(1).setRepositoryKey("squid").setRuleKey("UselessImportCheck")
+ .setDefaultCharacteristicId(2).setDefaultRemediationFunction("LINEAR_OFFSET").setDefaultRemediationFactor("2h").setDefaultRemediationOffset("15min")
+ .setCreatedAt(oldDate).setUpdatedAt(oldDate)
+ ));
+
+ debtModelRestore.restoreFromXml("<xml/>");
+
+ verify(ruleDao).selectEnablesAndNonManual(session);
+ ArgumentCaptor<RuleDto> ruleArgument = ArgumentCaptor.forClass(RuleDto.class);
+ verify(ruleDao).update(ruleArgument.capture(), eq(session));
+ verifyNoMoreInteractions(ruleDao);
+
+ RuleDto rule = ruleArgument.getValue();
+ assertThat(rule.getId()).isEqualTo(1);
+ assertThat(rule.getCharacteristicId()).isEqualTo(-1);
+ assertThat(rule.getRemediationFunction()).isNull();
+ assertThat(rule.getRemediationFactor()).isNull();
+ assertThat(rule.getRemediationOffset()).isNull();
+ assertThat(rule.getUpdatedAt()).isEqualTo(now);
+
verify(session).commit();
}
+
+ @Test
+ public void restore_from_xml_and_language() throws Exception {
+ Date oldDate = DateUtils.parseDate("2014-01-01");
+
+ characteristics
+ .addRootCharacteristic(new DefaultDebtCharacteristic().setKey("PORTABILITY").setName("Portability").setOrder(1))
+ .addSubCharacteristic(new DefaultDebtCharacteristic().setKey("COMPILER").setName("Compiler"), "PORTABILITY");
+
+ when(dao.selectEnabledCharacteristics()).thenReturn(newArrayList(
+ new CharacteristicDto().setId(1).setKey("PORTABILITY").setName("Portability").setOrder(1).setCreatedAt(oldDate),
+ new CharacteristicDto().setId(2).setKey("COMPILER").setName("Compiler").setParentId(1).setCreatedAt(oldDate)));
+
+ rules.add(new DebtRulesXMLImporter.RuleDebt()
+ .setRuleKey(RuleKey.of("squid", "UselessImportCheck")).setCharacteristicKey("COMPILER").setFunction(DebtRemediationFunction.Type.LINEAR).setFactor("2h"));
+
+ when(ruleDao.selectEnablesAndNonManual(session)).thenReturn(newArrayList(
+ new RuleDto().setId(1).setRepositoryKey("squid").setRuleKey("UselessImportCheck")
+ .setDefaultCharacteristicId(10).setDefaultRemediationFunction("LINEAR").setDefaultRemediationFactor("2h")
+ .setCreatedAt(oldDate).setUpdatedAt(oldDate),
+ // Should be ignored
+ new RuleDto().setId(2).setRepositoryKey("checkstyle")
+ .setCharacteristicId(3).setRemediationFunction("LINEAR").setRemediationFactor("2h")
+ .setCreatedAt(oldDate).setUpdatedAt(oldDate)
+ ));
+
+ RuleRepositories.Repository squid = mock(RuleRepositories.Repository.class);
+ when(squid.getKey()).thenReturn("squid");
+ when(ruleRepositories.repositoriesForLang("java")).thenReturn(newArrayList(squid));
+
+ debtModelRestore.restoreFromXml("<xml/>", "java");
+
+ verify(ruleDao).selectEnablesAndNonManual(session);
+ ArgumentCaptor<RuleDto> ruleArgument = ArgumentCaptor.forClass(RuleDto.class);
+ verify(ruleDao).update(ruleArgument.capture(), eq(session));
+ verifyNoMoreInteractions(ruleDao);
+
+ RuleDto rule = ruleArgument.getValue();
+ assertThat(rule.getId()).isEqualTo(1);
+
+ verify(session).commit();
+ }
+
+ @Test
+ public void add_warning_message_when_rule_from_xml_is_not_found() throws Exception {
+ Date oldDate = DateUtils.parseDate("2014-01-01");
+
+ characteristics
+ .addRootCharacteristic(new DefaultDebtCharacteristic().setKey("PORTABILITY").setName("Portability").setOrder(1))
+ .addSubCharacteristic(new DefaultDebtCharacteristic().setKey("COMPILER").setName("Compiler"), "PORTABILITY");
+
+ when(dao.selectEnabledCharacteristics()).thenReturn(newArrayList(
+ new CharacteristicDto().setId(1).setKey("PORTABILITY").setName("Portability").setOrder(1).setCreatedAt(oldDate),
+ new CharacteristicDto().setId(2).setKey("COMPILER").setName("Compiler").setParentId(1).setCreatedAt(oldDate)));
+
+ rules.add(new DebtRulesXMLImporter.RuleDebt()
+ .setRuleKey(RuleKey.of("squid", "UselessImportCheck")).setCharacteristicKey("COMPILER").setFunction(DebtRemediationFunction.Type.LINEAR).setFactor("2h"));
+
+ when(ruleDao.selectEnablesAndNonManual(session)).thenReturn(Collections.<RuleDto>emptyList());
+
+ ValidationMessages validationMessages = debtModelRestore.restoreFromXml("<xml/>");
+
+ assertThat(validationMessages.getWarnings()).hasSize(1);
+
+ verify(ruleDao).selectEnablesAndNonManual(session);
+ verifyNoMoreInteractions(ruleDao);
+
+ verify(session).commit();
+ }
+
}
diff --git a/sonar-server/src/test/java/org/sonar/server/debt/DebtModelServiceTest.java b/sonar-server/src/test/java/org/sonar/server/debt/DebtModelServiceTest.java
index 9c044e6508a..59051abf5f6 100644
--- a/sonar-server/src/test/java/org/sonar/server/debt/DebtModelServiceTest.java
+++ b/sonar-server/src/test/java/org/sonar/server/debt/DebtModelServiceTest.java
@@ -102,8 +102,20 @@ public class DebtModelServiceTest {
@Test
public void restore_from_language() {
- service.restore("xoo");
+ service.restoreFromLanguage("xoo");
verify(debtModelRestore).restore("xoo");
}
+ @Test
+ public void restore_xml() {
+ service.restoreFromXml("<xml/>");
+ verify(debtModelRestore).restoreFromXml("<xml/>");
+ }
+
+ @Test
+ public void restore_from_xml_and_language() {
+ service.restoreFromXmlAndLanguage("<xml/>", "xoo");
+ verify(debtModelRestore).restoreFromXml("<xml/>", "xoo");
+ }
+
}
diff --git a/sonar-server/src/test/java/org/sonar/server/debt/DebtRulesXMLImporterTest.java b/sonar-server/src/test/java/org/sonar/server/debt/DebtRulesXMLImporterTest.java
index d2ddfde267b..e1e8f82b2bc 100644
--- a/sonar-server/src/test/java/org/sonar/server/debt/DebtRulesXMLImporterTest.java
+++ b/sonar-server/src/test/java/org/sonar/server/debt/DebtRulesXMLImporterTest.java
@@ -25,6 +25,7 @@ import com.google.common.io.Resources;
import org.junit.Test;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.server.rule.DebtRemediationFunction;
+import org.sonar.api.utils.ValidationMessages;
import java.io.IOException;
import java.util.List;
@@ -34,27 +35,31 @@ import static org.fest.assertions.Fail.fail;
public class DebtRulesXMLImporterTest {
+ ValidationMessages validationMessages = ValidationMessages.create();
DebtRulesXMLImporter importer = new DebtRulesXMLImporter();
@Test
public void import_rules() {
String xml = getFileContent("import_rules.xml");
- List<DebtRulesXMLImporter.RuleDebt> results = importer.importXML(xml);
+ List<DebtRulesXMLImporter.RuleDebt> results = importer.importXML(xml, validationMessages);
+
assertThat(results).hasSize(2);
+ assertThat(validationMessages.getErrors()).isEmpty();
+ assertThat(validationMessages.getWarnings()).isEmpty();
}
@Test
public void import_linear() {
String xml = getFileContent("import_linear.xml");
- List<DebtRulesXMLImporter.RuleDebt> results = importer.importXML(xml);
+ List<DebtRulesXMLImporter.RuleDebt> results = importer.importXML(xml, validationMessages);
assertThat(results).hasSize(1);
DebtRulesXMLImporter.RuleDebt ruleDebt = results.get(0);
assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
assertThat(ruleDebt.ruleKey()).isEqualTo(RuleKey.of("checkstyle", "Regexp"));
- assertThat(ruleDebt.type()).isEqualTo(DebtRemediationFunction.Type.LINEAR);
+ assertThat(ruleDebt.function()).isEqualTo(DebtRemediationFunction.Type.LINEAR);
assertThat(ruleDebt.factor()).isEqualTo("3h");
assertThat(ruleDebt.offset()).isNull();
}
@@ -63,13 +68,13 @@ public class DebtRulesXMLImporterTest {
public void import_linear_having_offset_to_zero() {
String xml = getFileContent("import_linear_having_offset_to_zero.xml");
- List<DebtRulesXMLImporter.RuleDebt> results = importer.importXML(xml);
+ List<DebtRulesXMLImporter.RuleDebt> results = importer.importXML(xml, validationMessages);
assertThat(results).hasSize(1);
DebtRulesXMLImporter.RuleDebt ruleDebt = results.get(0);
assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
assertThat(ruleDebt.ruleKey()).isEqualTo(RuleKey.of("checkstyle", "Regexp"));
- assertThat(ruleDebt.type()).isEqualTo(DebtRemediationFunction.Type.LINEAR);
+ assertThat(ruleDebt.function()).isEqualTo(DebtRemediationFunction.Type.LINEAR);
assertThat(ruleDebt.factor()).isEqualTo("3h");
assertThat(ruleDebt.offset()).isNull();
}
@@ -78,12 +83,12 @@ public class DebtRulesXMLImporterTest {
public void import_linear_with_offset() {
String xml = getFileContent("import_linear_with_offset.xml");
- List<DebtRulesXMLImporter.RuleDebt> results = importer.importXML(xml);
+ List<DebtRulesXMLImporter.RuleDebt> results = importer.importXML(xml, validationMessages);
assertThat(results).hasSize(1);
DebtRulesXMLImporter.RuleDebt ruleDebt = results.get(0);
assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
- assertThat(ruleDebt.type()).isEqualTo(DebtRemediationFunction.Type.LINEAR_OFFSET);
+ assertThat(ruleDebt.function()).isEqualTo(DebtRemediationFunction.Type.LINEAR_OFFSET);
assertThat(ruleDebt.factor()).isEqualTo("3h");
assertThat(ruleDebt.offset()).isEqualTo("1min");
}
@@ -92,12 +97,12 @@ public class DebtRulesXMLImporterTest {
public void import_constant_issue() {
String xml = getFileContent("import_constant_issue.xml");
- List<DebtRulesXMLImporter.RuleDebt> results = importer.importXML(xml);
+ List<DebtRulesXMLImporter.RuleDebt> results = importer.importXML(xml, validationMessages);
assertThat(results).hasSize(1);
DebtRulesXMLImporter.RuleDebt ruleDebt = results.get(0);
assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
- assertThat(ruleDebt.type()).isEqualTo(DebtRemediationFunction.Type.CONSTANT_ISSUE);
+ assertThat(ruleDebt.function()).isEqualTo(DebtRemediationFunction.Type.CONSTANT_ISSUE);
assertThat(ruleDebt.factor()).isNull();
assertThat(ruleDebt.offset()).isEqualTo("3d");
}
@@ -106,12 +111,12 @@ public class DebtRulesXMLImporterTest {
public void use_default_unit_when_no_unit() {
String xml = getFileContent("use_default_unit_when_no_unit.xml");
- List<DebtRulesXMLImporter.RuleDebt> results = importer.importXML(xml);
+ List<DebtRulesXMLImporter.RuleDebt> results = importer.importXML(xml, validationMessages);
assertThat(results).hasSize(1);
DebtRulesXMLImporter.RuleDebt ruleDebt = results.get(0);
assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
- assertThat(ruleDebt.type()).isEqualTo(DebtRemediationFunction.Type.LINEAR_OFFSET);
+ assertThat(ruleDebt.function()).isEqualTo(DebtRemediationFunction.Type.LINEAR_OFFSET);
assertThat(ruleDebt.factor()).isEqualTo("3d");
assertThat(ruleDebt.offset()).isEqualTo("1d");
}
@@ -120,12 +125,12 @@ public class DebtRulesXMLImporterTest {
public void replace_mn_by_min() {
String xml = getFileContent("replace_mn_by_min.xml");
- List<DebtRulesXMLImporter.RuleDebt> results = importer.importXML(xml);
+ List<DebtRulesXMLImporter.RuleDebt> results = importer.importXML(xml, validationMessages);
assertThat(results).hasSize(1);
DebtRulesXMLImporter.RuleDebt ruleDebt = results.get(0);
assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
- assertThat(ruleDebt.type()).isEqualTo(DebtRemediationFunction.Type.LINEAR);
+ assertThat(ruleDebt.function()).isEqualTo(DebtRemediationFunction.Type.LINEAR);
assertThat(ruleDebt.factor()).isEqualTo("3min");
assertThat(ruleDebt.offset()).isNull();
}
@@ -134,26 +139,28 @@ public class DebtRulesXMLImporterTest {
public void convert_deprecated_linear_with_threshold_function_by_linear_function() {
String xml = getFileContent("convert_deprecated_linear_with_threshold_function_by_linear_function.xml");
- List<DebtRulesXMLImporter.RuleDebt> results = importer.importXML(xml);
+ List<DebtRulesXMLImporter.RuleDebt> results = importer.importXML(xml, validationMessages);
assertThat(results).hasSize(1);
DebtRulesXMLImporter.RuleDebt ruleDebt = results.get(0);
assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
- assertThat(ruleDebt.type()).isEqualTo(DebtRemediationFunction.Type.LINEAR);
+ assertThat(ruleDebt.function()).isEqualTo(DebtRemediationFunction.Type.LINEAR);
assertThat(ruleDebt.factor()).isEqualTo("3h");
assertThat(ruleDebt.offset()).isNull();
+
+ assertThat(validationMessages.getWarnings()).isNotEmpty();
}
@Test
public void convert_constant_per_issue_with_factor_by_constant_by_issue_with_offset() {
String xml = getFileContent("convert_constant_per_issue_with_factor_by_constant_by_issue_with_offset.xml");
- List<DebtRulesXMLImporter.RuleDebt> results = importer.importXML(xml);
+ List<DebtRulesXMLImporter.RuleDebt> results = importer.importXML(xml, validationMessages);
assertThat(results).hasSize(1);
DebtRulesXMLImporter.RuleDebt ruleDebt = results.get(0);
assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
- assertThat(ruleDebt.type()).isEqualTo(DebtRemediationFunction.Type.CONSTANT_ISSUE);
+ assertThat(ruleDebt.function()).isEqualTo(DebtRemediationFunction.Type.CONSTANT_ISSUE);
assertThat(ruleDebt.factor()).isNull();
assertThat(ruleDebt.offset()).isEqualTo("3h");
}
@@ -162,29 +169,33 @@ public class DebtRulesXMLImporterTest {
public void ignore_deprecated_constant_per_file_function() {
String xml = getFileContent("ignore_deprecated_constant_per_file_function.xml");
- List<DebtRulesXMLImporter.RuleDebt> results = importer.importXML(xml);
+ List<DebtRulesXMLImporter.RuleDebt> results = importer.importXML(xml, validationMessages);
assertThat(results).isEmpty();
+
+ assertThat(validationMessages.getWarnings()).isNotEmpty();
}
@Test
public void ignore_rule_on_root_characteristics() {
String xml = getFileContent("ignore_rule_on_root_characteristics.xml");
- List<DebtRulesXMLImporter.RuleDebt> results = importer.importXML(xml);
+ List<DebtRulesXMLImporter.RuleDebt> results = importer.importXML(xml, validationMessages);
assertThat(results).isEmpty();
+
+ assertThat(validationMessages.getWarnings()).isNotEmpty();
}
@Test
public void import_badly_formatted_xml() {
String xml = getFileContent("import_badly_formatted_xml.xml");
- List<DebtRulesXMLImporter.RuleDebt> results = importer.importXML(xml);
+ List<DebtRulesXMLImporter.RuleDebt> results = importer.importXML(xml, validationMessages);
assertThat(results).hasSize(1);
DebtRulesXMLImporter.RuleDebt ruleDebt = results.get(0);
assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
assertThat(ruleDebt.ruleKey()).isEqualTo(RuleKey.of("checkstyle", "Regexp"));
- assertThat(ruleDebt.type()).isEqualTo(org.sonar.api.server.rule.DebtRemediationFunction.Type.LINEAR);
+ assertThat(ruleDebt.function()).isEqualTo(org.sonar.api.server.rule.DebtRemediationFunction.Type.LINEAR);
assertThat(ruleDebt.factor()).isEqualTo("3h");
assertThat(ruleDebt.offset()).isNull();
}
@@ -192,8 +203,10 @@ public class DebtRulesXMLImporterTest {
@Test
public void ignore_invalid_value() throws Exception {
String xml = getFileContent("ignore_invalid_value.xml");
- List<DebtRulesXMLImporter.RuleDebt> results = importer.importXML(xml);
+ List<DebtRulesXMLImporter.RuleDebt> results = importer.importXML(xml, validationMessages);
assertThat(results).isEmpty();
+
+ assertThat(validationMessages.getErrors()).isNotEmpty();
}
@Test
diff --git a/sonar-server/src/test/java/org/sonar/server/rule/DeprecatedRulesDefinitionTest.java b/sonar-server/src/test/java/org/sonar/server/rule/DeprecatedRulesDefinitionTest.java
index 636b5f757de..cfad5d4927b 100644
--- a/sonar-server/src/test/java/org/sonar/server/rule/DeprecatedRulesDefinitionTest.java
+++ b/sonar-server/src/test/java/org/sonar/server/rule/DeprecatedRulesDefinitionTest.java
@@ -31,6 +31,7 @@ import org.sonar.api.rules.RulePriority;
import org.sonar.api.rules.RuleRepository;
import org.sonar.api.server.rule.DebtRemediationFunction;
import org.sonar.api.server.rule.RulesDefinition;
+import org.sonar.api.utils.ValidationMessages;
import org.sonar.core.i18n.RuleI18nManager;
import org.sonar.core.technicaldebt.TechnicalDebtModelRepository;
import org.sonar.server.debt.DebtRulesXMLImporter;
@@ -41,6 +42,7 @@ import java.util.List;
import static com.google.common.collect.Lists.newArrayList;
import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -158,7 +160,7 @@ public class DeprecatedRulesDefinitionTest {
new DebtRulesXMLImporter.RuleDebt()
.setCharacteristicKey("MEMORY_EFFICIENCY")
.setRuleKey(RuleKey.of("checkstyle", "ConstantName"))
- .setType(DebtRemediationFunction.Type.LINEAR_OFFSET)
+ .setFunction(DebtRemediationFunction.Type.LINEAR_OFFSET)
.setFactor("1d")
.setOffset("10min")
);
@@ -166,7 +168,7 @@ public class DeprecatedRulesDefinitionTest {
Reader javaModelReader = mock(Reader.class);
when(debtModelRepository.createReaderForXMLFile("java")).thenReturn(javaModelReader);
when(debtModelRepository.getContributingPluginList()).thenReturn(newArrayList("java"));
- when(importer.importXML(eq(javaModelReader))).thenReturn(ruleDebts);
+ when(importer.importXML(eq(javaModelReader), any(ValidationMessages.class))).thenReturn(ruleDebts);
new DeprecatedRulesDefinition(i18n, new RuleRepository[]{new CheckstyleRules()}, debtModelRepository, importer).define(context);