Browse Source

SONAR-5121 Verify remediation factor and offset following remediation function defined on rules

tags/4.3
Julien Lancelot 10 years ago
parent
commit
dd6a45a1ba
40 changed files with 596 additions and 242 deletions
  1. 140
    0
      sonar-plugin-api/src/main/java/org/sonar/api/server/rule/DebtRemediationFunction.java
  2. 14
    43
      sonar-plugin-api/src/main/java/org/sonar/api/server/rule/RulesDefinition.java
  3. 146
    0
      sonar-plugin-api/src/test/java/org/sonar/api/server/rule/DebtRemediationFunctionTest.java
  4. 8
    49
      sonar-plugin-api/src/test/java/org/sonar/api/server/rule/RulesDefinitionTest.java
  5. 2
    2
      sonar-server/src/main/java/org/sonar/server/debt/DebtCharacteristicsXMLImporter.java
  6. 3
    1
      sonar-server/src/main/java/org/sonar/server/debt/DebtModelSynchronizer.java
  7. 45
    68
      sonar-server/src/main/java/org/sonar/server/debt/DebtRulesXMLImporter.java
  8. 1
    1
      sonar-server/src/main/java/org/sonar/server/debt/DebtService.java
  9. 1
    1
      sonar-server/src/main/java/org/sonar/server/debt/package-info.java
  10. 8
    2
      sonar-server/src/main/java/org/sonar/server/platform/Platform.java
  11. 3
    5
      sonar-server/src/main/java/org/sonar/server/rule/DeprecatedRulesDefinition.java
  12. 16
    16
      sonar-server/src/main/java/org/sonar/server/rule/RuleRegistration.java
  13. 2
    0
      sonar-server/src/main/java/org/sonar/server/startup/CopyRequirementsFromCharacteristicsToRules.java
  14. 1
    1
      sonar-server/src/main/java/org/sonar/server/startup/RegisterDebtModel.java
  15. 1
    1
      sonar-server/src/main/webapp/WEB-INF/app/models/internal.rb
  16. 2
    1
      sonar-server/src/test/java/org/sonar/server/debt/DebtCharacteristicsXMLImporterTest.java
  17. 3
    1
      sonar-server/src/test/java/org/sonar/server/debt/DebtModelSynchronizerTest.java
  18. 47
    23
      sonar-server/src/test/java/org/sonar/server/debt/DebtRulesXMLImporterTest.java
  19. 1
    1
      sonar-server/src/test/java/org/sonar/server/debt/DebtServiceTest.java
  20. 6
    10
      sonar-server/src/test/java/org/sonar/server/rule/DeprecatedRulesDefinitionTest.java
  21. 6
    8
      sonar-server/src/test/java/org/sonar/server/rule/RuleRegistrationTest.java
  22. 1
    1
      sonar-server/src/test/java/org/sonar/server/startup/RegisterDebtModelTest.java
  23. 0
    0
      sonar-server/src/test/resources/org/sonar/server/debt/DebtCharacteristicsXMLImporterTest/import_badly_formatted_xml.xml
  24. 0
    0
      sonar-server/src/test/resources/org/sonar/server/debt/DebtCharacteristicsXMLImporterTest/import_characteristics.xml
  25. 50
    0
      sonar-server/src/test/resources/org/sonar/server/debt/DebtRulesXMLImporterTest/convert_constant_per_issue_with_factor_by_constant_by_issue_with_offset.xml
  26. 0
    0
      sonar-server/src/test/resources/org/sonar/server/debt/DebtRulesXMLImporterTest/convert_deprecated_linear_with_threshold_function_by_linear_function.xml
  27. 49
    0
      sonar-server/src/test/resources/org/sonar/server/debt/DebtRulesXMLImporterTest/fail_to_import_linear_having_offset.xml
  28. 0
    0
      sonar-server/src/test/resources/org/sonar/server/debt/DebtRulesXMLImporterTest/ignore_deprecated_constant_per_file_function.xml
  29. 0
    0
      sonar-server/src/test/resources/org/sonar/server/debt/DebtRulesXMLImporterTest/ignore_invalid_value.xml
  30. 0
    0
      sonar-server/src/test/resources/org/sonar/server/debt/DebtRulesXMLImporterTest/ignore_rule_on_root_characteristics.xml
  31. 0
    0
      sonar-server/src/test/resources/org/sonar/server/debt/DebtRulesXMLImporterTest/import_badly_formatted_xml.xml
  32. 0
    0
      sonar-server/src/test/resources/org/sonar/server/debt/DebtRulesXMLImporterTest/import_constant_issue.xml
  33. 0
    0
      sonar-server/src/test/resources/org/sonar/server/debt/DebtRulesXMLImporterTest/import_linear.xml
  34. 34
    0
      sonar-server/src/test/resources/org/sonar/server/debt/DebtRulesXMLImporterTest/import_linear_having_offset_to_zero.xml
  35. 0
    0
      sonar-server/src/test/resources/org/sonar/server/debt/DebtRulesXMLImporterTest/import_linear_with_offset.xml
  36. 1
    1
      sonar-server/src/test/resources/org/sonar/server/debt/DebtRulesXMLImporterTest/import_rules.xml
  37. 0
    0
      sonar-server/src/test/resources/org/sonar/server/debt/DebtRulesXMLImporterTest/replace_mn_by_min.xml
  38. 1
    1
      sonar-server/src/test/resources/org/sonar/server/debt/DebtRulesXMLImporterTest/use_default_unit_when_no_unit.xml
  39. 4
    5
      sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/set_no_characteristic_when_characteristic_not_found-result.xml
  40. 0
    0
      sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/set_no_characteristic_when_characteristic_not_found.xml

+ 140
- 0
sonar-plugin-api/src/main/java/org/sonar/api/server/rule/DebtRemediationFunction.java View File

@@ -0,0 +1,140 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* SonarQube is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

package org.sonar.api.server.rule;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;

import javax.annotation.CheckForNull;
import javax.annotation.Nullable;

/**
* @since 4.3
*/
public class DebtRemediationFunction {

public static enum Type {
LINEAR, LINEAR_OFFSET, CONSTANT_ISSUE
}

public static class ValidationException extends RuntimeException {

public ValidationException(String message) {
super(message);
}
}

private Type type;
private String factor;
private String offset;

private DebtRemediationFunction(Type type, @Nullable String factor, @Nullable String offset) {
this.type = type;
// TODO validate factor and offset format
this.factor = StringUtils.deleteWhitespace(factor);
this.offset = StringUtils.deleteWhitespace(offset);
switch (type) {
case LINEAR:
if (this.factor == null || this.offset != null) {
throw new ValidationException(String.format("%s is invalid, Linear remediation function should only define a factor", this));
}
break;
case LINEAR_OFFSET:
if (this.factor == null || this.offset == null) {
throw new ValidationException(String.format("%s is invalid, Linear with offset remediation function should define both factor and offset", this));
}
break;
case CONSTANT_ISSUE:
if (this.factor != null || this.offset == null) {
throw new ValidationException(String.format("%s is invalid, Constant/issue remediation function should only define an offset", this));
}
break;
}
}

public static DebtRemediationFunction create(Type type, @Nullable String factor, @Nullable String offset) {
return new DebtRemediationFunction(type, factor, offset);
}

public static DebtRemediationFunction createLinear(String factor) {
return new DebtRemediationFunction(Type.LINEAR, factor, null);
}

public static DebtRemediationFunction createLinearWithOffset(String factor, String offset) {
return new DebtRemediationFunction(Type.LINEAR_OFFSET, factor, offset);
}

public static DebtRemediationFunction createConstantPerIssue(String offset) {
return new DebtRemediationFunction(Type.CONSTANT_ISSUE, null, offset);
}

public Type type() {
return type;
}

@CheckForNull
public String factor() {
return factor;
}

@CheckForNull
public String offset() {
return offset;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}

DebtRemediationFunction that = (DebtRemediationFunction) o;

if (type != that.type) {
return false;
}
if (factor != null ? !factor.equals(that.factor) : that.factor != null) {
return false;
}
if (offset != null ? !offset.equals(that.offset) : that.offset != null) {
return false;
}

return true;
}

