@@ -315,7 +315,7 @@ public final class RuleDto { | |||
} | |||
public boolean hasCharacteristic(){ | |||
return ((characteristicId != null && !RuleDto.DISABLED_CHARACTERISTIC_ID.equals(characteristicId))) || (characteristicId == null && defaultCharacteristicId != null); | |||
return (characteristicId != null && !RuleDto.DISABLED_CHARACTERISTIC_ID.equals(characteristicId)) || (characteristicId == null && defaultCharacteristicId != null); | |||
} | |||
@Override |
@@ -83,15 +83,17 @@ public class DefaultDebtCharacteristic implements DebtCharacteristic { | |||
} | |||
@Override | |||
@CheckForNull | |||
public Integer parentId() { | |||
return parentId; | |||
} | |||
public DefaultDebtCharacteristic setParentId(Integer parentId) { | |||
public DefaultDebtCharacteristic setParentId(@Nullable Integer parentId) { | |||
this.parentId = parentId; | |||
return this; | |||
} | |||
@Override | |||
public Date createdAt() { | |||
return createdAt; | |||
} | |||
@@ -101,6 +103,7 @@ public class DefaultDebtCharacteristic implements DebtCharacteristic { | |||
return this; | |||
} | |||
@Override | |||
@CheckForNull | |||
public Date updatedAt() { | |||
return updatedAt; |
@@ -22,6 +22,7 @@ package org.sonar.api.server.debt.internal; | |||
import com.google.common.base.Objects; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.apache.commons.lang.builder.EqualsBuilder; | |||
import org.sonar.api.server.debt.DebtRemediationFunction; | |||
import org.sonar.api.utils.Duration; | |||
@@ -33,12 +34,12 @@ public class DefaultDebtRemediationFunction implements DebtRemediationFunction { | |||
private static final int HOURS_IN_DAY = 24; | |||
private final Type type; | |||
private final String factor; | |||
private final String coefficient; | |||
private final String offset; | |||
public DefaultDebtRemediationFunction(Type type, @Nullable String factor, @Nullable String offset) { | |||
public DefaultDebtRemediationFunction(Type type, @Nullable String coefficient, @Nullable String offset) { | |||
this.type = type; | |||
this.factor = sanitizeValue("coefficient", factor); | |||
this.coefficient = sanitizeValue("coefficient", coefficient); | |||
this.offset = sanitizeValue("offset", offset); | |||
validate(); | |||
} | |||
@@ -64,7 +65,7 @@ public class DefaultDebtRemediationFunction implements DebtRemediationFunction { | |||
@Override | |||
@CheckForNull | |||
public String coefficient() { | |||
return factor; | |||
return coefficient; | |||
} | |||
@Override | |||
@@ -76,17 +77,17 @@ public class DefaultDebtRemediationFunction implements DebtRemediationFunction { | |||
private void validate() { | |||
switch (type) { | |||
case LINEAR: | |||
if (this.factor == null || this.offset != null) { | |||
if (this.coefficient == null || this.offset != null) { | |||
throw new IllegalArgumentException(String.format("Only coefficient must be set on %s", this)); | |||
} | |||
break; | |||
case LINEAR_OFFSET: | |||
if (this.factor == null || this.offset == null) { | |||
if (this.coefficient == null || this.offset == null) { | |||
throw new IllegalArgumentException(String.format("Both coefficient and offset are required on %s", this)); | |||
} | |||
break; | |||
case CONSTANT_ISSUE: | |||
if (this.factor != null || this.offset == null) { | |||
if (this.coefficient != null || this.offset == null) { | |||
throw new IllegalArgumentException(String.format("Only offset must be set on %s", this)); | |||
} | |||
break; | |||
@@ -97,26 +98,24 @@ public class DefaultDebtRemediationFunction implements DebtRemediationFunction { | |||
@Override | |||
public boolean equals(Object o) { | |||
if (this == o) { | |||
return true; | |||
} | |||
if (o == null || getClass() != o.getClass()) { | |||
return false; | |||
} | |||
DefaultDebtRemediationFunction that = (DefaultDebtRemediationFunction) o; | |||
if (factor != null ? !factor.equals(that.factor) : that.factor != null) { | |||
if (!(o instanceof DefaultDebtRemediationFunction)) { | |||
return false; | |||
} | |||
if (offset != null ? !offset.equals(that.offset) : that.offset != null) { | |||
return false; | |||
if (this == o) { | |||
return true; | |||
} | |||
return type == that.type; | |||
DefaultDebtRemediationFunction other = (DefaultDebtRemediationFunction) o; | |||
return new EqualsBuilder() | |||
.append(coefficient, other.coefficient()) | |||
.append(offset, other.offset()) | |||
.append(type, other.type()) | |||
.isEquals(); | |||
} | |||
@Override | |||
public int hashCode() { | |||
int result = type.hashCode(); | |||
result = 31 * result + (factor != null ? factor.hashCode() : 0); | |||
result = 31 * result + (coefficient != null ? coefficient.hashCode() : 0); | |||
result = 31 * result + (offset != null ? offset.hashCode() : 0); | |||
return result; | |||
} | |||
@@ -125,7 +124,7 @@ public class DefaultDebtRemediationFunction implements DebtRemediationFunction { | |||
public String toString() { | |||
return Objects.toStringHelper(DebtRemediationFunction.class) | |||
.add("type", type) | |||
.add("coefficient", factor) | |||
.add("coefficient", coefficient) | |||
.add("offset", offset) | |||
.toString(); | |||
} |
@@ -137,10 +137,6 @@ public interface RulesDefinition extends ServerExtension { | |||
* Default sub-characteristics of technical debt model. See http://www.sqale.org | |||
*/ | |||
final class SubCharacteristics { | |||
private SubCharacteristics() { | |||
// only constants | |||
} | |||
/** | |||
* Related to characteristic REUSABILITY | |||
*/ | |||
@@ -295,6 +291,10 @@ public interface RulesDefinition extends ServerExtension { | |||
* Related to characteristic TESTABILITY | |||
*/ | |||
public static final String UNIT_TESTABILITY = "UNIT_TESTABILITY"; | |||
private SubCharacteristics() { | |||
// only constants | |||
} | |||
} | |||
/** |
@@ -112,9 +112,11 @@ public class DebtModelBackup implements ServerComponent { | |||
List<RuleDebt> rules = newArrayList(); | |||
for (RuleDto rule : ruleDao.selectEnablesAndNonManual(session)) { | |||
if ((languageKey == null || languageKey.equals(rule.getLanguage())) && rule.hasCharacteristic()) { | |||
Integer characteristicId = rule.getCharacteristicId() != null ? rule.getCharacteristicId() : rule.getDefaultCharacteristicId(); | |||
rules.add(toRuleDebt(rule, debtModel.characteristicById(characteristicId).key())); | |||
if ((languageKey == null || languageKey.equals(rule.getLanguage()))) { | |||
Integer effectiveCharacteristicId = rule.getCharacteristicId() != null ? rule.getCharacteristicId() : rule.getDefaultCharacteristicId(); | |||
if (effectiveCharacteristicId != null && !RuleDto.DISABLED_CHARACTERISTIC_ID.equals(effectiveCharacteristicId)) { | |||
rules.add(toRuleDebt(rule, debtModel.characteristicById(effectiveCharacteristicId).key())); | |||
} | |||
} | |||
} | |||
return debtModelXMLExporter.export(debtModel, rules); | |||
@@ -151,8 +153,8 @@ public class DebtModelBackup implements ServerComponent { | |||
try { | |||
List<RuleDto> rules = newArrayList(Iterables.filter(ruleDao.selectEnablesAndNonManual(session), new Predicate<RuleDto>() { | |||
@Override | |||
public boolean apply(RuleDto input) { | |||
return languageKey.equals(input.getLanguage()); | |||
public boolean apply(@Nullable RuleDto input) { | |||
return input != null && languageKey.equals(input.getLanguage()); | |||
} | |||
})); | |||
restoreProvidedModel(rules, updateDate, session); | |||
@@ -201,8 +203,8 @@ public class DebtModelBackup implements ServerComponent { | |||
List<CharacteristicDto> characteristicDtos = dao.selectEnabledCharacteristics(session); | |||
List<RuleDto> rules = newArrayList(Iterables.filter(ruleDao.selectEnablesAndNonManual(session), new Predicate<RuleDto>() { | |||
@Override | |||
public boolean apply(RuleDto input) { | |||
return languageKey.equals(input.getLanguage()); | |||
public boolean apply(@Nullable RuleDto input) { | |||
return input != null && languageKey.equals(input.getLanguage()); | |||
} | |||
})); | |||
restoreRules(characteristicDtos, rules, rulesXMLImporter.importXML(xml, validationMessages), validationMessages, updateDate, session); | |||
@@ -227,10 +229,10 @@ public class DebtModelBackup implements ServerComponent { | |||
} else { | |||
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.setRemediationCoefficient((!isSameFunction ? ruleDebt.factor() : null)); | |||
rule.setRemediationOffset((!isSameFunction ? ruleDebt.offset() : null)); | |||
rule.setCharacteristicId(!isSameCharacteristic ? characteristicDto.getId() : null); | |||
rule.setRemediationFunction(!isSameFunction ? ruleDebt.function().name() : null); | |||
rule.setRemediationCoefficient(!isSameFunction ? ruleDebt.coefficient() : null); | |||
rule.setRemediationOffset(!isSameFunction ? ruleDebt.offset() : null); | |||
rule.setUpdatedAt(updateDate); | |||
ruleDao.update(rule, session); | |||
// TODO index rules in E/S | |||
@@ -290,12 +292,12 @@ public class DebtModelBackup implements ServerComponent { | |||
private static boolean isSameRemediationFunction(RuleDebt ruleDebt, RuleDto rule) { | |||
return new EqualsBuilder() | |||
.append(ruleDebt.function().name(), rule.getDefaultRemediationFunction()) | |||
.append(ruleDebt.factor(), rule.getDefaultRemediationCoefficient()) | |||
.append(ruleDebt.coefficient(), rule.getDefaultRemediationCoefficient()) | |||
.append(ruleDebt.offset(), rule.getDefaultRemediationOffset()) | |||
.isEquals(); | |||
} | |||
private void disabledRuleDebt(RuleDto rule, Date updateDate, SqlSession session){ | |||
private void disabledRuleDebt(RuleDto rule, Date updateDate, SqlSession session) { | |||
rule.setCharacteristicId(rule.getDefaultCharacteristicId() != null ? RuleDto.DISABLED_CHARACTERISTIC_ID : null); | |||
rule.setRemediationFunction(null); | |||
rule.setRemediationCoefficient(null); | |||
@@ -321,8 +323,8 @@ public class DebtModelBackup implements ServerComponent { | |||
} | |||
return Iterables.find(ruleDebts, new Predicate<RuleDebt>() { | |||
@Override | |||
public boolean apply(RuleDebt input) { | |||
return rule.getRepositoryKey().equals(input.ruleKey().repository()) && rule.getRuleKey().equals(input.ruleKey().rule()); | |||
public boolean apply(@Nullable RuleDebt input) { | |||
return input != null && rule.getRepositoryKey().equals(input.ruleKey().repository()) && rule.getRuleKey().equals(input.ruleKey().rule()); | |||
} | |||
}, null); | |||
} | |||
@@ -331,8 +333,8 @@ public class DebtModelBackup implements ServerComponent { | |||
private static CharacteristicDto characteristicByKey(final String key, List<CharacteristicDto> characteristicDtos) { | |||
return Iterables.find(characteristicDtos, new Predicate<CharacteristicDto>() { | |||
@Override | |||
public boolean apply(CharacteristicDto input) { | |||
return key.equals(input.getKey()); | |||
public boolean apply(@Nullable CharacteristicDto input) { | |||
return input != null && key.equals(input.getKey()); | |||
} | |||
}, null); | |||
} | |||
@@ -340,21 +342,25 @@ public class DebtModelBackup implements ServerComponent { | |||
private static List<CharacteristicDto> subCharacteristics(final Integer parentId, List<CharacteristicDto> allCharacteristics) { | |||
return newArrayList(Iterables.filter(allCharacteristics, new Predicate<CharacteristicDto>() { | |||
@Override | |||
public boolean apply(CharacteristicDto input) { | |||
return parentId.equals(input.getParentId()); | |||
public boolean apply(@Nullable CharacteristicDto input) { | |||
return input != null && parentId.equals(input.getParentId()); | |||
} | |||
})); | |||
} | |||
private static RuleDebt toRuleDebt(RuleDto rule, String characteristicKey) { | |||
RuleDebt ruleDebt = new RuleDebt().setRuleKey(RuleKey.of(rule.getRepositoryKey(), rule.getRuleKey())); | |||
String function = rule.getRemediationFunction() != null ? rule.getRemediationFunction() : rule.getDefaultRemediationFunction(); | |||
String factor = rule.getRemediationCoefficient() != null ? rule.getRemediationCoefficient() : rule.getDefaultRemediationCoefficient(); | |||
String offset = rule.getRemediationOffset() != null ? rule.getRemediationOffset() : rule.getDefaultRemediationOffset(); | |||
String function = rule.getRemediationFunction(); | |||
String coefficient = rule.getRemediationCoefficient(); | |||
String offset = rule.getRemediationOffset(); | |||
String effectiveFunction = function != null ? function : rule.getDefaultRemediationFunction(); | |||
String effectiveCoefficient = coefficient != null ? coefficient : rule.getDefaultRemediationCoefficient(); | |||
String effectiveOffset = offset != null ? offset : rule.getDefaultRemediationOffset(); | |||
ruleDebt.setCharacteristicKey(characteristicKey); | |||
ruleDebt.setFunction(DebtRemediationFunction.Type.valueOf(function)); | |||
ruleDebt.setFactor(factor); | |||
ruleDebt.setOffset(offset); | |||
ruleDebt.setFunction(DebtRemediationFunction.Type.valueOf(effectiveFunction)); | |||
ruleDebt.setCoefficient(effectiveCoefficient); | |||
ruleDebt.setOffset(effectiveOffset); | |||
return ruleDebt; | |||
} | |||
@@ -29,6 +29,7 @@ import org.sonar.core.technicaldebt.db.CharacteristicDao; | |||
import org.sonar.core.technicaldebt.db.CharacteristicDto; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
import java.util.Collection; | |||
import java.util.List; | |||
@@ -60,8 +61,8 @@ public class DebtModelLookup implements ServerComponent { | |||
private static List<DebtCharacteristic> toCharacteristics(Collection<CharacteristicDto> dtos) { | |||
return newArrayList(Iterables.transform(dtos, new Function<CharacteristicDto, DebtCharacteristic>() { | |||
@Override | |||
public DebtCharacteristic apply(CharacteristicDto input) { | |||
return toCharacteristic(input); | |||
public DebtCharacteristic apply(@Nullable CharacteristicDto input) { | |||
return input != null ? toCharacteristic(input) : null; | |||
} | |||
})); | |||
} |
@@ -130,7 +130,10 @@ public class DebtModelOperations implements ServerComponent { | |||
SqlSession session = mybatis.openSession(); | |||
try { | |||
final CharacteristicDto dto = findCharacteristic(characteristicId, session); | |||
int currentOrder = dto.getOrder(); | |||
if (dto.getParentId() != null) { | |||
throw new BadRequestException("Sub characteristics can not be moved."); | |||
} | |||
int currentOrder = getOrder(dto); | |||
CharacteristicDto dtoToSwitchOrderWith = findCharacteristicToSwitchWith(dto, moveUpOrDown, session); | |||
// Do nothing when characteristic is already to the good location | |||
@@ -138,7 +141,7 @@ public class DebtModelOperations implements ServerComponent { | |||
return toCharacteristic(dto); | |||
} | |||
int nextOrder = dtoToSwitchOrderWith.getOrder(); | |||
int nextOrder = getOrder(dtoToSwitchOrderWith); | |||
dtoToSwitchOrderWith.setOrder(currentOrder); | |||
dtoToSwitchOrderWith.setUpdatedAt(new Date(system2.now())); | |||
dao.update(dtoToSwitchOrderWith, session); | |||
@@ -154,14 +157,22 @@ public class DebtModelOperations implements ServerComponent { | |||
} | |||
} | |||
private int getOrder(CharacteristicDto characteristicDto){ | |||
Integer order= characteristicDto.getOrder(); | |||
if (order == null) { | |||
throw new IllegalArgumentException(String.format("The order of the characteristic '%s' should not be null", characteristicDto.getKey())); | |||
} | |||
return order; | |||
} | |||
@CheckForNull | |||
private CharacteristicDto findCharacteristicToSwitchWith(final CharacteristicDto dto, final boolean moveUpOrDown, SqlSession session) { | |||
// characteristics should be order by 'order' | |||
List<CharacteristicDto> rootCharacteristics = dao.selectEnabledRootCharacteristics(session); | |||
int currentPosition = Iterables.indexOf(rootCharacteristics, new Predicate<CharacteristicDto>() { | |||
@Override | |||
public boolean apply(CharacteristicDto input) { | |||
return input.getKey().equals(dto.getKey()); | |||
public boolean apply(@Nullable CharacteristicDto input) { | |||
return input != null && input.getKey().equals(dto.getKey()); | |||
} | |||
}); | |||
Integer nextPosition = moveUpOrDown ? (currentPosition > 0 ? currentPosition - 1 : null) : (currentPosition < rootCharacteristics.size() - 1 ? currentPosition + 1 : null); |
@@ -68,7 +68,7 @@ public class DebtModelXMLExporter implements ServerComponent { | |||
public static final String RULE_KEY = "rule-key"; | |||
public static final String PROPERTY_FUNCTION = "remediationFunction"; | |||
public static final String PROPERTY_FACTOR = "remediationFactor"; | |||
public static final String PROPERTY_COEFFICIENT = "remediationFactor"; | |||
public static final String PROPERTY_OFFSET = "offset"; | |||
protected String export(DebtModel debtModel, List<RuleDebt> allRules) { | |||
@@ -114,13 +114,13 @@ public class DebtModelXMLExporter implements ServerComponent { | |||
xml.append(StringEscapeUtils.escapeXml(rule.ruleKey().rule())); | |||
xml.append("</" + RULE_KEY + ">"); | |||
String factor = rule.factor(); | |||
String coefficient = rule.coefficient(); | |||
String offset = rule.offset(); | |||
appendProperty(PROPERTY_FUNCTION, null, rule.function().name(), xml); | |||
if (factor != null) { | |||
String[] values = getValues(factor); | |||
appendProperty(PROPERTY_FACTOR, values[0], values[1], xml); | |||
if (coefficient != null) { | |||
String[] values = getValues(coefficient); | |||
appendProperty(PROPERTY_COEFFICIENT, values[0], values[1], xml); | |||
} | |||
if (offset != null) { | |||
String[] values = getValues(offset); | |||
@@ -266,7 +266,7 @@ public class DebtModelXMLExporter implements ServerComponent { | |||
private RuleKey ruleKey; | |||
private String characteristicKey; | |||
private DebtRemediationFunction.Type type; | |||
private String factor; | |||
private String coefficient; | |||
private String offset; | |||
public RuleKey ruleKey() { | |||
@@ -297,12 +297,12 @@ public class DebtModelXMLExporter implements ServerComponent { | |||
} | |||
@CheckForNull | |||
public String factor() { | |||
return factor; | |||
public String coefficient() { | |||
return coefficient; | |||
} | |||
public RuleDebt setFactor(@Nullable String factor) { | |||
this.factor = factor; | |||
public RuleDebt setCoefficient(@Nullable String coefficient) { | |||
this.coefficient = coefficient; | |||
return this; | |||
} | |||
@@ -315,6 +315,17 @@ public class DebtModelXMLExporter implements ServerComponent { | |||
this.offset = offset; | |||
return this; | |||
} | |||
@Override | |||
public String toString() { | |||
return "RuleDebt{" + | |||
"ruleKey=" + ruleKey + | |||
", characteristicKey='" + characteristicKey + '\'' + | |||
", type=" + type + | |||
", coefficient='" + coefficient + '\'' + | |||
", offset='" + offset + '\'' + | |||
'}'; | |||
} | |||
} | |||
} |
@@ -85,7 +85,8 @@ public class DebtRulesXMLImporter implements ServerComponent { | |||
return new SMInputFactory(xmlFactory); | |||
} | |||
private void process(List<RuleDebt> ruleDebts, @Nullable String rootKey, @Nullable String parentKey, ValidationMessages validationMessages, 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) { | |||
@@ -159,27 +160,27 @@ public class DebtRulesXMLImporter implements ServerComponent { | |||
Property function = properties.function(); | |||
if (function != null) { | |||
Property factorProperty = properties.factor(); | |||
String factor = factorProperty != null ? factorProperty.toDuration() : null; | |||
Property coefficientProperty = properties.coefficient(); | |||
String coefficient = coefficientProperty != null ? coefficientProperty.toDuration() : null; | |||
Property offsetProperty = properties.offset(); | |||
String offset = offsetProperty != null ? offsetProperty.toDuration() : null; | |||
return createRuleDebt(ruleKey, function.getTextValue(), factor, offset, validationMessages); | |||
return createRuleDebt(ruleKey, function.getTextValue(), coefficient, offset, validationMessages); | |||
} | |||
return null; | |||
} | |||
@CheckForNull | |||
private RuleDebt createRuleDebt(RuleKey ruleKey, String function, @Nullable String factor, @Nullable String offset, ValidationMessages validationMessages) { | |||
if ("linear_threshold".equals(function) && factor != null) { | |||
private RuleDebt createRuleDebt(RuleKey ruleKey, String function, @Nullable String coefficient, @Nullable String offset, ValidationMessages validationMessages) { | |||
if ("linear_threshold".equals(function) && coefficient != null) { | |||
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); | |||
return new RuleDebt().setRuleKey(ruleKey).setFunction(DebtRemediationFunction.Type.LINEAR).setCoefficient(coefficient); | |||
} else if ("constant_resource".equals(function)) { | |||
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).setFunction(DebtRemediationFunction.Type.CONSTANT_ISSUE).setOffset(factor); | |||
} else if (DebtRemediationFunction.Type.CONSTANT_ISSUE.name().equalsIgnoreCase(function) && coefficient != null && offset == null) { | |||
return new RuleDebt().setRuleKey(ruleKey).setFunction(DebtRemediationFunction.Type.CONSTANT_ISSUE).setOffset(coefficient); | |||
} else { | |||
return new RuleDebt().setRuleKey(ruleKey).setFunction(DebtRemediationFunction.Type.valueOf(function.toUpperCase())).setFactor(factor).setOffset(offset); | |||
return new RuleDebt().setRuleKey(ruleKey).setFunction(DebtRemediationFunction.Type.valueOf(function.toUpperCase())).setCoefficient(coefficient).setOffset(offset); | |||
} | |||
return null; | |||
} | |||
@@ -200,8 +201,8 @@ public class DebtRulesXMLImporter implements ServerComponent { | |||
return find(PROPERTY_FUNCTION); | |||
} | |||
public Property factor() { | |||
return find(PROPERTY_FACTOR); | |||
public Property coefficient() { | |||
return find(PROPERTY_COEFFICIENT); | |||
} | |||
public Property offset() { |
@@ -29,6 +29,7 @@ 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.debt.DebtRemediationFunction; | |||
import org.sonar.api.server.rule.RuleParamType; | |||
import org.sonar.api.server.rule.RulesDefinition; | |||
import org.sonar.api.utils.ValidationMessages; | |||
@@ -108,22 +109,22 @@ public class DeprecatedRulesDefinition implements RulesDefinition { | |||
} | |||
} | |||
private void updateRuleDebtDefinitions(NewRule newRule, String repoKey, String ruleKey, List<RuleDebt> ruleDebts){ | |||
private void updateRuleDebtDefinitions(NewRule newRule, String repoKey, String ruleKey, List<RuleDebt> ruleDebts) { | |||
RuleDebt ruleDebt = findRequirement(ruleDebts, repoKey, ruleKey); | |||
if (ruleDebt != null) { | |||
newRule.setDebtSubCharacteristic(ruleDebt.characteristicKey()); | |||
switch (ruleDebt.function()) { | |||
case LINEAR : | |||
newRule.setDebtRemediationFunction(newRule.debtRemediationFunctions().linear(ruleDebt.factor())); | |||
break; | |||
case LINEAR_OFFSET: | |||
newRule.setDebtRemediationFunction(newRule.debtRemediationFunctions().linearWithOffset(ruleDebt.factor(), ruleDebt.offset())); | |||
break; | |||
case CONSTANT_ISSUE: | |||
newRule.setDebtRemediationFunction(newRule.debtRemediationFunctions().constantPerIssue(ruleDebt.offset())); | |||
break; | |||
default : | |||
throw new IllegalArgumentException(String.format("The type '%s' is unknown", ruleDebt.function())); | |||
DebtRemediationFunction.Type function = ruleDebt.function(); | |||
String coefficient = ruleDebt.coefficient(); | |||
String offset = ruleDebt.offset(); | |||
if (DebtRemediationFunction.Type.LINEAR.equals(function) && coefficient != null) { | |||
newRule.setDebtRemediationFunction(newRule.debtRemediationFunctions().linear(coefficient)); | |||
} else if (DebtRemediationFunction.Type.CONSTANT_ISSUE.equals(function) && offset != null) { | |||
newRule.setDebtRemediationFunction(newRule.debtRemediationFunctions().constantPerIssue(offset)); | |||
} else if (DebtRemediationFunction.Type.LINEAR_OFFSET.equals(function) && coefficient != null && offset != null) { | |||
newRule.setDebtRemediationFunction(newRule.debtRemediationFunctions().linearWithOffset(coefficient, offset)); | |||
} else { | |||
throw new IllegalArgumentException(String.format("Debt definition on rule '%s:%s' is invalid", repoKey, ruleKey)); | |||
} | |||
} | |||
} |
@@ -169,7 +169,7 @@ public class DebtModelBackupTest { | |||
assertThat(rule.ruleKey().rule()).isEqualTo("UselessImportCheck"); | |||
assertThat(rule.characteristicKey()).isEqualTo("COMPILER"); | |||
assertThat(rule.function().name()).isEqualTo("LINEAR_OFFSET"); | |||
assertThat(rule.factor()).isEqualTo("2h"); | |||
assertThat(rule.coefficient()).isEqualTo("2h"); | |||
assertThat(rule.offset()).isEqualTo("15min"); | |||
rule = rules.get(1); | |||
@@ -177,7 +177,7 @@ public class DebtModelBackupTest { | |||
assertThat(rule.ruleKey().rule()).isEqualTo("AvoidNPE"); | |||
assertThat(rule.characteristicKey()).isEqualTo("COMPILER"); | |||
assertThat(rule.function().name()).isEqualTo("LINEAR"); | |||
assertThat(rule.factor()).isEqualTo("2h"); | |||
assertThat(rule.coefficient()).isEqualTo("2h"); | |||
assertThat(rule.offset()).isNull(); | |||
} | |||
@@ -232,7 +232,7 @@ public class DebtModelBackupTest { | |||
assertThat(rule.ruleKey().rule()).isEqualTo("UselessImportCheck"); | |||
assertThat(rule.characteristicKey()).isEqualTo("COMPILER"); | |||
assertThat(rule.function().name()).isEqualTo("CONSTANT_ISSUE"); | |||
assertThat(rule.factor()).isNull(); | |||
assertThat(rule.coefficient()).isNull(); | |||
assertThat(rule.offset()).isEqualTo("15min"); | |||
} | |||
@@ -428,7 +428,7 @@ public class DebtModelBackupTest { | |||
new CharacteristicDto().setId(2).setKey("COMPILER").setName("Compiler").setParentId(1).setCreatedAt(oldDate))); | |||
when(rulesXMLImporter.importXML(anyString(), any(ValidationMessages.class))).thenReturn(newArrayList(new RuleDebt() | |||
.setRuleKey(RuleKey.of("squid", "UselessImportCheck")).setCharacteristicKey("COMPILER").setFunction(DebtRemediationFunction.Type.LINEAR).setFactor("2h"))); | |||
.setRuleKey(RuleKey.of("squid", "UselessImportCheck")).setCharacteristicKey("COMPILER").setFunction(DebtRemediationFunction.Type.LINEAR).setCoefficient("2h"))); | |||
when(ruleDao.selectEnablesAndNonManual(session)).thenReturn(newArrayList( | |||
new RuleDto().setId(1).setRepositoryKey("squid").setRuleKey("UselessImportCheck") | |||
@@ -464,7 +464,7 @@ public class DebtModelBackupTest { | |||
new CharacteristicDto().setId(2).setKey("COMPILER").setName("Compiler").setParentId(1).setCreatedAt(oldDate))); | |||
when(rulesXMLImporter.importXML(anyString(), any(ValidationMessages.class))).thenReturn(newArrayList(new RuleDebt() | |||
.setRuleKey(RuleKey.of("squid", "UselessImportCheck")).setCharacteristicKey("COMPILER").setFunction(DebtRemediationFunction.Type.LINEAR_OFFSET).setFactor("12h").setOffset("11min"))); | |||
.setRuleKey(RuleKey.of("squid", "UselessImportCheck")).setCharacteristicKey("COMPILER").setFunction(DebtRemediationFunction.Type.LINEAR_OFFSET).setCoefficient("12h").setOffset("11min"))); | |||
when(ruleDao.selectEnablesAndNonManual(session)).thenReturn(newArrayList( | |||
new RuleDto().setId(1).setRepositoryKey("squid").setRuleKey("UselessImportCheck") | |||
@@ -500,7 +500,7 @@ public class DebtModelBackupTest { | |||
new CharacteristicDto().setId(2).setKey("COMPILER").setName("Compiler").setParentId(1).setCreatedAt(oldDate))); | |||
when(rulesXMLImporter.importXML(anyString(), any(ValidationMessages.class))).thenReturn(newArrayList(new RuleDebt() | |||
.setRuleKey(RuleKey.of("squid", "UselessImportCheck")).setCharacteristicKey("COMPILER").setFunction(DebtRemediationFunction.Type.LINEAR_OFFSET).setFactor("2h").setOffset("15min"))); | |||
.setRuleKey(RuleKey.of("squid", "UselessImportCheck")).setCharacteristicKey("COMPILER").setFunction(DebtRemediationFunction.Type.LINEAR_OFFSET).setCoefficient("2h").setOffset("15min"))); | |||
when(ruleDao.selectEnablesAndNonManual(session)).thenReturn(newArrayList( | |||
new RuleDto().setId(1).setRepositoryKey("squid").setRuleKey("UselessImportCheck") | |||
@@ -598,7 +598,7 @@ public class DebtModelBackupTest { | |||
new CharacteristicDto().setId(2).setKey("COMPILER").setName("Compiler").setParentId(1).setCreatedAt(oldDate))); | |||
when(rulesXMLImporter.importXML(anyString(), any(ValidationMessages.class))).thenReturn(newArrayList(new RuleDebt() | |||
.setRuleKey(RuleKey.of("squid", "UselessImportCheck")).setCharacteristicKey("COMPILER").setFunction(DebtRemediationFunction.Type.LINEAR).setFactor("2h"))); | |||
.setRuleKey(RuleKey.of("squid", "UselessImportCheck")).setCharacteristicKey("COMPILER").setFunction(DebtRemediationFunction.Type.LINEAR).setCoefficient("2h"))); | |||
when(ruleDao.selectEnablesAndNonManual(session)).thenReturn(newArrayList( | |||
new RuleDto().setId(1).setRepositoryKey("squid").setRuleKey("UselessImportCheck").setLanguage("java") | |||
@@ -677,7 +677,7 @@ public class DebtModelBackupTest { | |||
when(rulesXMLImporter.importXML(anyString(), any(ValidationMessages.class))).thenReturn(newArrayList(new RuleDebt() | |||
// Linked on a default disabled characteristic -> Rule debt should be disabled | |||
.setRuleKey(RuleKey.of("squid", "UselessImportCheck")).setCharacteristicKey("HARDWARE").setFunction(DebtRemediationFunction.Type.LINEAR).setFactor("2h"))); | |||
.setRuleKey(RuleKey.of("squid", "UselessImportCheck")).setCharacteristicKey("HARDWARE").setFunction(DebtRemediationFunction.Type.LINEAR).setCoefficient("2h"))); | |||
debtModelBackup.restoreFromXml("<xml/>", "java"); | |||
@@ -710,7 +710,7 @@ public class DebtModelBackupTest { | |||
new CharacteristicDto().setId(2).setKey("COMPILER").setName("Compiler").setParentId(1).setCreatedAt(oldDate))); | |||
when(rulesXMLImporter.importXML(anyString(), any(ValidationMessages.class))).thenReturn(newArrayList(new RuleDebt() | |||
.setRuleKey(RuleKey.of("squid", "UselessImportCheck")).setCharacteristicKey("COMPILER").setFunction(DebtRemediationFunction.Type.LINEAR).setFactor("2h"))); | |||
.setRuleKey(RuleKey.of("squid", "UselessImportCheck")).setCharacteristicKey("COMPILER").setFunction(DebtRemediationFunction.Type.LINEAR).setCoefficient("2h"))); | |||
when(ruleDao.selectEnablesAndNonManual(session)).thenReturn(Collections.<RuleDto>emptyList()); | |||
@@ -298,6 +298,42 @@ public class DebtModelOperationsTest { | |||
verify(dao, never()).update(any(CharacteristicDto.class), eq(session)); | |||
} | |||
@Test | |||
public void fail_to_move_sub_characteristic() { | |||
when(dao.selectById(10, session)).thenReturn(new CharacteristicDto().setId(10).setKey("MEMORY_EFFICIENCY").setParentId(1)); | |||
when(dao.selectEnabledRootCharacteristics(session)).thenReturn(newArrayList( | |||
new CharacteristicDto().setId(10).setKey("MEMORY_EFFICIENCY").setOrder(2), | |||
new CharacteristicDto().setId(2).setKey("PORTABILITY").setOrder(3) | |||
)); | |||
try { | |||
service.moveDown(10); | |||
fail(); | |||
} catch (Exception e) { | |||
assertThat(e).isInstanceOf(BadRequestException.class).hasMessage("Sub characteristics can not be moved."); | |||
} | |||
verify(dao, never()).update(any(CharacteristicDto.class), eq(session)); | |||
} | |||
@Test | |||
public void fail_to_move_characteristic_with_no_order() { | |||
when(dao.selectById(10, session)).thenReturn(new CharacteristicDto().setId(10).setKey("MEMORY_EFFICIENCY").setOrder(null)); | |||
when(dao.selectEnabledRootCharacteristics(session)).thenReturn(newArrayList( | |||
new CharacteristicDto().setId(10).setKey("MEMORY_EFFICIENCY").setOrder(2), | |||
new CharacteristicDto().setId(2).setKey("PORTABILITY").setOrder(3) | |||
)); | |||
try { | |||
service.moveDown(10); | |||
fail(); | |||
} catch (Exception e) { | |||
assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("The order of the characteristic 'MEMORY_EFFICIENCY' should not be null"); | |||
} | |||
verify(dao, never()).update(any(CharacteristicDto.class), eq(session)); | |||
} | |||
@Test | |||
public void delete_sub_characteristic() { | |||
BatchSession batchSession = mock(BatchSession.class); |
@@ -25,8 +25,8 @@ import org.apache.commons.lang.SystemUtils; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import org.sonar.api.rule.RuleKey; | |||
import org.sonar.api.server.debt.internal.DefaultDebtCharacteristic; | |||
import org.sonar.api.server.debt.DebtRemediationFunction; | |||
import org.sonar.api.server.debt.internal.DefaultDebtCharacteristic; | |||
import org.sonar.test.TestUtils; | |||
import java.io.IOException; | |||
@@ -62,7 +62,7 @@ public class DebtModelXMLExporterTest { | |||
List<RuleDebt> rules = newArrayList( | |||
new RuleDebt().setRuleKey(RuleKey.of("checkstyle", "Regexp")) | |||
.setCharacteristicKey("MEMORY_USE").setFunction(DebtRemediationFunction.Type.LINEAR_OFFSET).setFactor("3d").setOffset("15min") | |||
.setCharacteristicKey("MEMORY_USE").setFunction(DebtRemediationFunction.Type.LINEAR_OFFSET).setCoefficient("3d").setOffset("15min") | |||
); | |||
TestUtils.assertSimilarXml(getFileContent("export_xml.xml"), xmlExporter.export(debtModel, rules)); | |||
@@ -99,7 +99,7 @@ public class DebtModelXMLExporterTest { | |||
List<RuleDebt> rules = newArrayList( | |||
new RuleDebt().setRuleKey(RuleKey.of("checkstyle", "Regexp")) | |||
.setCharacteristicKey("MEMORY_USE").setFunction(DebtRemediationFunction.Type.LINEAR).setFactor("3d") | |||
.setCharacteristicKey("MEMORY_USE").setFunction(DebtRemediationFunction.Type.LINEAR).setCoefficient("3d") | |||
); | |||
assertThat(xmlExporter.export(debtModel, rules)).isEqualTo( | |||
"<sqale>" + SystemUtils.LINE_SEPARATOR + |
@@ -61,7 +61,7 @@ public class DebtRulesXMLImporterTest { | |||
assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY"); | |||
assertThat(ruleDebt.ruleKey()).isEqualTo(RuleKey.of("checkstyle", "Regexp")); | |||
assertThat(ruleDebt.function()).isEqualTo(DebtRemediationFunction.Type.LINEAR); | |||
assertThat(ruleDebt.factor()).isEqualTo("3h"); | |||
assertThat(ruleDebt.coefficient()).isEqualTo("3h"); | |||
assertThat(ruleDebt.offset()).isNull(); | |||
} | |||
@@ -76,7 +76,7 @@ public class DebtRulesXMLImporterTest { | |||
assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY"); | |||
assertThat(ruleDebt.ruleKey()).isEqualTo(RuleKey.of("checkstyle", "Regexp")); | |||
assertThat(ruleDebt.function()).isEqualTo(DebtRemediationFunction.Type.LINEAR); | |||
assertThat(ruleDebt.factor()).isEqualTo("3h"); | |||
assertThat(ruleDebt.coefficient()).isEqualTo("3h"); | |||
assertThat(ruleDebt.offset()).isNull(); | |||
} | |||
@@ -90,7 +90,7 @@ public class DebtRulesXMLImporterTest { | |||
RuleDebt ruleDebt = results.get(0); | |||
assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY"); | |||
assertThat(ruleDebt.function()).isEqualTo(DebtRemediationFunction.Type.LINEAR_OFFSET); | |||
assertThat(ruleDebt.factor()).isEqualTo("3h"); | |||
assertThat(ruleDebt.coefficient()).isEqualTo("3h"); | |||
assertThat(ruleDebt.offset()).isEqualTo("1min"); | |||
} | |||
@@ -104,7 +104,7 @@ public class DebtRulesXMLImporterTest { | |||
RuleDebt ruleDebt = results.get(0); | |||
assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY"); | |||
assertThat(ruleDebt.function()).isEqualTo(DebtRemediationFunction.Type.CONSTANT_ISSUE); | |||
assertThat(ruleDebt.factor()).isNull(); | |||
assertThat(ruleDebt.coefficient()).isNull(); | |||
assertThat(ruleDebt.offset()).isEqualTo("3d"); | |||
} | |||
@@ -118,7 +118,7 @@ public class DebtRulesXMLImporterTest { | |||
RuleDebt ruleDebt = results.get(0); | |||
assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY"); | |||
assertThat(ruleDebt.function()).isEqualTo(DebtRemediationFunction.Type.LINEAR_OFFSET); | |||
assertThat(ruleDebt.factor()).isEqualTo("3d"); | |||
assertThat(ruleDebt.coefficient()).isEqualTo("3d"); | |||
assertThat(ruleDebt.offset()).isEqualTo("1d"); | |||
} | |||
@@ -132,7 +132,7 @@ public class DebtRulesXMLImporterTest { | |||
RuleDebt ruleDebt = results.get(0); | |||
assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY"); | |||
assertThat(ruleDebt.function()).isEqualTo(DebtRemediationFunction.Type.LINEAR); | |||
assertThat(ruleDebt.factor()).isEqualTo("3min"); | |||
assertThat(ruleDebt.coefficient()).isEqualTo("3min"); | |||
assertThat(ruleDebt.offset()).isNull(); | |||
} | |||
@@ -147,7 +147,7 @@ public class DebtRulesXMLImporterTest { | |||
assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY"); | |||
assertThat(ruleDebt.ruleKey()).isEqualTo(RuleKey.of("checkstyle", "Regexp")); | |||
assertThat(ruleDebt.function()).isEqualTo(DebtRemediationFunction.Type.LINEAR); | |||
assertThat(ruleDebt.factor()).isEqualTo("3h"); | |||
assertThat(ruleDebt.coefficient()).isEqualTo("3h"); | |||
assertThat(ruleDebt.offset()).isNull(); | |||
} | |||
@@ -161,15 +161,15 @@ public class DebtRulesXMLImporterTest { | |||
RuleDebt ruleDebt = results.get(0); | |||
assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY"); | |||
assertThat(ruleDebt.function()).isEqualTo(DebtRemediationFunction.Type.LINEAR); | |||
assertThat(ruleDebt.factor()).isEqualTo("3h"); | |||
assertThat(ruleDebt.coefficient()).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"); | |||
public void convert_constant_per_issue_with_coefficient_by_constant_per_issue_with_offset() { | |||
String xml = getFileContent("convert_constant_per_issue_with_coefficient_by_constant_per_issue_with_offset.xml"); | |||
List<RuleDebt> results = importer.importXML(xml, validationMessages); | |||
assertThat(results).hasSize(1); | |||
@@ -177,7 +177,7 @@ public class DebtRulesXMLImporterTest { | |||
RuleDebt ruleDebt = results.get(0); | |||
assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY"); | |||
assertThat(ruleDebt.function()).isEqualTo(DebtRemediationFunction.Type.CONSTANT_ISSUE); | |||
assertThat(ruleDebt.factor()).isNull(); | |||
assertThat(ruleDebt.coefficient()).isNull(); | |||
assertThat(ruleDebt.offset()).isEqualTo("3h"); | |||
} | |||
@@ -212,7 +212,7 @@ public class DebtRulesXMLImporterTest { | |||
assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY"); | |||
assertThat(ruleDebt.ruleKey()).isEqualTo(RuleKey.of("checkstyle", "Regexp")); | |||
assertThat(ruleDebt.function()).isEqualTo(DebtRemediationFunction.Type.LINEAR); | |||
assertThat(ruleDebt.factor()).isEqualTo("3h"); | |||
assertThat(ruleDebt.coefficient()).isEqualTo("3h"); | |||
assertThat(ruleDebt.offset()).isNull(); | |||
} | |||
@@ -43,6 +43,7 @@ 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.mock; | |||
@@ -162,7 +163,7 @@ public class DeprecatedRulesDefinitionTest { | |||
.setCharacteristicKey("MEMORY_EFFICIENCY") | |||
.setRuleKey(RuleKey.of("checkstyle", "ConstantName")) | |||
.setFunction(DebtRemediationFunction.Type.LINEAR_OFFSET) | |||
.setFactor("1d") | |||
.setCoefficient("1d") | |||
.setOffset("10min") | |||
); | |||
@@ -186,4 +187,31 @@ public class DeprecatedRulesDefinitionTest { | |||
assertThat(rule.debtRemediationFunction().offset()).isEqualTo("10min"); | |||
} | |||
@Test | |||
public void fail_on_invalid_rule_debt() throws Exception { | |||
RulesDefinition.Context context = new RulesDefinition.Context(); | |||
List<DebtModelXMLExporter.RuleDebt> ruleDebts = newArrayList( | |||
new DebtModelXMLExporter.RuleDebt() | |||
.setCharacteristicKey("MEMORY_EFFICIENCY") | |||
.setRuleKey(RuleKey.of("checkstyle", "ConstantName")) | |||
.setFunction(DebtRemediationFunction.Type.LINEAR_OFFSET) | |||
.setCoefficient("1d") | |||
); | |||
Reader javaModelReader = mock(Reader.class); | |||
when(debtModelRepository.createReaderForXMLFile("java")).thenReturn(javaModelReader); | |||
when(debtModelRepository.getContributingPluginList()).thenReturn(newArrayList("java")); | |||
when(importer.importXML(eq(javaModelReader), any(ValidationMessages.class))).thenReturn(ruleDebts); | |||
try { | |||
new DeprecatedRulesDefinition(i18n, new RuleRepository[]{new CheckstyleRules()}, debtModelRepository, importer).define(context); | |||
fail(); | |||
} catch (Exception e) { | |||
assertThat(e).isInstanceOf(IllegalArgumentException.class); | |||
} | |||
assertThat(context.repositories()).isEmpty(); | |||
} | |||
} |