--- /dev/null
+package it.debt;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableSet;
+import com.sonar.orchestrator.Orchestrator;
+import java.util.Set;
+import org.junit.rules.ExternalResource;
+
+import static com.google.common.base.Preconditions.checkState;
+import static util.ItUtils.setServerProperty;
+
+/**
+ * This rule should be used when dealing with technical debt properties, in order to always be sure that the properties are correctly reset between each tests.
+ */
+public class DebtConfigurationRule extends ExternalResource {
+
+ private static final String HOURS_IN_DAY_PROPERTY = "sonar.technicalDebt.hoursInDay";
+ private static final String DEV_COST_PROPERTY = "sonar.technicalDebt.developmentCost";
+ private static final String RATING_GRID_PROPERTY = "sonar.technicalDebt.ratingGrid";
+
+ private static final String DEV_COST_LANGUAGE_PROPERTY = "languageSpecificParameters";
+ private static final String DEV_COST_LANGUAGE_NAME_PROPERTY = DEV_COST_LANGUAGE_PROPERTY + ".0.language";
+ private static final String DEV_COST_LANGUAGE_COST_PROPERTY = DEV_COST_LANGUAGE_PROPERTY + ".0.man_days";
+
+ private static final Joiner COMA_JOINER = Joiner.on(",");
+
+ private static final Set<String> DEV_COST_PROPERTIES = ImmutableSet.of(
+ DEV_COST_PROPERTY,
+ DEV_COST_LANGUAGE_PROPERTY,
+ DEV_COST_LANGUAGE_NAME_PROPERTY,
+ DEV_COST_LANGUAGE_COST_PROPERTY,
+ RATING_GRID_PROPERTY);
+
+ private final Orchestrator orchestrator;
+
+ private DebtConfigurationRule(Orchestrator orchestrator) {
+ this.orchestrator = orchestrator;
+ }
+
+ public static DebtConfigurationRule create(Orchestrator orchestrator) {
+ return new DebtConfigurationRule(orchestrator);
+ }
+
+ @Override
+ protected void before() throws Throwable {
+ reset();
+ }
+
+ @Override
+ protected void after() {
+ reset();
+ }
+
+ public void reset() {
+ resetHoursInDay();
+ resetDevelopmentCost();
+ resetRatingGrid();
+ }
+
+ public DebtConfigurationRule updateHoursInDay(int hoursInDay) {
+ setProperty(HOURS_IN_DAY_PROPERTY, Integer.toString(hoursInDay));
+ return this;
+ }
+
+ public DebtConfigurationRule resetHoursInDay() {
+ resetProperty(HOURS_IN_DAY_PROPERTY);
+ return this;
+ }
+
+ public DebtConfigurationRule updateDevelopmentCost(int developmentCost) {
+ setProperty(DEV_COST_PROPERTY, Integer.toString(developmentCost));
+ return this;
+ }
+
+ public DebtConfigurationRule updateLanguageDevelopmentCost(String language, int developmentCost) {
+ setServerProperty(orchestrator, DEV_COST_LANGUAGE_PROPERTY, "0");
+ setServerProperty(orchestrator, DEV_COST_LANGUAGE_NAME_PROPERTY, language);
+ setServerProperty(orchestrator, DEV_COST_LANGUAGE_COST_PROPERTY, Integer.toString(developmentCost));
+ return this;
+ }
+
+ public void resetDevelopmentCost() {
+ for (String property : DEV_COST_PROPERTIES) {
+ resetProperty(property);
+ }
+ }
+
+ public DebtConfigurationRule updateRatingGrid(Double... ratingGrid) {
+ checkState(ratingGrid.length == 4, "Rating grid must contains 4 values");
+ setProperty(RATING_GRID_PROPERTY, COMA_JOINER.join(ratingGrid));
+ return this;
+ }
+
+ public DebtConfigurationRule resetRatingGrid() {
+ resetProperty(RATING_GRID_PROPERTY);
+ return this;
+ }
+
+ private void setProperty(String property, String value) {
+ setServerProperty(orchestrator, property, value);
+ }
+
+ private void resetProperty(String property) {
+ setProperty(property, null);
+ }
+
+}
*/
package it.debt;
-import com.google.common.collect.ImmutableSet;
import com.sonar.orchestrator.Orchestrator;
import com.sonar.orchestrator.build.SonarRunner;
import com.sonar.orchestrator.locator.FileLocation;
import it.Category2Suite;
-import org.junit.AfterClass;
import org.junit.Before;
import org.junit.ClassRule;
+import org.junit.Rule;
import org.junit.Test;
import org.sonar.wsclient.services.Measure;
import org.sonar.wsclient.services.Resource;
import static org.assertj.core.api.Assertions.assertThat;
import static util.ItUtils.projectDir;
-import static util.ItUtils.setServerProperty;
/**
* SONAR-4715
private static final String SUB_MODULE = "com.sonarsource.it.samples:multi-modules-sample:module_a:module_a1";
private static final String DIRECTORY = "com.sonarsource.it.samples:multi-modules-sample:module_a:module_a1:src/main/xoo/com/sonar/it/samples/modules/a1";
private static final String FILE = "com.sonarsource.it.samples:multi-modules-sample:module_a:module_a1:src/main/xoo/com/sonar/it/samples/modules/a1/HelloA1.xoo";
+
@ClassRule
public static Orchestrator orchestrator = Category2Suite.ORCHESTRATOR;
- private static void resetDevelopmentCost() {
- for (String property : ImmutableSet.of("sonar.technicalDebt.developmentCost", "sonar.technicalDebt.sizeMetric",
- "languageSpecificParameters", "languageSpecificParameters.0.language", "languageSpecificParameters.0.man_days", "languageSpecificParameters.0.size_metric",
- "ratingGrid")) {
- setServerProperty(orchestrator, property, null);
- }
- }
-
- @AfterClass
- public static void reset() {
- resetDevelopmentCost();
- }
+ @Rule
+ public DebtConfigurationRule debtConfiguration = DebtConfigurationRule.create(orchestrator);
@Before
public void init() {
- resetDevelopmentCost();
orchestrator.resetData();
+
+ // Set rating grid values to not depend from default value
+ debtConfiguration.updateRatingGrid(0.1d, 0.2d, 0.5d, 1d);
}
@Test
assertThat(rating.getIntValue()).isEqualTo(1);
assertThat(rating.getData()).isEqualTo("A");
- setServerProperty(orchestrator, "sonar.technicalDebt.developmentCost", "2");
+ debtConfiguration.updateDevelopmentCost(2);
orchestrator.executeBuild(SonarRunner.create(projectDir("shared/xoo-sample")));
rating = getMeasure("sample", "sqale_rating");
assertThat(rating.getIntValue()).isEqualTo(1);
assertThat(rating.getData()).isEqualTo("A");
- setServerProperty(orchestrator, "languageSpecificParameters", "0");
- setServerProperty(orchestrator, "languageSpecificParameters.0.language", "xoo");
- setServerProperty(orchestrator, "languageSpecificParameters.0.man_days", "1");
- setServerProperty(orchestrator, "languageSpecificParameters.0.size_metric", "ncloc");
+ debtConfiguration.updateLanguageDevelopmentCost("xoo", 1);
orchestrator.executeBuild(
SonarRunner.create(projectDir("shared/xoo-multi-modules-sample"))
.setProfile("one-issue-per-line"));
assertThat(rating.getIntValue()).isEqualTo(1);
assertThat(rating.getData()).isEqualTo("A");
- setServerProperty(orchestrator, "ratingGrid", "0.001,0.005,0.010,0.015");
+ debtConfiguration.updateRatingGrid(0.001d, 0.005d, 0.01d, 0.015d);
orchestrator.executeBuild(SonarRunner.create(projectDir("shared/xoo-sample")));
rating = getMeasure("sample", "sqale_rating");
import com.sonar.orchestrator.locator.FileLocation;
import it.Category2Suite;
import java.util.List;
-import org.junit.AfterClass;
import org.junit.Before;
import org.junit.ClassRule;
+import org.junit.Rule;
import org.junit.Test;
import org.sonar.wsclient.issue.Issue;
import org.sonar.wsclient.issue.IssueChange;
import static org.assertj.core.api.Assertions.assertThat;
import static util.ItUtils.projectDir;
-import static util.ItUtils.setServerProperty;
/**
* SONAR-4834
@ClassRule
public static Orchestrator orchestrator = Category2Suite.ORCHESTRATOR;
- @AfterClass
- public static void resetHoursInDay() throws Exception {
- setServerProperty(orchestrator, "sonar.technicalDebt.hoursInDay", null);
- }
+ @Rule
+ public DebtConfigurationRule debtConfiguration = DebtConfigurationRule.create(orchestrator);
@Before
public void deleteAnalysisData() {
orchestrator.resetData();
// Set hours in day property to 8
- setServerProperty(orchestrator, "sonar.technicalDebt.hoursInDay", "8");
+ debtConfiguration.updateHoursInDay(8);
}
@Test
orchestrator.executeBuild(SonarRunner.create(projectDir("shared/xoo-sample")));
// One day -> 10 hours
- setServerProperty(orchestrator, "sonar.technicalDebt.hoursInDay", "10");
+ debtConfiguration.updateHoursInDay(10);
orchestrator.executeBuild(SonarRunner.create(projectDir("shared/xoo-sample"))
// As OneIssuePerFile has a debt of 10 minutes, we multiply it by 72 to have 1 day and 2 hours of technical debtn
import com.sonar.orchestrator.locator.FileLocation;
import it.Category2Suite;
import java.util.List;
-import org.junit.AfterClass;
import org.junit.Before;
import org.junit.ClassRule;
+import org.junit.Rule;
import org.junit.Test;
import org.sonar.wsclient.issue.Issue;
import org.sonar.wsclient.issue.IssueClient;
import static org.assertj.core.api.Assertions.assertThat;
import static util.ItUtils.projectDir;
-import static util.ItUtils.setServerProperty;
public class TechnicalDebtTest {
@ClassRule
public static Orchestrator orchestrator = Category2Suite.ORCHESTRATOR;
- @AfterClass
- public static void resetHoursInDay() throws Exception {
- setServerProperty(orchestrator, "sonar.technicalDebt.hoursInDay", null);
- }
+ @Rule
+ public DebtConfigurationRule debtConfiguration = DebtConfigurationRule.create(orchestrator);
@Before
public void deleteAnalysisData() {
orchestrator.resetData();
+
// Set hours in day property to 8
- setServerProperty(orchestrator, "sonar.technicalDebt.hoursInDay", "8");
+ debtConfiguration.updateHoursInDay(8);
}
/**
orchestrator.getServer().associateProjectToQualityProfile("sample", "xoo", "one-issue-per-file");
// One day -> 10 hours
- setServerProperty(orchestrator, "sonar.technicalDebt.hoursInDay", "10");
+ debtConfiguration.updateHoursInDay(10);
orchestrator.executeBuild(SonarRunner.create(projectDir("shared/xoo-sample"))
// As OneIssuePerFile has a debt of 10 minutes, we multiply it by 72 to have 1 day and 2 hours of technical debt
orchestrator.getServer().associateProjectToQualityProfile("sample", "xoo", "one-day-debt-per-file");
// One day -> 10 hours : debt will be stored as 360.000 seconds (1 day * 10 hours per day * 60 * 60)
- setServerProperty(orchestrator, "sonar.technicalDebt.hoursInDay", "10");
+ debtConfiguration.updateHoursInDay(10);
orchestrator.executeBuild(SonarRunner.create(projectDir("shared/xoo-sample")));
// Issue debt was 1 day during analysis but will be displayed as 1 day and 2 hours (hours in day property was set
// to 10 during analysis but is now 8)
- setServerProperty(orchestrator, "sonar.technicalDebt.hoursInDay", "8");
+ debtConfiguration.updateHoursInDay(8);
IssueClient issueClient = orchestrator.getServer().wsClient().issueClient();
Issue issue = issueClient.find(IssueQuery.create()).list().get(0);
@ClassRule
public static Orchestrator orchestrator = Category2Suite.ORCHESTRATOR;
+ @ClassRule
+ public static DebtConfigurationRule debtConfiguration = DebtConfigurationRule.create(orchestrator);
+
@BeforeClass
public static void init() {
orchestrator.resetData();
+ // Set rating grid values to not depend from default value
+ debtConfiguration.updateRatingGrid(0.1d, 0.2d, 0.5d, 1d);
+
orchestrator.getServer().restoreProfile(FileLocation.ofClasspath("/debt/with-many-rules.xml"));
orchestrator.getServer().provisionProject("com.sonarsource.it.samples:multi-modules-sample", "com.sonarsource.it.samples:multi-modules-sample");
orchestrator.getServer().associateProjectToQualityProfile("com.sonarsource.it.samples:multi-modules-sample", "xoo", "with-many-rules");
.name("Rating grid")
.description("SQALE ratings range from A (very good) to E (very bad). The rating is determined by the value of " +
"the Technical Debt Ratio, which compares the technical debt on a project to the cost it would take to rewrite " +
- "the code from scratch. The default values for A through D are 0.1,0.2,0.5,1. Anything over 1 is an E. " +
+ "the code from scratch. The default values for A through D are 0.05,0.1,0.2,0.5. Anything over 0.5 is an E. " +
"Example: assuming the development cost is 30 minutes, a project with a technical debt of 24,000 minutes for " +
- "2,500 LOC will have a technical debt ratio of 24000/(30 * 2,500) = 0.32. That yields a SQALE rating of C.")
+ "2,500 LOC will have a technical debt ratio of 24000/(30 * 2,500) = 0.32. That yields a SQALE rating of D.")
.category(CoreProperties.CATEGORY_TECHNICAL_DEBT)
.deprecatedKey("ratingGrid")
.build(),
/**
* @since 4.5
*/
- String RATING_GRID_DEF_VALUES = "0.1,0.2,0.5,1";
+ String RATING_GRID_DEF_VALUES = "0.05,0.1,0.2,0.5";
/**
* @since 4.5