@Override
public int hashCode() {
int result = type.hashCode();
result = 31 * result + (factor != null ? factor.hashCode() : 0);
result = 31 * result + (offset != null ? offset.hashCode() : 0);
return result;
}

@Override
public String toString() {
return new ReflectionToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).toString();
}
}

+ 14
- 43
sonar-plugin-api/src/main/java/org/sonar/api/server/rule/RulesDefinition.java View File

@@ -24,7 +24,6 @@ import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.LoggerFactory;
import org.sonar.api.ServerExtension;
import org.sonar.api.rule.RemediationFunction;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.rule.Severity;

@@ -312,10 +311,8 @@ public interface RulesDefinition extends ServerExtension {
private String name, htmlDescription, internalKey, severity = Severity.MAJOR;
private boolean template;
private RuleStatus status = RuleStatus.defaultStatus();
private String characteristicKey;
private RemediationFunction remediationFunction;
private String remediationFactor;
private String remediationOffset;
private String debtCharacteristic;
private DebtRemediationFunction debtRemediationFunction;
private String effortToFixL10nKey;
private final Set<String> tags = Sets.newTreeSet();
private final Map<String, NewParam> paramsByKey = Maps.newHashMap();
@@ -376,25 +373,13 @@ public interface RulesDefinition extends ServerExtension {
return this;
}

public NewRule setCharacteristicKey(@Nullable String characteristicKey) {
this.characteristicKey = characteristicKey;
public NewRule setDebtCharacteristic(@Nullable String debtCharacteristic) {
this.debtCharacteristic = debtCharacteristic;
return this;
}

public NewRule setRemediationFunction(@Nullable RemediationFunction remediationFunction) {
this.remediationFunction = remediationFunction;
return this;
}

public NewRule setRemediationFactor(@Nullable String remediationFactor) {
// TODO validate format
this.remediationFactor = StringUtils.deleteWhitespace(remediationFactor);
return this;
}

public NewRule setRemediationOffset(@Nullable String remediationOffset) {
// TODO validate format
this.remediationOffset = StringUtils.deleteWhitespace(remediationOffset);
public NewRule setDebtRemediationFunction(@Nullable DebtRemediationFunction debtRemediationFunction) {
this.debtRemediationFunction = debtRemediationFunction;
return this;
}

@@ -467,10 +452,8 @@ public interface RulesDefinition extends ServerExtension {
private final Repository repository;
private final String repoKey, key, name, htmlDescription, internalKey, severity;
private final boolean template;
private final String characteristicKey;
private final RemediationFunction remediationFunction;
private final String remediationFactor;
private final String remediationOffset;
private final String debtCharacteristic;
private final DebtRemediationFunction debtRemediationFunction;
private final String effortToFixL10nKey;
private final Set<String> tags;
private final Map<String, Param> params;
@@ -486,10 +469,8 @@ public interface RulesDefinition extends ServerExtension {
this.severity = newRule.severity;
this.template = newRule.template;
this.status = newRule.status;
this.characteristicKey = newRule.characteristicKey;
this.remediationFunction = newRule.remediationFunction;
this.remediationFactor = newRule.remediationFactor;
this.remediationOffset = newRule.remediationOffset;
this.debtCharacteristic = newRule.debtCharacteristic;
this.debtRemediationFunction = newRule.debtRemediationFunction;
this.effortToFixL10nKey = newRule.effortToFixL10nKey;
this.tags = ImmutableSortedSet.copyOf(newRule.tags);
ImmutableMap.Builder<String, Param> paramsBuilder = ImmutableMap.builder();
@@ -529,23 +510,13 @@ public interface RulesDefinition extends ServerExtension {
}

@CheckForNull
public String characteristicKey() {
return characteristicKey;
}

@CheckForNull
public RemediationFunction remediationFunction() {
return remediationFunction;
}

@CheckForNull
public String remediationFactor() {
return remediationFactor;
public String debtCharacteristic() {
return debtCharacteristic;
}

@CheckForNull
public String remediationOffset() {
return remediationOffset;
public DebtRemediationFunction debtRemediationFunction() {
return debtRemediationFunction;
}

@CheckForNull

+ 146
- 0
sonar-plugin-api/src/test/java/org/sonar/api/server/rule/DebtRemediationFunctionTest.java View File

@@ -0,0 +1,146 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* SonarQube is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

package org.sonar.api.server.rule;

import org.junit.Test;

import static org.fest.assertions.Assertions.assertThat;
import static org.fest.assertions.Fail.fail;

public class DebtRemediationFunctionTest {

@Test
public void create_linear() throws Exception {
DebtRemediationFunction function = DebtRemediationFunction.createLinear("10h");
assertThat(function.type()).isEqualTo(DebtRemediationFunction.Type.LINEAR);
assertThat(function.factor()).isEqualTo("10h");
assertThat(function.offset()).isNull();
}

@Test
public void create_linear_with_offset() throws Exception {
DebtRemediationFunction function = DebtRemediationFunction.createLinearWithOffset("10h", "5min");
assertThat(function.type()).isEqualTo(DebtRemediationFunction.Type.LINEAR_OFFSET);
assertThat(function.factor()).isEqualTo("10h");
assertThat(function.offset()).isEqualTo("5min");
}

@Test
public void create_constant_per_issue() throws Exception {
DebtRemediationFunction function = DebtRemediationFunction.createConstantPerIssue("10h");
assertThat(function.type()).isEqualTo(DebtRemediationFunction.Type.CONSTANT_ISSUE);
assertThat(function.factor()).isNull();
assertThat(function.offset()).isEqualTo("10h");
}

@Test
public void sanitize_remediation_factor_and_offset() {
DebtRemediationFunction function = DebtRemediationFunction.create(DebtRemediationFunction.Type.LINEAR_OFFSET, " 1 h ", " 10 mi n");

assertThat(function.factor()).isEqualTo("1h");
assertThat(function.offset()).isEqualTo("10min");
}

@Test
public void fail_to_create_linear_when_no_factor() throws Exception {
try {
DebtRemediationFunction.create(DebtRemediationFunction.Type.LINEAR, null, "10h");
fail();
} catch(Exception e) {
assertThat(e).isInstanceOf(DebtRemediationFunction.ValidationException.class);
}
}

@Test
public void fail_to_create_linear_when_offset() throws Exception {
try {
DebtRemediationFunction.create(DebtRemediationFunction.Type.LINEAR, "5min", "10h");
fail();
} catch(Exception e) {
assertThat(e).isInstanceOf(DebtRemediationFunction.ValidationException.class);
}
}

@Test
public void fail_to_create_constant_per_issue_when_no_offset() throws Exception {
try {
DebtRemediationFunction.create(DebtRemediationFunction.Type.CONSTANT_ISSUE, "10h", null);
fail();
} catch(Exception e) {
assertThat(e).isInstanceOf(DebtRemediationFunction.ValidationException.class);
}
}

@Test
public void fail_to_create_constant_per_issue_when_factor() throws Exception {
try {
DebtRemediationFunction.create(DebtRemediationFunction.Type.CONSTANT_ISSUE, "5min", "10h");
fail();
} catch(Exception e) {
assertThat(e).isInstanceOf(DebtRemediationFunction.ValidationException.class);
}
}

@Test
public void fail_to_create_linear_with_offset_when_no_factor() throws Exception {
try {
DebtRemediationFunction.create(DebtRemediationFunction.Type.LINEAR_OFFSET, null, "10h");
fail();
} catch(Exception e) {
assertThat(e).isInstanceOf(DebtRemediationFunction.ValidationException.class);
}
}

@Test
public void fail_to_create_linear_with_offset_when_no_offset() throws Exception {
try {
DebtRemediationFunction.create(DebtRemediationFunction.Type.LINEAR_OFFSET, "5min", null);
fail();
} catch(Exception e) {
assertThat(e).isInstanceOf(DebtRemediationFunction.ValidationException.class);
}
}

@Test
public void test_equals_and_hashcode() throws Exception {
DebtRemediationFunction function = DebtRemediationFunction.createLinearWithOffset("10h", "5min");
DebtRemediationFunction functionWithSameValue = DebtRemediationFunction.createLinearWithOffset("10h", "5min");
DebtRemediationFunction functionWithDifferentType = DebtRemediationFunction.createConstantPerIssue("5min");

assertThat(function).isEqualTo(function);
assertThat(function).isEqualTo(functionWithSameValue);
assertThat(function).isNotEqualTo(functionWithDifferentType);
assertThat(function).isNotEqualTo(DebtRemediationFunction.createLinearWithOffset("11h", "5min"));
assertThat(function).isNotEqualTo(DebtRemediationFunction.createLinearWithOffset("10h", "6min"));
assertThat(function).isNotEqualTo(DebtRemediationFunction.createLinear("10h"));
assertThat(function).isNotEqualTo(DebtRemediationFunction.createConstantPerIssue("6min"));

assertThat(function.hashCode()).isEqualTo(function.hashCode());
assertThat(function.hashCode()).isEqualTo(functionWithSameValue.hashCode());
assertThat(function.hashCode()).isNotEqualTo(functionWithDifferentType.hashCode());
}

@Test
public void test_to_string() throws Exception {
assertThat(DebtRemediationFunction.createLinearWithOffset("10h", "5min").toString()).isNotNull();
}

}

+ 8
- 49
sonar-plugin-api/src/test/java/org/sonar/api/server/rule/RulesDefinitionTest.java View File

@@ -19,9 +19,7 @@
*/
package org.sonar.api.server.rule;

import org.junit.Ignore;
import org.junit.Test;
import org.sonar.api.rule.RemediationFunction;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.rule.Severity;

@@ -72,10 +70,8 @@ public class RulesDefinitionTest {
.setSeverity(Severity.BLOCKER)
.setInternalKey("/something")
.setStatus(RuleStatus.BETA)
.setCharacteristicKey("COMPILER")
.setRemediationFunction(RemediationFunction.LINEAR_OFFSET)
.setRemediationFactor("1h")
.setRemediationOffset("10min")
.setDebtCharacteristic("COMPILER")
.setDebtRemediationFunction(DebtRemediationFunction.create(DebtRemediationFunction.Type.LINEAR_OFFSET, "1h", "10min"))
.setEffortToFixL10nKey("squid.S115.effortToFix")
.setTags("one", "two")
.addTags("two", "three", "four");
@@ -95,10 +91,8 @@ public class RulesDefinitionTest {
assertThat(npeRule.internalKey()).isEqualTo("/something");
assertThat(npeRule.template()).isFalse();
assertThat(npeRule.status()).isEqualTo(RuleStatus.BETA);
assertThat(npeRule.characteristicKey()).isEqualTo("COMPILER");
assertThat(npeRule.remediationFunction()).isEqualTo(RemediationFunction.LINEAR_OFFSET);
assertThat(npeRule.remediationFactor()).isEqualTo("1h");
assertThat(npeRule.remediationOffset()).isEqualTo("10min");
assertThat(npeRule.debtCharacteristic()).isEqualTo("COMPILER");
assertThat(npeRule.debtRemediationFunction()).isEqualTo(DebtRemediationFunction.create(DebtRemediationFunction.Type.LINEAR_OFFSET, "1h", "10min"));
assertThat(npeRule.effortToFixL10nKey()).isEqualTo("squid.S115.effortToFix");
assertThat(npeRule.toString()).isEqualTo("[repository=findbugs, key=NPE]");
assertThat(npeRule.repository()).isSameAs(findbugs);
@@ -122,10 +116,8 @@ public class RulesDefinitionTest {
assertThat(rule.internalKey()).isNull();
assertThat(rule.status()).isEqualTo(RuleStatus.defaultStatus());
assertThat(rule.tags()).isEmpty();
assertThat(rule.characteristicKey()).isNull();
assertThat(rule.remediationFunction()).isNull();
assertThat(rule.remediationFactor()).isNull();
assertThat(rule.remediationOffset()).isNull();
assertThat(rule.debtCharacteristic()).isNull();
assertThat(rule.debtRemediationFunction()).isNull();
}

@Test
@@ -167,21 +159,6 @@ public class RulesDefinitionTest {
assertThat(rule.name()).isEqualTo("NullPointer");
}

@Test
public void sanitize_remediation_factor_and_offset() {
RulesDefinition.NewRepository newFindbugs = context.createRepository("findbugs", "java");
newFindbugs.createRule("NPE")
.setName("Detect NPE")
.setHtmlDescription("NPE")
.setRemediationFactor(" 1 h ")
.setRemediationOffset(" 10 mi n ");
newFindbugs.done();

RulesDefinition.Rule npeRule = context.repository("findbugs").rule("NPE");
assertThat(npeRule.remediationFactor()).isEqualTo("1h");
assertThat(npeRule.remediationOffset()).isEqualTo("10min");
}

@Test
public void extend_repository() {
assertThat(context.extendedRepositories()).isEmpty();
@@ -276,7 +253,7 @@ public class RulesDefinitionTest {
@Test
public void fail_to_load_rule_description_from_file() {
RulesDefinition.NewRepository newRepository = context.createRepository("findbugs", "java");
newRepository.createRule("NPE").setName("NPE").setHtmlDescription((URL)null);
newRepository.createRule("NPE").setName("NPE").setHtmlDescription((URL) null);
try {
newRepository.done();
fail();
@@ -288,7 +265,7 @@ public class RulesDefinitionTest {
@Test
public void fail_if_blank_rule_html_description() {
RulesDefinition.NewRepository newRepository = context.createRepository("findbugs", "java");
newRepository.createRule("NPE").setName("NPE").setHtmlDescription((String)null);
newRepository.createRule("NPE").setName("NPE").setHtmlDescription((String) null);
try {
newRepository.done();
fail();
@@ -317,22 +294,4 @@ public class RulesDefinitionTest {
}
}

@Test
@Ignore("TODO")
public void fail_if_bad_remediation_factor_or_offset() {
try {
context.createRepository("findbugs", "java").createRule("NPE").setRemediationFactor("ten hours");
fail();
} catch (IllegalArgumentException e) {
assertThat(e).hasMessage("Duration 'ten hours' is invalid, it should use the following sample format : 2d 10h 15min");
}

try {
context.createRepository("findbugs", "java").createRule("NPE").setRemediationOffset("ten hours");
fail();
} catch (IllegalArgumentException e) {
assertThat(e).hasMessage("Duration 'ten hours' is invalid, it should use the following sample format : 2d 10h 15min");
}
}

}

sonar-core/src/main/java/org/sonar/core/technicaldebt/DebtCharacteristicsXMLImporter.java → sonar-server/src/main/java/org/sonar/server/debt/DebtCharacteristicsXMLImporter.java View File

@@ -18,7 +18,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

package org.sonar.core.technicaldebt;
package org.sonar.server.debt;

import org.apache.commons.lang.StringUtils;
import org.codehaus.stax2.XMLInputFactory2;
@@ -30,6 +30,7 @@ import org.slf4j.LoggerFactory;
import org.sonar.api.ServerExtension;
import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
import org.sonar.api.utils.ValidationMessages;
import org.sonar.core.technicaldebt.DefaultTechnicalDebtModel;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
@@ -98,7 +99,6 @@ public class DebtCharacteristicsXMLImporter implements ServerExtension {
// <chc> can contain characteristics or requirements
} else if (StringUtils.equals(node, CHARACTERISTIC)) {
processCharacteristic(model, characteristic, cursor, messages);

}
}


sonar-core/src/main/java/org/sonar/core/technicaldebt/DebtModelSynchronizer.java → sonar-server/src/main/java/org/sonar/server/debt/DebtModelSynchronizer.java View File

@@ -18,7 +18,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

package org.sonar.core.technicaldebt;
package org.sonar.server.debt;

import org.apache.commons.io.IOUtils;
import org.apache.ibatis.session.SqlSession;
@@ -28,6 +28,8 @@ import org.sonar.api.ServerExtension;
import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
import org.sonar.api.utils.ValidationMessages;
import org.sonar.core.persistence.MyBatis;
import org.sonar.core.technicaldebt.DefaultTechnicalDebtModel;
import org.sonar.core.technicaldebt.TechnicalDebtModelRepository;
import org.sonar.core.technicaldebt.db.CharacteristicDao;
import org.sonar.core.technicaldebt.db.CharacteristicDto;


sonar-core/src/main/java/org/sonar/core/technicaldebt/DebtRulesXMLImporter.java → sonar-server/src/main/java/org/sonar/server/debt/DebtRulesXMLImporter.java View File

@@ -18,7 +18,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

package org.sonar.core.technicaldebt;
package org.sonar.server.debt;

import com.google.common.base.Predicate;
import com.google.common.base.Strings;
@@ -32,9 +32,10 @@ import org.codehaus.staxmate.in.SMInputCursor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.ServerExtension;
import org.sonar.api.rule.RemediationFunction;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.server.rule.DebtRemediationFunction;
import org.sonar.api.utils.Duration;
import org.sonar.api.utils.MessageException;

import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
@@ -123,10 +124,9 @@ public class DebtRulesXMLImporter implements ServerExtension {
}
}

private RuleDebt processRule(SMInputCursor cursor)
throws XMLStreamException {
@CheckForNull
private RuleDebt processRule(SMInputCursor cursor) throws XMLStreamException {

RuleDebt ruleDebt = new RuleDebt();
String ruleRepositoryKey = cursor.collectDescendantText().trim();
String ruleKey = null;
Properties properties = new Properties();
@@ -139,11 +139,9 @@ public class DebtRulesXMLImporter implements ServerExtension {
}
}
if (StringUtils.isNotBlank(ruleRepositoryKey) && StringUtils.isNotBlank(ruleKey)) {
ruleDebt.ruleKey = RuleKey.of(ruleRepositoryKey, ruleKey);
} else {
return null;
return processRule(RuleKey.of(ruleRepositoryKey, ruleKey), properties);
}
return processFunctionsOnRequirement(ruleDebt, properties);
return null;
}

private Property processProperty(SMInputCursor cursor) throws XMLStreamException {
@@ -166,43 +164,42 @@ public class DebtRulesXMLImporter implements ServerExtension {
}
} else if (StringUtils.equals(node, PROPERTY_TEXT_VALUE)) {
textValue = c.collectDescendantText().trim();
textValue = "mn".equals(textValue) ? Duration.MINUTE : textValue;
}
}
return new Property(key, value, textValue);
}

@CheckForNull
private RuleDebt processFunctionsOnRequirement(RuleDebt requirement, Properties properties) {
Property function = properties.function();
Property factor = properties.factor();
Property offset = properties.offset();
private RuleDebt processRule(RuleKey ruleKey, Properties properties){
try {
return createRule(ruleKey, properties);
} catch (DebtRemediationFunction.ValidationException e) {
throw MessageException.of(String.format("Rule '%s' is invalid : %s", ruleKey, e.getMessage()));
}
}

@CheckForNull
private RuleDebt createRule(RuleKey ruleKey, Properties properties) {
Property function = properties.function();
if (function != null) {
// Init with default values
requirement.factor = "0" + Duration.DAY;
requirement.offset = "0" + Duration.DAY;

Property factorProperty = properties.factor();
String factor = factorProperty != null ? factorProperty.toDuration() : null;
Property offsetProperty = properties.offset();
String offset = offsetProperty != null ? offsetProperty.toDuration() : null;

String functionKey = function.getTextValue();
if ("linear_threshold".equals(functionKey)) {
function.setTextValue(RemediationFunction.LINEAR.name().toLowerCase());
offset.setValue(0);
offset.setTextValue(Duration.DAY);
LOG.warn(String.format("Linear with threshold function is no longer used, remediation function of '%s' is replaced by linear.", requirement.ruleKey));
if ("linear_threshold".equals(functionKey) && 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).setFunction(DebtRemediationFunction.createLinear(factor));
} else if ("constant_resource".equals(functionKey)) {
LOG.warn(String.format("Constant/file function is no longer used, technical debt definitions on '%s' are ignored.", requirement.ruleKey));
return null;
}

requirement.function = RemediationFunction.valueOf(function.getTextValue().toUpperCase());
if (factor != null) {
requirement.factor = Integer.toString(factor.getValue());
requirement.factor += !Strings.isNullOrEmpty(factor.getTextValue()) ? factor.getTextValue() : Duration.DAY;
LOG.warn(String.format("Constant/file function is no longer used, technical debt definitions on '%s' are ignored.", ruleKey));
} else if (DebtRemediationFunction.Type.CONSTANT_ISSUE.name().toLowerCase().equals(functionKey) && factor != null && offset == null) {
return new RuleDebt().setRuleKey(ruleKey).setFunction(DebtRemediationFunction.createConstantPerIssue(factor));
} else {
return new RuleDebt().setRuleKey(ruleKey).setFunction(DebtRemediationFunction.create(DebtRemediationFunction.Type.valueOf(functionKey.toUpperCase()), factor, offset));
}
if (offset != null) {
requirement.offset = Integer.toString(offset.getValue());
requirement.offset += !Strings.isNullOrEmpty(offset.getTextValue()) ? offset.getTextValue() : Duration.DAY;
}
return requirement;
}
return null;
}
@@ -252,16 +249,6 @@ public class DebtRulesXMLImporter implements ServerExtension {
this.textValue = textValue;
}

private Property setValue(int value) {
this.value = value;
return this;
}

private Property setTextValue(String textValue) {
this.textValue = textValue;
return this;
}

private String getKey() {
return key;
}
@@ -271,16 +258,24 @@ public class DebtRulesXMLImporter implements ServerExtension {
}

private String getTextValue() {
return "mn".equals(textValue) ? Duration.MINUTE : textValue;
return textValue;
}

@CheckForNull
public String toDuration() {
if (key != null && getValue() > 0) {
String duration = Integer.toString(getValue());
duration += !Strings.isNullOrEmpty(getTextValue()) ? getTextValue() : Duration.DAY;
return duration;
}
return null;
}
}

public static class RuleDebt {
private RuleKey ruleKey;
private String characteristicKey;
private RemediationFunction function;
private String factor;
private String offset;
private DebtRemediationFunction function;

public RuleKey ruleKey() {
return ruleKey;
@@ -300,32 +295,14 @@ public class DebtRulesXMLImporter implements ServerExtension {
return this;
}

public RemediationFunction function() {
public DebtRemediationFunction function() {
return function;
}

public RuleDebt setFunction(RemediationFunction function) {
public RuleDebt setFunction(DebtRemediationFunction function) {
this.function = function;
return this;
}

public String factor() {
return factor;
}

public RuleDebt setFactor(String factor) {
this.factor = factor;
return this;
}

public String offset() {
return offset;
}

public RuleDebt setOffset(String offset) {
this.offset = offset;
return this;
}
}

}

sonar-server/src/main/java/org/sonar/server/technicaldebt/DebtService.java → sonar-server/src/main/java/org/sonar/server/debt/DebtService.java View File

@@ -18,7 +18,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

package org.sonar.server.technicaldebt;
package org.sonar.server.debt;

import org.sonar.api.ServerComponent;
import org.sonar.api.technicaldebt.server.Characteristic;

sonar-server/src/main/java/org/sonar/server/technicaldebt/package-info.java → sonar-server/src/main/java/org/sonar/server/debt/package-info.java View File

@@ -18,6 +18,6 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
@ParametersAreNonnullByDefault
package org.sonar.server.technicaldebt;
package org.sonar.server.debt;

import javax.annotation.ParametersAreNonnullByDefault;

+ 8
- 2
sonar-server/src/main/java/org/sonar/server/platform/Platform.java View File

@@ -63,7 +63,10 @@ import org.sonar.core.qualitygate.db.QualityGateConditionDao;
import org.sonar.core.qualitygate.db.QualityGateDao;
import org.sonar.core.resource.DefaultResourcePermissions;
import org.sonar.core.rule.DefaultRuleFinder;
import org.sonar.core.technicaldebt.*;
import org.sonar.core.technicaldebt.DefaultTechnicalDebtManager;
import org.sonar.core.technicaldebt.TechnicalDebtModelRepository;
import org.sonar.core.technicaldebt.TechnicalDebtModelSynchronizer;
import org.sonar.core.technicaldebt.TechnicalDebtXMLImporter;
import org.sonar.core.test.TestPlanPerspectiveLoader;
import org.sonar.core.test.TestablePerspectiveLoader;
import org.sonar.core.timemachine.Periods;
@@ -83,6 +86,10 @@ import org.sonar.server.db.EmbeddedDatabaseFactory;
import org.sonar.server.db.migrations.DatabaseMigration;
import org.sonar.server.db.migrations.DatabaseMigrations;
import org.sonar.server.db.migrations.DatabaseMigrator;
import org.sonar.server.debt.DebtCharacteristicsXMLImporter;
import org.sonar.server.debt.DebtModelSynchronizer;
import org.sonar.server.debt.DebtRulesXMLImporter;
import org.sonar.server.debt.DebtService;
import org.sonar.server.es.ESIndex;
import org.sonar.server.es.ESNode;
import org.sonar.server.issue.*;
@@ -110,7 +117,6 @@ import org.sonar.server.source.SourceService;
import org.sonar.server.source.ws.SourcesShowWsHandler;
import org.sonar.server.source.ws.SourcesWs;
import org.sonar.server.startup.*;
import org.sonar.server.technicaldebt.DebtService;
import org.sonar.server.text.MacroInterpreter;
import org.sonar.server.text.RubyTextService;
import org.sonar.server.ui.JRubyI18n;

+ 3
- 5
sonar-server/src/main/java/org/sonar/server/rule/DeprecatedRulesDefinition.java View File

@@ -31,8 +31,8 @@ import org.sonar.api.server.rule.RuleParamType;
import org.sonar.api.server.rule.RulesDefinition;
import org.sonar.check.Cardinality;
import org.sonar.core.i18n.RuleI18nManager;
import org.sonar.core.technicaldebt.DebtRulesXMLImporter;
import org.sonar.core.technicaldebt.TechnicalDebtModelRepository;
import org.sonar.server.debt.DebtRulesXMLImporter;

import javax.annotation.CheckForNull;

@@ -104,10 +104,8 @@ public class DeprecatedRulesDefinition implements RulesDefinition {
private void updateRuleDebtDefinitions(NewRule newRule, String repoKey, String ruleKey, List<DebtRulesXMLImporter.RuleDebt> ruleDebts){
DebtRulesXMLImporter.RuleDebt ruleDebt = findRequirement(ruleDebts, repoKey, ruleKey);
if (ruleDebt != null) {
newRule.setCharacteristicKey(ruleDebt.characteristicKey());
newRule.setRemediationFunction(ruleDebt.function());
newRule.setRemediationFactor(ruleDebt.factor());
newRule.setRemediationOffset(ruleDebt.offset());
newRule.setDebtCharacteristic(ruleDebt.characteristicKey());
newRule.setDebtRemediationFunction(ruleDebt.function());
}
}


+ 16
- 16
sonar-server/src/main/java/org/sonar/server/rule/RuleRegistration.java View File

@@ -28,9 +28,9 @@ import org.apache.ibatis.session.SqlSession;
import org.picocontainer.Startable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.rule.RemediationFunction;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rules.Rule;
import org.sonar.api.server.rule.DebtRemediationFunction;
import org.sonar.api.server.rule.RulesDefinition;
import org.sonar.api.utils.MessageException;
import org.sonar.api.utils.System2;
@@ -165,8 +165,6 @@ public class RuleRegistration implements Startable {
}

private RuleDto enableAndInsert(Buffer buffer, SqlSession sqlSession, RulesDefinition.Rule ruleDef, List<CharacteristicDto> characteristicDtos) {
RemediationFunction remediationFunction = ruleDef.remediationFunction();

RuleDto ruleDto = new RuleDto()
.setCardinality(ruleDef.template() ? Cardinality.MULTIPLE : Cardinality.SINGLE)
.setConfigKey(ruleDef.internalKey())
@@ -181,12 +179,14 @@ public class RuleRegistration implements Startable {
.setStatus(ruleDef.status().name());

CharacteristicDto characteristic = findCharacteristic(characteristicDtos, ruleDef);
if (characteristic != null) {
ruleDto.setDefaultCharacteristicId(characteristic.getId())
.setDefaultRemediationFunction(remediationFunction != null ? remediationFunction.name() : null)
.setDefaultRemediationFactor(ruleDef.remediationFactor())
.setDefaultRemediationOffset(ruleDef.remediationOffset())
.setEffortToFixL10nKey(ruleDef.effortToFixL10nKey());
ruleDto.setDefaultCharacteristicId(characteristic != null ? characteristic.getId() : null)
.setEffortToFixL10nKey(ruleDef.effortToFixL10nKey());

DebtRemediationFunction remediationFunction = ruleDef.debtRemediationFunction();
if (remediationFunction != null) {
ruleDto.setDefaultRemediationFunction(remediationFunction.type().name());
ruleDto.setDefaultRemediationFactor(remediationFunction.factor());
ruleDto.setDefaultRemediationOffset(remediationFunction.offset());
}

ruleDao.insert(ruleDto, sqlSession);
@@ -261,16 +261,16 @@ public class RuleRegistration implements Startable {
CharacteristicDto characteristic = findCharacteristic(characteristicDtos, def);
// Debt definitions are set to null if the characteristic is null or unknown
Integer characteristicId = characteristic != null ? characteristic.getId() : null;
RemediationFunction remediationFunction = characteristic != null ? def.remediationFunction() : null;
String remediationFactor = characteristic != null ? def.remediationFactor() : null;
String remediationOffset = characteristic != null ? def.remediationOffset() : null;
String effortToFixL10nKey = characteristic != null ? def.effortToFixL10nKey() : null;
DebtRemediationFunction debtRemediationFunction = def.debtRemediationFunction();
String remediationFactor = debtRemediationFunction != null ? debtRemediationFunction.factor() : null;
String remediationOffset = debtRemediationFunction != null ? debtRemediationFunction.offset() : null;
String effortToFixL10nKey = def.effortToFixL10nKey();

if (!ObjectUtils.equals(dto.getDefaultCharacteristicId(), characteristicId)) {
dto.setDefaultCharacteristicId(characteristicId);
changed = true;
}
String remediationFunctionString = remediationFunction != null ? remediationFunction.name() : null;
String remediationFunctionString = debtRemediationFunction != null ? debtRemediationFunction.type().name() : null;
if (!StringUtils.equals(dto.getDefaultRemediationFunction(), remediationFunctionString)) {
dto.setDefaultRemediationFunction(remediationFunctionString);
changed = true;
@@ -539,7 +539,7 @@ public class RuleRegistration implements Startable {

@CheckForNull
private CharacteristicDto findCharacteristic(List<CharacteristicDto> characteristicDtos, RulesDefinition.Rule ruleDef) {
final String key = ruleDef.characteristicKey();
final String key = ruleDef.debtCharacteristic();
if (key == null) {
// Rule is not linked to a characteristic, nothing to do
return null;
@@ -553,7 +553,7 @@ public class RuleRegistration implements Startable {
}, null);

if (characteristicDto == null) {
LOG.warn(String.format("Characteristic '%s' has not been found, technical debt definitions on rule '%s:%s' will be ignored",
LOG.warn(String.format("Characteristic '%s' has not been found on rule '%s:%s'",
key, ruleDef.repository().name(), ruleDef.key()));
} else if (characteristicDto.getParentId() == null) {
throw MessageException.of(String.format("Rule '%s:%s' cannot be linked on the root characteristic '%s'",

+ 2
- 0
sonar-server/src/main/java/org/sonar/server/startup/CopyRequirementsFromCharacteristicsToRules.java View File

@@ -49,6 +49,8 @@ import java.util.Collection;
import java.util.List;

/**
* This script copy every requirements from characteristics table (every row where rule_id is not null) to the rules table.
*
* This script need to be executed after rules registration because default debt columns (characteristics, function, factor and offset) has to be populated
* in order to be able to compare default values with overridden values.
*

+ 1
- 1
sonar-server/src/main/java/org/sonar/server/startup/RegisterDebtModel.java View File

@@ -24,7 +24,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.utils.TimeProfiler;
import org.sonar.api.utils.ValidationMessages;
import org.sonar.core.technicaldebt.DebtModelSynchronizer;
import org.sonar.server.debt.DebtModelSynchronizer;

public class RegisterDebtModel {


+ 1
- 1
sonar-server/src/main/webapp/WEB-INF/app/models/internal.rb View File

@@ -55,7 +55,7 @@ class Internal
end

def self.debt
component(Java::OrgSonarServerTechnicaldebt::DebtService.java_class)
component(Java::OrgSonarServerDebt::DebtService.java_class)
end

def self.profiling

sonar-core/src/test/java/org/sonar/core/technicaldebt/DebtCharacteristicsXMLImporterTest.java → sonar-server/src/test/java/org/sonar/server/debt/DebtCharacteristicsXMLImporterTest.java View File

@@ -18,13 +18,14 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

package org.sonar.core.technicaldebt;
package org.sonar.server.debt;

import com.google.common.base.Charsets;
import com.google.common.io.Resources;
import org.junit.Test;
import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
import org.sonar.api.utils.ValidationMessages;
import org.sonar.core.technicaldebt.DefaultTechnicalDebtModel;

import java.io.IOException;


sonar-core/src/test/java/org/sonar/core/technicaldebt/DebtModelSynchronizerTest.java → sonar-server/src/test/java/org/sonar/server/debt/DebtModelSynchronizerTest.java View File

@@ -18,7 +18,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

package org.sonar.core.technicaldebt;
package org.sonar.server.debt;

import com.google.common.collect.Lists;
import org.apache.ibatis.session.SqlSession;
@@ -33,6 +33,8 @@ import org.mockito.stubbing.Answer;
import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
import org.sonar.api.utils.ValidationMessages;
import org.sonar.core.persistence.MyBatis;
import org.sonar.core.technicaldebt.DefaultTechnicalDebtModel;
import org.sonar.core.technicaldebt.TechnicalDebtModelRepository;
import org.sonar.core.technicaldebt.db.CharacteristicDao;
import org.sonar.core.technicaldebt.db.CharacteristicDto;


sonar-core/src/test/java/org/sonar/core/technicaldebt/DebtRulesXMLImporterTest.java → sonar-server/src/test/java/org/sonar/server/debt/DebtRulesXMLImporterTest.java View File

@@ -18,18 +18,20 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

package org.sonar.core.technicaldebt;
package org.sonar.server.debt;

import com.google.common.base.Charsets;
import com.google.common.io.Resources;
import org.junit.Test;
import org.sonar.api.rule.RemediationFunction;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.server.rule.DebtRemediationFunction;
import org.sonar.api.utils.MessageException;

import java.io.IOException;
import java.util.List;

import static org.fest.assertions.Assertions.assertThat;
import static org.fest.assertions.Fail.fail;

public class DebtRulesXMLImporterTest {

@@ -53,9 +55,20 @@ public class DebtRulesXMLImporterTest {
DebtRulesXMLImporter.RuleDebt ruleDebt = results.get(0);
assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
assertThat(ruleDebt.ruleKey()).isEqualTo(RuleKey.of("checkstyle", "Regexp"));
assertThat(ruleDebt.function()).isEqualTo(RemediationFunction.LINEAR);
assertThat(ruleDebt.factor()).isEqualTo("3h");
assertThat(ruleDebt.offset()).isEqualTo("0d");
assertThat(ruleDebt.function()).isEqualTo(DebtRemediationFunction.createLinear("3h"));
}

@Test
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);
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.function()).isEqualTo(DebtRemediationFunction.createLinear("3h"));
}

@Test
@@ -67,9 +80,7 @@ public class DebtRulesXMLImporterTest {

DebtRulesXMLImporter.RuleDebt ruleDebt = results.get(0);
assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
assertThat(ruleDebt.function()).isEqualTo(RemediationFunction.LINEAR_OFFSET);
assertThat(ruleDebt.factor()).isEqualTo("3h");
assertThat(ruleDebt.offset()).isEqualTo("1min");
assertThat(ruleDebt.function()).isEqualTo(DebtRemediationFunction.createLinearWithOffset("3h", "1min"));
}

@Test
@@ -81,9 +92,7 @@ public class DebtRulesXMLImporterTest {

DebtRulesXMLImporter.RuleDebt ruleDebt = results.get(0);
assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
assertThat(ruleDebt.function()).isEqualTo(RemediationFunction.CONSTANT_ISSUE);
assertThat(ruleDebt.factor()).isEqualTo("0d");
assertThat(ruleDebt.offset()).isEqualTo("3d");
assertThat(ruleDebt.function()).isEqualTo(DebtRemediationFunction.createConstantPerIssue("3d"));
}

@Test
@@ -95,9 +104,7 @@ public class DebtRulesXMLImporterTest {

DebtRulesXMLImporter.RuleDebt ruleDebt = results.get(0);
assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
assertThat(ruleDebt.function()).isEqualTo(RemediationFunction.LINEAR);
assertThat(ruleDebt.factor()).isEqualTo("3d");
assertThat(ruleDebt.offset()).isEqualTo("1d");
assertThat(ruleDebt.function()).isEqualTo(DebtRemediationFunction.createLinearWithOffset("3d", "1d"));
}

@Test
@@ -109,9 +116,7 @@ public class DebtRulesXMLImporterTest {

DebtRulesXMLImporter.RuleDebt ruleDebt = results.get(0);
assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
assertThat(ruleDebt.function()).isEqualTo(RemediationFunction.LINEAR);
assertThat(ruleDebt.factor()).isEqualTo("3min");
assertThat(ruleDebt.offset()).isEqualTo("0d");
assertThat(ruleDebt.function()).isEqualTo(DebtRemediationFunction.createLinear("3min"));
}

@Test
@@ -123,9 +128,19 @@ public class DebtRulesXMLImporterTest {

DebtRulesXMLImporter.RuleDebt ruleDebt = results.get(0);
assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
assertThat(ruleDebt.function()).isEqualTo(RemediationFunction.LINEAR);
assertThat(ruleDebt.factor()).isEqualTo("3h");
assertThat(ruleDebt.offset()).isEqualTo("0d");
assertThat(ruleDebt.function()).isEqualTo(DebtRemediationFunction.createLinear("3h"));
}

@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);
assertThat(results).hasSize(1);

DebtRulesXMLImporter.RuleDebt ruleDebt = results.get(0);
assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
assertThat(ruleDebt.function()).isEqualTo(DebtRemediationFunction.createConstantPerIssue("3h"));
}

@Test
@@ -154,9 +169,7 @@ public class DebtRulesXMLImporterTest {
DebtRulesXMLImporter.RuleDebt ruleDebt = results.get(0);
assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
assertThat(ruleDebt.ruleKey()).isEqualTo(RuleKey.of("checkstyle", "Regexp"));
assertThat(ruleDebt.function()).isEqualTo(RemediationFunction.LINEAR);
assertThat(ruleDebt.factor()).isEqualTo("3h");
assertThat(ruleDebt.offset()).isEqualTo("0d");
assertThat(ruleDebt.function()).isEqualTo(DebtRemediationFunction.createLinear("3h"));
}

@Test
@@ -166,6 +179,17 @@ public class DebtRulesXMLImporterTest {
assertThat(results).isEmpty();
}

@Test
public void fail_to_import_linear_having_offset() throws Exception {
String xml = getFileContent("fail_to_import_linear_having_offset.xml");
try {
importer.importXML(xml);
fail();
} catch (Exception e) {
assertThat(e).isInstanceOf(MessageException.class);
}
}

private String getFileContent(String file) {
try {
return Resources.toString(Resources.getResource(DebtRulesXMLImporterTest.class, "DebtRulesXMLImporterTest/" + file), Charsets.UTF_8);

sonar-server/src/test/java/org/sonar/server/technicaldebt/DebtServiceTest.java → sonar-server/src/test/java/org/sonar/server/debt/DebtServiceTest.java View File

@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.technicaldebt;
package org.sonar.server.debt;

import org.junit.Before;
import org.junit.Test;

+ 6
- 10
sonar-server/src/test/java/org/sonar/server/rule/DeprecatedRulesDefinitionTest.java View File

@@ -23,17 +23,17 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.sonar.api.rule.RemediationFunction;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.rule.Severity;
import org.sonar.api.rules.Rule;
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.core.i18n.RuleI18nManager;
import org.sonar.core.technicaldebt.DebtRulesXMLImporter;
import org.sonar.core.technicaldebt.TechnicalDebtModelRepository;
import org.sonar.server.debt.DebtRulesXMLImporter;

import java.io.Reader;
import java.util.Arrays;
@@ -158,10 +158,8 @@ public class DeprecatedRulesDefinitionTest {
new DebtRulesXMLImporter.RuleDebt()
.setCharacteristicKey("MEMORY_EFFICIENCY")
.setRuleKey(RuleKey.of("checkstyle", "ConstantName"))
.setFunction(RemediationFunction.LINEAR_OFFSET)
.setFactor("1d")
.setOffset("10min")
);
.setFunction(DebtRemediationFunction.createLinearWithOffset("1d", "10min")
));

Reader javaModelReader = mock(Reader.class);
when(debtModelRepository.createReaderForXMLFile("java")).thenReturn(javaModelReader);
@@ -177,10 +175,8 @@ public class DeprecatedRulesDefinitionTest {
RulesDefinition.Rule rule = checkstyle.rule("ConstantName");
assertThat(rule).isNotNull();
assertThat(rule.key()).isEqualTo("ConstantName");
assertThat(rule.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
assertThat(rule.remediationFunction()).isEqualTo(RemediationFunction.LINEAR_OFFSET);
assertThat(rule.remediationFactor()).isEqualTo("1d");
assertThat(rule.remediationOffset()).isEqualTo("10min");
assertThat(rule.debtCharacteristic()).isEqualTo("MEMORY_EFFICIENCY");
assertThat(rule.debtRemediationFunction()).isEqualTo(DebtRemediationFunction.createLinearWithOffset("1d", "10min"));
}

}

+ 6
- 8
sonar-server/src/test/java/org/sonar/server/rule/RuleRegistrationTest.java View File

@@ -22,9 +22,9 @@ package org.sonar.server.rule;

import org.junit.Before;
import org.junit.Test;
import org.sonar.api.rule.RemediationFunction;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.rule.Severity;
import org.sonar.api.server.rule.DebtRemediationFunction;
import org.sonar.api.server.rule.RulesDefinition;
import org.sonar.api.utils.MessageException;
import org.sonar.core.persistence.AbstractDaoTestCase;
@@ -168,11 +168,11 @@ public class RuleRegistrationTest extends AbstractDaoTestCase {
}

@Test
public void remove_rule_debt_definitions_if_characteristic_not_found() {
setupData("remove_rule_debt_definitions_if_characteristic_not_found");
public void set_no_characteristic_when_characteristic_not_found() {
setupData("set_no_characteristic_when_characteristic_not_found");
task.start();

checkTables("remove_rule_debt_definitions_if_characteristic_not_found", EXCLUDED_COLUMN_NAMES, "rules");
checkTables("set_no_characteristic_when_characteristic_not_found", EXCLUDED_COLUMN_NAMES, "rules");
}

@Test
@@ -247,10 +247,8 @@ public class RuleRegistrationTest extends AbstractDaoTestCase {
.setName("One")
.setHtmlDescription("Description of One")
.setSeverity(Severity.BLOCKER)
.setCharacteristicKey("MEMORY_EFFICIENCY")
.setRemediationFunction(RemediationFunction.LINEAR_OFFSET)
.setRemediationFactor("5d")
.setRemediationOffset("10h")
.setDebtCharacteristic("MEMORY_EFFICIENCY")
.setDebtRemediationFunction(DebtRemediationFunction.createLinearWithOffset("5d", "10h"))
.setEffortToFixL10nKey("squid.S115.effortToFix")
.setInternalKey("config1")
.setTags("tag1", "tag3", "tag5");

+ 1
- 1
sonar-server/src/test/java/org/sonar/server/startup/RegisterDebtModelTest.java View File

@@ -22,7 +22,7 @@ package org.sonar.server.startup;

import org.junit.Test;
import org.sonar.api.utils.ValidationMessages;
import org.sonar.core.technicaldebt.DebtModelSynchronizer;
import org.sonar.server.debt.DebtModelSynchronizer;

import static org.mockito.Matchers.any;
import static org.mockito.Mockito.*;

sonar-core/src/test/resources/org/sonar/core/technicaldebt/DebtCharacteristicsXMLImporterTest/import_badly_formatted_xml.xml → sonar-server/src/test/resources/org/sonar/server/debt/DebtCharacteristicsXMLImporterTest/import_badly_formatted_xml.xml View File


sonar-core/src/test/resources/org/sonar/core/technicaldebt/DebtCharacteristicsXMLImporterTest/import_characteristics.xml → sonar-server/src/test/resources/org/sonar/server/debt/DebtCharacteristicsXMLImporterTest/import_characteristics.xml View File


+ 50
- 0
sonar-server/src/test/resources/org/sonar/server/debt/DebtRulesXMLImporterTest/convert_constant_per_issue_with_factor_by_constant_by_issue_with_offset.xml View File

@@ -0,0 +1,50 @@
<!--
~ SonarQube, open source software quality management tool.
~ Copyright (C) 2008-2014 SonarSource
~ mailto:contact AT sonarsource DOT com
~
~ SonarQube is free software; you can redistribute it and/or
~ modify it under the terms of the GNU Lesser General Public
~ License as published by the Free Software Foundation; either
~ version 3 of the License, or (at your option) any later version.
~
~ SonarQube is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
~ Lesser General Public License for more details.
~
~ You should have received a copy of the GNU Lesser General Public License
~ along with this program; if not, write to the Free Software Foundation,
~ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-->

<sqale>
<chc>
<key>USABILITY</key>
<name>Usability</name>
<desc>Estimate usability</desc>
</chc>
<chc>
<key>EFFICIENCY</key>
<name>Efficiency</name>
<chc>
<key>MEMORY_EFFICIENCY</key>
<name>Memory use</name>
<chc>
<rule-repo>checkstyle</rule-repo>
<rule-key>Regexp</rule-key>
<prop>
<key>remediationFunction</key>
<txt>constant_issue</txt>
</prop>
<prop>
<!-- Should be replaced by offset -->
<key>remediationFactor</key>
<val>3.0</val>
<txt>h</txt>
</prop>
</chc>
</chc>
</chc>

</sqale>

sonar-core/src/test/resources/org/sonar/core/technicaldebt/DebtRulesXMLImporterTest/convert_deprecated_linear_with_threshold_function_by_linear_function.xml → sonar-server/src/test/resources/org/sonar/server/debt/DebtRulesXMLImporterTest/convert_deprecated_linear_with_threshold_function_by_linear_function.xml View File


+ 49
- 0
sonar-server/src/test/resources/org/sonar/server/debt/DebtRulesXMLImporterTest/fail_to_import_linear_having_offset.xml View File

@@ -0,0 +1,49 @@
<!--
~ SonarQube, open source software quality management tool.
~ Copyright (C) 2008-2014 SonarSource
~ mailto:contact AT sonarsource DOT com
~
~ SonarQube is free software; you can redistribute it and/or
~ modify it under the terms of the GNU Lesser General Public
~ License as published by the Free Software Foundation; either
~ version 3 of the License, or (at your option) any later version.
~
~ SonarQube is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
~ Lesser General Public License for more details.
~
~ You should have received a copy of the GNU Lesser General Public License
~ along with this program; if not, write to the Free Software Foundation,
~ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-->

<sqale>
<chc>
<key>USABILITY</key>
<name>Usability</name>
<desc>Estimate usability</desc>
</chc>
<chc>
<key>EFFICIENCY</key>
<name>Efficiency</name>
<chc>
<key>MEMORY_EFFICIENCY</key>
<name>Memory use</name>
<chc>
<rule-repo>checkstyle</rule-repo>
<rule-key>Regexp</rule-key>
<prop>
<key>offset</key>
<val>3.0</val>
<txt>h</txt>
</prop>
<prop>
<key>remediationFunction</key>
<txt>linear</txt>
</prop>
</chc>
</chc>
</chc>

</sqale>

sonar-core/src/test/resources/org/sonar/core/technicaldebt/DebtRulesXMLImporterTest/ignore_deprecated_constant_per_file_function.xml → sonar-server/src/test/resources/org/sonar/server/debt/DebtRulesXMLImporterTest/ignore_deprecated_constant_per_file_function.xml View File


sonar-core/src/test/resources/org/sonar/core/technicaldebt/DebtRulesXMLImporterTest/ignore_invalid_value.xml → sonar-server/src/test/resources/org/sonar/server/debt/DebtRulesXMLImporterTest/ignore_invalid_value.xml View File


sonar-core/src/test/resources/org/sonar/core/technicaldebt/DebtRulesXMLImporterTest/ignore_rule_on_root_characteristics.xml → sonar-server/src/test/resources/org/sonar/server/debt/DebtRulesXMLImporterTest/ignore_rule_on_root_characteristics.xml View File


sonar-core/src/test/resources/org/sonar/core/technicaldebt/DebtRulesXMLImporterTest/import_badly_formatted_xml.xml → sonar-server/src/test/resources/org/sonar/server/debt/DebtRulesXMLImporterTest/import_badly_formatted_xml.xml View File


sonar-core/src/test/resources/org/sonar/core/technicaldebt/DebtRulesXMLImporterTest/import_constant_issue.xml → sonar-server/src/test/resources/org/sonar/server/debt/DebtRulesXMLImporterTest/import_constant_issue.xml View File


sonar-core/src/test/resources/org/sonar/core/technicaldebt/DebtRulesXMLImporterTest/import_linear.xml → sonar-server/src/test/resources/org/sonar/server/debt/DebtRulesXMLImporterTest/import_linear.xml View File


+ 34
- 0
sonar-server/src/test/resources/org/sonar/server/debt/DebtRulesXMLImporterTest/import_linear_having_offset_to_zero.xml View File

@@ -0,0 +1,34 @@
<sqale>
<chc>
<key>USABILITY</key>
<name>Usability</name>
<desc>Estimate usability</desc>
</chc>
<chc>
<key>EFFICIENCY</key>
<name>Efficiency</name>
<chc>
<key>MEMORY_EFFICIENCY</key>
<name>Memory use</name>
<chc>
<rule-repo>checkstyle</rule-repo>
<rule-key>Regexp</rule-key>
<prop>
<key>remediationFactor</key>
<val>3.0</val>
<txt>h</txt>
</prop>
<prop>
<key>remediationFunction</key>
<txt>linear</txt>
</prop>
<prop>
<key>offset</key>
<val>0.0</val>
<txt>min</txt>
</prop>
</chc>
</chc>
</chc>

</sqale>

sonar-core/src/test/resources/org/sonar/core/technicaldebt/DebtRulesXMLImporterTest/import_linear_with_offset.xml → sonar-server/src/test/resources/org/sonar/server/debt/DebtRulesXMLImporterTest/import_linear_with_offset.xml View File


sonar-core/src/test/resources/org/sonar/core/technicaldebt/DebtRulesXMLImporterTest/import_rules.xml → sonar-server/src/test/resources/org/sonar/server/debt/DebtRulesXMLImporterTest/import_rules.xml View File

@@ -45,7 +45,7 @@
</prop>
<prop>
<key>remediationFunction</key>
<txt>linear</txt>
<txt>linear_offset</txt>
</prop>
<prop>
<key>offset</key>

sonar-core/src/test/resources/org/sonar/core/technicaldebt/DebtRulesXMLImporterTest/replace_mn_by_min.xml → sonar-server/src/test/resources/org/sonar/server/debt/DebtRulesXMLImporterTest/replace_mn_by_min.xml View File


sonar-core/src/test/resources/org/sonar/core/technicaldebt/DebtRulesXMLImporterTest/use_default_unit_when_no_unit.xml → sonar-server/src/test/resources/org/sonar/server/debt/DebtRulesXMLImporterTest/use_default_unit_when_no_unit.xml View File

@@ -19,7 +19,7 @@
</prop>
<prop>
<key>remediationFunction</key>
<txt>linear</txt>
<txt>linear_offset</txt>
</prop>
<prop>
<key>offset</key>

sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/remove_rule_debt_definitions_if_characteristic_not_found-result.xml → sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/set_no_characteristic_when_characteristic_not_found-result.xml View File

@@ -1,13 +1,12 @@
<dataset>

<!-- All debt parameters are reset as the characteristic MEMORY_EFFICIENCY do not exists -->
<rules id="1" plugin_rule_key="rule1" plugin_name="fake" plugin_config_key="config1" name="One" description="Description of One"
status="READY" priority="4" cardinality="SINGLE" parent_id="[null]" language="java"
characteristic_id="[null]" default_characteristic_id="[null]"
remediation_function="[null]" default_remediation_function="[null]"
remediation_factor="[null]" default_remediation_factor="[null]"
remediation_offset="[null]" default_remediation_offset="[null]"
effort_to_fix_l10n_key="[null]"/>
remediation_function="[null]" default_remediation_function="LINEAR_OFFSET"
remediation_factor="[null]" default_remediation_factor="5d"
remediation_offset="[null]" default_remediation_offset="10h"
effort_to_fix_l10n_key="squid.S115.effortToFix"/>

<rules id="2" plugin_rule_key="rule2" plugin_name="fake" plugin_config_key="[null]" name="Two" description="Description of Two"
status="DEPRECATED" priority="0" cardinality="SINGLE" parent_id="[null]" language="java"

sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/remove_rule_debt_definitions_if_characteristic_not_found.xml → sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/set_no_characteristic_when_characteristic_not_found.xml View File


Loading…
Cancel
Save