aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-batch/src/test/java/org
diff options
context:
space:
mode:
authorJulien Lancelot <julien.lancelot@sonarsource.com>2014-03-11 08:09:01 +0100
committerJulien Lancelot <julien.lancelot@sonarsource.com>2014-03-11 08:09:01 +0100
commitdce23fcf9ac907f6621ab0c11c397febff280ebc (patch)
treef819d4a7216d35389a3063b0f0a96cde49cb62db /sonar-batch/src/test/java/org
parent1ffa320fb3e44cdaf635678a04c473ca4f348514 (diff)
downloadsonarqube-dce23fcf9ac907f6621ab0c11c397febff280ebc.tar.gz
sonarqube-dce23fcf9ac907f6621ab0c11c397febff280ebc.zip
SONAR-5056 Read debt from rule during analysis
Diffstat (limited to 'sonar-batch/src/test/java/org')
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/debt/DebtModelProviderTest.java (renamed from sonar-batch/src/test/java/org/sonar/batch/debt/DebtModelLoaderTest.java)29
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/debt/RuleDebtCalculatorTest.java145
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/debt/TechnicalDebtModelProviderTest.java60
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/issue/ModuleIssuesTest.java200
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/rule/RulesProviderTest.java170
5 files changed, 309 insertions, 295 deletions
diff --git a/sonar-batch/src/test/java/org/sonar/batch/debt/DebtModelLoaderTest.java b/sonar-batch/src/test/java/org/sonar/batch/debt/DebtModelProviderTest.java
index 2de08c8f77a..50e08fc793c 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/debt/DebtModelLoaderTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/debt/DebtModelProviderTest.java
@@ -27,34 +27,27 @@ import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rules.Rule;
-import org.sonar.api.rules.RuleFinder;
-import org.sonar.api.rules.RuleQuery;
import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
-import org.sonar.api.technicaldebt.batch.internal.DefaultRequirement;
-import org.sonar.api.utils.internal.WorkDuration;
import org.sonar.core.technicaldebt.DefaultTechnicalDebtModel;
import org.sonar.core.technicaldebt.db.CharacteristicDao;
import org.sonar.core.technicaldebt.db.CharacteristicDto;
import static com.google.common.collect.Lists.newArrayList;
import static org.fest.assertions.Assertions.assertThat;
-import static org.mockito.Matchers.any;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
-public class DebtModelLoaderTest {
+public class DebtModelProviderTest {
@Mock
CharacteristicDao dao;
- @Mock
- RuleFinder ruleFinder;
+ DebtModelProvider provider;
- DebtModelLoader loader;
@Before
public void before() {
- loader = new DebtModelLoader(dao, ruleFinder);
+ provider = new DebtModelProvider();
}
@Test
@@ -83,17 +76,15 @@ public class DebtModelLoaderTest {
RuleKey ruleKey = RuleKey.of("checkstyle", "Regexp");
Rule rule = Rule.create(ruleKey.repository(), ruleKey.rule());
rule.setId(100);
- when(ruleFinder.findAll(any(RuleQuery.class))).thenReturn(newArrayList(rule));
- when(dao.selectEnabledCharacteristics()).thenReturn(newArrayList(rootCharacteristicDto, characteristicDto, requirementDto));
+ when(dao.selectCharacteristics()).thenReturn(newArrayList(rootCharacteristicDto, characteristicDto, requirementDto));
- DefaultTechnicalDebtModel result = (DefaultTechnicalDebtModel) loader.load();
+ DefaultTechnicalDebtModel result = (DefaultTechnicalDebtModel) provider.provide(dao);
assertThat(result.rootCharacteristics()).hasSize(1);
DefaultCharacteristic rootCharacteristic = result.characteristicByKey("MEMORY_EFFICIENCY");
assertThat(rootCharacteristic.key()).isEqualTo("MEMORY_EFFICIENCY");
assertThat(rootCharacteristic.name()).isEqualTo("Memory use");
assertThat(rootCharacteristic.parent()).isNull();
- assertThat(rootCharacteristic.requirements()).isEmpty();
assertThat(rootCharacteristic.children()).hasSize(1);
assertThat(rootCharacteristic.children().get(0).key()).isEqualTo("EFFICIENCY");
@@ -102,16 +93,6 @@ public class DebtModelLoaderTest {
assertThat(characteristic.name()).isEqualTo("Efficiency");
assertThat(characteristic.parent().key()).isEqualTo("MEMORY_EFFICIENCY");
assertThat(characteristic.children()).isEmpty();
- assertThat(characteristic.requirements()).hasSize(1);
- assertThat(characteristic.requirements().get(0).ruleKey()).isEqualTo(ruleKey);
-
- DefaultRequirement requirement = result.requirementsByRule(ruleKey);
- assertThat(requirement.ruleKey()).isEqualTo(ruleKey);
- assertThat(requirement.function()).isEqualTo("linear");
- assertThat(requirement.factorValue()).isEqualTo(2);
- assertThat(requirement.factorUnit()).isEqualTo(WorkDuration.UNIT.DAYS);
- assertThat(requirement.offsetValue()).isEqualTo(0);
- assertThat(requirement.offsetUnit()).isEqualTo(WorkDuration.UNIT.MINUTES);
}
}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/debt/RuleDebtCalculatorTest.java b/sonar-batch/src/test/java/org/sonar/batch/debt/RuleDebtCalculatorTest.java
deleted file mode 100644
index c53cdcdc2d5..00000000000
--- a/sonar-batch/src/test/java/org/sonar/batch/debt/RuleDebtCalculatorTest.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.batch.debt;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.config.Settings;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.technicaldebt.batch.TechnicalDebtModel;
-import org.sonar.api.technicaldebt.batch.internal.DefaultRequirement;
-import org.sonar.api.utils.internal.WorkDuration;
-
-import static org.fest.assertions.Assertions.assertThat;
-import static org.fest.assertions.Fail.fail;
-import static org.mockito.Mockito.when;
-
-@RunWith(MockitoJUnitRunner.class)
-public class RuleDebtCalculatorTest {
-
- private static final int HOURS_IN_DAY = 8;
-
- @Mock
- TechnicalDebtModel model;
-
- RuleDebtCalculator calculator;
-
- @Before
- public void before() {
- calculator = new RuleDebtCalculator(model, new Settings().setProperty(CoreProperties.HOURS_IN_DAY, 8));
- }
-
- @Test
- public void calculate_technical_debt() throws Exception {
- RuleKey ruleKey = RuleKey.of("squid", "AvoidCycle");
- DefaultIssue issue = new DefaultIssue().setKey("ABCDE").setRuleKey(ruleKey);
-
- DefaultRequirement requirement = new DefaultRequirement()
- .setFunction("constant_issue")
- .setFactorValue(10)
- .setFactorUnit(WorkDuration.UNIT.MINUTES)
- .setOffsetValue(5)
- .setOffsetUnit(WorkDuration.UNIT.MINUTES);
- when(model.requirementsByRule(ruleKey)).thenReturn(requirement);
-
- assertThat(calculator.calculateTechnicalDebt(issue.ruleKey(), issue.effortToFix())).isEqualTo(15L);
- }
-
- @Test
- public void calculate_technical_debt_with_effort_to_fix() throws Exception {
- RuleKey ruleKey = RuleKey.of("squid", "AvoidCycle");
- DefaultIssue issue = new DefaultIssue().setKey("ABCDE").setRuleKey(ruleKey).setEffortToFix(2d);
-
- DefaultRequirement requirement = new DefaultRequirement()
- .setFunction("linear_offset")
- .setFactorValue(10)
- .setFactorUnit(WorkDuration.UNIT.MINUTES)
- .setOffsetValue(5)
- .setOffsetUnit(WorkDuration.UNIT.MINUTES);
- when(model.requirementsByRule(ruleKey)).thenReturn(requirement);
-
- assertThat(calculator.calculateTechnicalDebt(issue.ruleKey(), issue.effortToFix())).isEqualTo(((10 * 2) + 5));
- }
-
- @Test
- public void calculate_technical_debt_with_no_offset() throws Exception {
- RuleKey ruleKey = RuleKey.of("squid", "AvoidCycle");
- DefaultIssue issue = new DefaultIssue().setKey("ABCDE").setRuleKey(ruleKey).setEffortToFix(2d);
-
- DefaultRequirement requirement = new DefaultRequirement()
- .setFunction("linear")
- .setFactorValue(10)
- .setFactorUnit(WorkDuration.UNIT.HOURS);
- when(model.requirementsByRule(ruleKey)).thenReturn(requirement);
-
- assertThat(calculator.calculateTechnicalDebt(issue.ruleKey(), issue.effortToFix())).isEqualTo((10 * 2) * 60);
- }
-
- @Test
- public void calculate_technical_debt_with_no_factor() throws Exception {
- RuleKey ruleKey = RuleKey.of("squid", "AvoidCycle");
- DefaultIssue issue = new DefaultIssue().setKey("ABCDE").setRuleKey(ruleKey);
-
- DefaultRequirement requirement = new DefaultRequirement()
- .setFunction("constant_issue")
- .setOffsetValue(5)
- .setOffsetUnit(WorkDuration.UNIT.DAYS);
-
- when(model.requirementsByRule(ruleKey)).thenReturn(requirement);
-
- assertThat(calculator.calculateTechnicalDebt(issue.ruleKey(), issue.effortToFix())).isEqualTo(5 * HOURS_IN_DAY * 60);
- }
-
- @Test
- public void no_technical_debt_if_requirement_not_found() throws Exception {
- RuleKey ruleKey = RuleKey.of("squid", "AvoidCycle");
- DefaultIssue issue = new DefaultIssue().setKey("ABCDE").setRuleKey(ruleKey);
- when(model.requirementsByRule(ruleKey)).thenReturn(null);
-
- assertThat(calculator.calculateTechnicalDebt(issue.ruleKey(), issue.effortToFix())).isNull();
- }
-
- @Test
- public void fail_to_calculate_technical_debt_on_constant_issue_function_with_effort_to_fix() throws Exception {
- RuleKey ruleKey = RuleKey.of("squid", "AvoidCycle");
- DefaultIssue issue = new DefaultIssue().setKey("ABCDE").setRuleKey(ruleKey).setEffortToFix(2d);
-
- DefaultRequirement requirement = new DefaultRequirement()
- .setFunction("constant_issue")
- .setOffsetValue(5)
- .setOffsetUnit(WorkDuration.UNIT.MINUTES);
- when(model.requirementsByRule(ruleKey)).thenReturn(requirement);
-
- try {
- assertThat(calculator.calculateTechnicalDebt(issue.ruleKey(), issue.effortToFix())).isEqualTo(15);
- fail();
- } catch (Exception e) {
- assertThat(e).isInstanceOf(IllegalArgumentException.class)
- .hasMessage("Requirement for 'squid:AvoidCycle' can not use 'Constant/issue' remediation function because this rule does not have a fixed remediation cost.");
- }
- }
-
-}
-
diff --git a/sonar-batch/src/test/java/org/sonar/batch/debt/TechnicalDebtModelProviderTest.java b/sonar-batch/src/test/java/org/sonar/batch/debt/TechnicalDebtModelProviderTest.java
deleted file mode 100644
index 05747f800e5..00000000000
--- a/sonar-batch/src/test/java/org/sonar/batch/debt/TechnicalDebtModelProviderTest.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.batch.debt;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-import org.sonar.api.technicaldebt.batch.TechnicalDebtModel;
-
-import static org.fest.assertions.Assertions.assertThat;
-import static org.mockito.Mockito.*;
-
-@RunWith(MockitoJUnitRunner.class)
-public class TechnicalDebtModelProviderTest {
-
- @Mock
- DebtModelLoader loader;
-
- @Test
- public void load_model() {
- TechnicalDebtModel model = mock(TechnicalDebtModel.class);
- when(loader.load()).thenReturn(model);
-
- DebtModelProvider provider = new DebtModelProvider();
- TechnicalDebtModel result = provider.provide(loader);
- assertThat(result).isNotNull();
- }
-
- @Test
- public void load_model_only_once() {
- TechnicalDebtModel model = mock(TechnicalDebtModel.class);
- when(loader.load()).thenReturn(model);
-
- DebtModelProvider provider = new DebtModelProvider();
- provider.provide(loader);
- verify(loader).load();
-
- provider.provide(loader);
- verifyZeroInteractions(loader);
- }
-}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/issue/ModuleIssuesTest.java b/sonar-batch/src/test/java/org/sonar/batch/issue/ModuleIssuesTest.java
index 1150211081e..b8c4d1efbf1 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/issue/ModuleIssuesTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/issue/ModuleIssuesTest.java
@@ -26,17 +26,19 @@ import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
+import org.sonar.api.batch.rule.internal.ActiveRulesBuilder;
+import org.sonar.api.batch.rule.internal.RulesBuilder;
import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.profiles.RulesProfile;
import org.sonar.api.resources.JavaFile;
import org.sonar.api.resources.Project;
import org.sonar.api.resources.Resource;
+import org.sonar.api.rule.RemediationFunction;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.Severity;
-import org.sonar.api.rules.*;
+import org.sonar.api.rules.RulePriority;
+import org.sonar.api.rules.Violation;
import org.sonar.api.utils.Duration;
import org.sonar.api.utils.MessageException;
-import org.sonar.batch.debt.RuleDebtCalculator;
import java.util.Calendar;
import java.util.Date;
@@ -44,7 +46,6 @@ import java.util.Date;
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.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.*;
@@ -52,25 +53,19 @@ import static org.mockito.Mockito.*;
public class ModuleIssuesTest {
static final RuleKey SQUID_RULE_KEY = RuleKey.of("squid", "AvoidCycle");
- static final Rule SQUID_RULE = Rule.create("squid", "AvoidCycle").setName("Avoid Cycle");
+ static final String SQUID_RULE_NAME = "Avoid Cycle";
@Mock
IssueCache cache;
@Mock
- RulesProfile qProfile;
-
- @Mock
Project project;
@Mock
IssueFilters filters;
- @Mock
- RuleDebtCalculator technicalDebtCalculator;
-
- @Mock
- RuleFinder ruleFinder;
+ ActiveRulesBuilder activeRulesBuilder = new ActiveRulesBuilder();
+ RulesBuilder ruleBuilder = new RulesBuilder();
ModuleIssues moduleIssues;
@@ -78,13 +73,11 @@ public class ModuleIssuesTest {
public void setUp() {
when(project.getAnalysisDate()).thenReturn(new Date());
when(project.getEffectiveKey()).thenReturn("org.apache:struts-core");
-
- moduleIssues = new ModuleIssues(qProfile, cache, project, filters, technicalDebtCalculator, ruleFinder);
}
@Test
public void fail_on_unknown_rule() throws Exception {
- when(ruleFinder.findByKey(SQUID_RULE_KEY)).thenReturn(null);
+ initModuleIssues();
DefaultIssue issue = new DefaultIssue().setRuleKey(SQUID_RULE_KEY);
try {
@@ -99,7 +92,8 @@ public class ModuleIssuesTest {
@Test
public void fail_if_rule_has_no_name_and_issue_has_no_message() throws Exception {
- when(ruleFinder.findByKey(SQUID_RULE_KEY)).thenReturn(Rule.create("squid", "AvoidCycle"));
+ ruleBuilder.add(RuleKey.of("squid", "AvoidCycle"));
+ initModuleIssues();
DefaultIssue issue = new DefaultIssue().setRuleKey(SQUID_RULE_KEY).setMessage("");
try {
@@ -114,8 +108,8 @@ public class ModuleIssuesTest {
@Test
public void ignore_null_active_rule() throws Exception {
- when(qProfile.getActiveRule(anyString(), anyString())).thenReturn(null);
- when(ruleFinder.findByKey(SQUID_RULE_KEY)).thenReturn(SQUID_RULE);
+ ruleBuilder.add(SQUID_RULE_KEY).setName(SQUID_RULE_NAME);
+ initModuleIssues();
DefaultIssue issue = new DefaultIssue().setRuleKey(SQUID_RULE_KEY);
boolean added = moduleIssues.initAndAddIssue(issue);
@@ -126,10 +120,9 @@ public class ModuleIssuesTest {
@Test
public void ignore_null_rule_of_active_rule() throws Exception {
- ActiveRule activeRule = mock(ActiveRule.class);
- when(activeRule.getRule()).thenReturn(null);
- when(qProfile.getActiveRule(anyString(), anyString())).thenReturn(activeRule);
- when(ruleFinder.findByKey(SQUID_RULE_KEY)).thenReturn(SQUID_RULE);
+ ruleBuilder.add(SQUID_RULE_KEY).setName(SQUID_RULE_NAME);
+ activeRulesBuilder.activate(SQUID_RULE_KEY);
+ initModuleIssues();
DefaultIssue issue = new DefaultIssue().setRuleKey(SQUID_RULE_KEY);
boolean added = moduleIssues.initAndAddIssue(issue);
@@ -140,12 +133,9 @@ public class ModuleIssuesTest {
@Test
public void add_issue_to_cache() throws Exception {
- Rule rule = SQUID_RULE;
- ActiveRule activeRule = mock(ActiveRule.class);
- when(activeRule.getRule()).thenReturn(rule);
- when(activeRule.getSeverity()).thenReturn(RulePriority.INFO);
- when(qProfile.getActiveRule("squid", "AvoidCycle")).thenReturn(activeRule);
- when(ruleFinder.findByKey(SQUID_RULE_KEY)).thenReturn(rule);
+ ruleBuilder.add(SQUID_RULE_KEY).setName(SQUID_RULE_NAME);
+ activeRulesBuilder.activate(SQUID_RULE_KEY).setSeverity(Severity.INFO);
+ initModuleIssues();
Date analysisDate = new Date();
when(project.getAnalysisDate()).thenReturn(analysisDate);
@@ -166,13 +156,10 @@ public class ModuleIssuesTest {
}
@Test
- public void use_severity_from_active_rule_if_no_severity() throws Exception {
- Rule rule = SQUID_RULE;
- ActiveRule activeRule = mock(ActiveRule.class);
- when(activeRule.getRule()).thenReturn(rule);
- when(activeRule.getSeverity()).thenReturn(RulePriority.INFO);
- when(qProfile.getActiveRule("squid", "AvoidCycle")).thenReturn(activeRule);
- when(ruleFinder.findByKey(SQUID_RULE_KEY)).thenReturn(rule);
+ public void use_severity_from_active_rule_if_no_severity_on_issue() throws Exception {
+ ruleBuilder.add(SQUID_RULE_KEY).setName(SQUID_RULE_NAME);
+ activeRulesBuilder.activate(SQUID_RULE_KEY).setSeverity(Severity.INFO);
+ initModuleIssues();
Date analysisDate = new Date();
when(project.getAnalysisDate()).thenReturn(analysisDate);
@@ -189,12 +176,9 @@ public class ModuleIssuesTest {
@Test
public void use_rule_name_if_no_message() throws Exception {
- Rule rule = SQUID_RULE;
- ActiveRule activeRule = mock(ActiveRule.class);
- when(activeRule.getRule()).thenReturn(rule);
- when(activeRule.getSeverity()).thenReturn(RulePriority.INFO);
- when(qProfile.getActiveRule("squid", "AvoidCycle")).thenReturn(activeRule);
- when(ruleFinder.findByKey(SQUID_RULE_KEY)).thenReturn(rule);
+ ruleBuilder.add(SQUID_RULE_KEY).setName(SQUID_RULE_NAME);
+ activeRulesBuilder.activate(SQUID_RULE_KEY).setSeverity(Severity.INFO);
+ initModuleIssues();
Date analysisDate = new Date();
when(project.getAnalysisDate()).thenReturn(analysisDate);
@@ -216,18 +200,17 @@ public class ModuleIssuesTest {
@Test
public void add_deprecated_violation() throws Exception {
- Rule rule = SQUID_RULE;
+ ruleBuilder.add(SQUID_RULE_KEY).setName(SQUID_RULE_NAME);
+ activeRulesBuilder.activate(SQUID_RULE_KEY).setSeverity(Severity.INFO);
+ initModuleIssues();
+
+ org.sonar.api.rules.Rule rule = org.sonar.api.rules.Rule.create("squid", "AvoidCycle", "Avoid Cycle");
Resource resource = new JavaFile("org.struts.Action").setEffectiveKey("struts:org.struts.Action");
Violation violation = new Violation(rule, resource);
violation.setLineId(42);
violation.setSeverity(RulePriority.CRITICAL);
violation.setMessage("the message");
- ActiveRule activeRule = mock(ActiveRule.class);
- when(activeRule.getRule()).thenReturn(rule);
- when(activeRule.getSeverity()).thenReturn(RulePriority.INFO);
- when(qProfile.getActiveRule("squid", "AvoidCycle")).thenReturn(activeRule);
- when(ruleFinder.findByKey(SQUID_RULE_KEY)).thenReturn(rule);
when(filters.accept(any(DefaultIssue.class), eq(violation))).thenReturn(true);
boolean added = moduleIssues.initAndAddViolation(violation);
@@ -241,17 +224,14 @@ public class ModuleIssuesTest {
assertThat(issue.message()).isEqualTo("the message");
assertThat(issue.key()).isNotEmpty();
assertThat(issue.ruleKey().toString()).isEqualTo("squid:AvoidCycle");
- assertThat(issue.componentKey().toString()).isEqualTo("struts:org.struts.Action");
+ assertThat(issue.componentKey()).isEqualTo("struts:org.struts.Action");
}
@Test
public void filter_issue() throws Exception {
- Rule rule = SQUID_RULE;
- ActiveRule activeRule = mock(ActiveRule.class);
- when(activeRule.getRule()).thenReturn(rule);
- when(activeRule.getSeverity()).thenReturn(RulePriority.INFO);
- when(qProfile.getActiveRule("squid", "AvoidCycle")).thenReturn(activeRule);
- when(ruleFinder.findByKey(SQUID_RULE_KEY)).thenReturn(rule);
+ ruleBuilder.add(SQUID_RULE_KEY).setName(SQUID_RULE_NAME);
+ activeRulesBuilder.activate(SQUID_RULE_KEY).setSeverity(Severity.INFO);
+ initModuleIssues();
DefaultIssue issue = new DefaultIssue()
.setKey("ABCDE")
@@ -267,13 +247,14 @@ public class ModuleIssuesTest {
}
@Test
- public void set_remediation_cost() throws Exception {
- Rule rule = SQUID_RULE;
- ActiveRule activeRule = mock(ActiveRule.class);
- when(activeRule.getRule()).thenReturn(rule);
- when(activeRule.getSeverity()).thenReturn(RulePriority.INFO);
- when(qProfile.getActiveRule("squid", "AvoidCycle")).thenReturn(activeRule);
- when(ruleFinder.findByKey(SQUID_RULE_KEY)).thenReturn(rule);
+ public void set_debt_with_linear_function() throws Exception {
+ ruleBuilder.add(SQUID_RULE_KEY)
+ .setName(SQUID_RULE_NAME)
+ .setCharacteristic("COMPILER_RELATED_PORTABILITY")
+ .setFunction(RemediationFunction.LINEAR)
+ .setFactor(Duration.create(10L));
+ activeRulesBuilder.activate(SQUID_RULE_KEY).setSeverity(Severity.INFO);
+ initModuleIssues();
Date analysisDate = new Date();
when(project.getAnalysisDate()).thenReturn(analysisDate);
@@ -281,17 +262,104 @@ public class ModuleIssuesTest {
DefaultIssue issue = new DefaultIssue()
.setKey("ABCDE")
.setRuleKey(SQUID_RULE_KEY)
- .setSeverity(Severity.CRITICAL);
+ .setSeverity(Severity.CRITICAL)
+ .setEffortToFix(2d);
+
+ when(filters.accept(issue, null)).thenReturn(true);
+ moduleIssues.initAndAddIssue(issue);
+
+ ArgumentCaptor<DefaultIssue> argument = ArgumentCaptor.forClass(DefaultIssue.class);
+ verify(cache).put(argument.capture());
+ assertThat(argument.getValue().debt()).isEqualTo(Duration.create(20L));
+ }
+
+ @Test
+ public void set_debt_with_linear_with_offset_function() throws Exception {
+ ruleBuilder.add(SQUID_RULE_KEY)
+ .setName(SQUID_RULE_NAME)
+ .setCharacteristic("COMPILER_RELATED_PORTABILITY")
+ .setFunction(RemediationFunction.LINEAR_OFFSET)
+ .setFactor(Duration.create(10L))
+ .setOffset(Duration.create(25L));
+ activeRulesBuilder.activate(SQUID_RULE_KEY).setSeverity(Severity.INFO);
+ initModuleIssues();
+
+ Date analysisDate = new Date();
+ when(project.getAnalysisDate()).thenReturn(analysisDate);
+
+ DefaultIssue issue = new DefaultIssue()
+ .setKey("ABCDE")
+ .setRuleKey(SQUID_RULE_KEY)
+ .setSeverity(Severity.CRITICAL)
+ .setEffortToFix(2d);
- Long debt = 10L;
- when(technicalDebtCalculator.calculateTechnicalDebt(issue.ruleKey(), issue.effortToFix())).thenReturn(debt);
when(filters.accept(issue, null)).thenReturn(true);
+ moduleIssues.initAndAddIssue(issue);
+
+ ArgumentCaptor<DefaultIssue> argument = ArgumentCaptor.forClass(DefaultIssue.class);
+ verify(cache).put(argument.capture());
+ assertThat(argument.getValue().debt()).isEqualTo(Duration.create(45L));
+ }
+
+ @Test
+ public void set_debt_with_constant_issue_function() throws Exception {
+ ruleBuilder.add(SQUID_RULE_KEY)
+ .setName(SQUID_RULE_NAME)
+ .setCharacteristic("COMPILER_RELATED_PORTABILITY")
+ .setFunction(RemediationFunction.CONSTANT_ISSUE)
+ .setOffset(Duration.create(10L));
+ activeRulesBuilder.activate(SQUID_RULE_KEY).setSeverity(Severity.INFO);
+ initModuleIssues();
+
+ Date analysisDate = new Date();
+ when(project.getAnalysisDate()).thenReturn(analysisDate);
+ DefaultIssue issue = new DefaultIssue()
+ .setKey("ABCDE")
+ .setRuleKey(SQUID_RULE_KEY)
+ .setSeverity(Severity.CRITICAL)
+ .setEffortToFix(null);
+
+ when(filters.accept(issue, null)).thenReturn(true);
moduleIssues.initAndAddIssue(issue);
ArgumentCaptor<DefaultIssue> argument = ArgumentCaptor.forClass(DefaultIssue.class);
verify(cache).put(argument.capture());
- assertThat(argument.getValue().debt()).isEqualTo(Duration.create(debt));
+ assertThat(argument.getValue().debt()).isEqualTo(Duration.create(10L));
+ }
+
+ @Test
+ public void fail_to_set_debt_with_constant_issue_function_when_effort_to_fix_is_set() throws Exception {
+ ruleBuilder.add(SQUID_RULE_KEY)
+ .setName(SQUID_RULE_NAME)
+ .setCharacteristic("COMPILER_RELATED_PORTABILITY")
+ .setFunction(RemediationFunction.CONSTANT_ISSUE)
+ .setOffset(Duration.create(25L));
+ activeRulesBuilder.activate(SQUID_RULE_KEY).setSeverity(Severity.INFO);
+ initModuleIssues();
+
+ DefaultIssue issue = new DefaultIssue()
+ .setKey("ABCDE")
+ .setRuleKey(SQUID_RULE_KEY)
+ .setSeverity(Severity.CRITICAL)
+ .setEffortToFix(2d);
+
+ when(filters.accept(issue, null)).thenReturn(true);
+
+ try {
+ moduleIssues.initAndAddIssue(issue);
+ fail();
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Rule 'squid:AvoidCycle' can not use 'Constant/issue' remediation function because this rule does not have a fixed remediation cost.");
+ }
+ }
+
+ /**
+ * Every rules and active rules has to be added in builders before creating ModuleIssues
+ */
+ private void initModuleIssues() {
+ moduleIssues = new ModuleIssues(activeRulesBuilder.build(), ruleBuilder.build(), cache, project, filters);
}
}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/rule/RulesProviderTest.java b/sonar-batch/src/test/java/org/sonar/batch/rule/RulesProviderTest.java
new file mode 100644
index 00000000000..dc5d9b9e6e9
--- /dev/null
+++ b/sonar-batch/src/test/java/org/sonar/batch/rule/RulesProviderTest.java
@@ -0,0 +1,170 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.batch.rule;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.sonar.api.batch.rule.Rule;
+import org.sonar.api.batch.rule.RuleParam;
+import org.sonar.api.batch.rule.Rules;
+import org.sonar.api.config.Settings;
+import org.sonar.api.rule.RemediationFunction;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rule.Severity;
+import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
+import org.sonar.api.utils.Duration;
+import org.sonar.api.utils.Durations;
+import org.sonar.core.persistence.AbstractDaoTestCase;
+import org.sonar.core.rule.RuleDao;
+import org.sonar.core.technicaldebt.DefaultTechnicalDebtModel;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.fest.assertions.Fail.fail;
+
+@RunWith(MockitoJUnitRunner.class)
+public class RulesProviderTest extends AbstractDaoTestCase {
+
+ @Mock
+ Durations durations;
+
+ RuleDao ruleDao;
+
+ DefaultTechnicalDebtModel debtModel;
+
+ RulesProvider provider;
+
+ @Before
+ public void setUp() throws Exception {
+ debtModel = new DefaultTechnicalDebtModel();
+ debtModel.addRootCharacteristic(new DefaultCharacteristic()
+ .setId(101)
+ .setKey("EFFICIENCY")
+ .setName("Efficiency")
+ .setParent(new DefaultCharacteristic()
+ .setId(100)
+ .setKey("MEMORY_EFFICIENCY")
+ .setName("Memory use")));
+ debtModel.addRootCharacteristic(new DefaultCharacteristic()
+ .setId(103)
+ .setKey("PORTABILITY")
+ .setName("Portability")
+ .setParent(new DefaultCharacteristic()
+ .setId(102)
+ .setKey("COMPILER_RELATED_PORTABILITY")
+ .setName("Compiler")));
+
+ durations = new Durations(new Settings().setProperty("sonar.technicalDebt.hoursInDay", 8), null);
+ ruleDao = new RuleDao(getMyBatis());
+
+ provider = new RulesProvider();
+ }
+
+ @Test
+ public void build_rules() throws Exception {
+ setupData("shared");
+
+ Rules rules = provider.provide(ruleDao, debtModel, durations);
+
+ assertThat(rules.findAll()).hasSize(1);
+ assertThat(rules.findByRepository("checkstyle")).hasSize(1);
+ assertThat(rules.findByRepository("unknown")).isEmpty();
+
+ Rule rule = rules.find(RuleKey.of("checkstyle", "AvoidNull"));
+ assertThat(rule).isNotNull();
+ assertThat(rule.key()).isEqualTo(RuleKey.of("checkstyle", "AvoidNull"));
+ assertThat(rule.name()).isEqualTo("Avoid Null");
+ assertThat(rule.description()).isEqualTo("Should avoid NULL");
+ assertThat(rule.severity()).isEqualTo(Severity.MINOR);
+ assertThat(rule.metadata()).isNull();
+ assertThat(rule.params()).hasSize(1);
+
+ RuleParam param = rule.param("myParameter");
+ assertThat(param).isNotNull();
+ assertThat(param.description()).isEqualTo("My Parameter");
+ }
+
+ @Test
+ public void build_rules_with_default_debt_definitions() throws Exception {
+ setupData("build_rules_with_default_debt_definitions");
+
+ Rules rules = provider.provide(ruleDao, debtModel, durations);
+
+ Rule rule = rules.find(RuleKey.of("checkstyle", "AvoidNull"));
+ assertThat(rule.characteristic()).isEqualTo("EFFICIENCY");
+ assertThat(rule.function()).isEqualTo(RemediationFunction.LINEAR_OFFSET);
+ assertThat(rule.factor()).isEqualTo(Duration.decode("5d", 8));
+ assertThat(rule.offset()).isEqualTo(Duration.decode("10h", 8));
+ }
+
+ @Test
+ public void build_rules_with_user_debt_definitions() throws Exception {
+ setupData("build_rules_with_user_debt_definitions");
+
+ Rules rules = provider.provide(ruleDao, debtModel, durations);
+
+ Rule rule = rules.find(RuleKey.of("checkstyle", "AvoidNull"));
+ assertThat(rule.characteristic()).isEqualTo("PORTABILITY");
+ assertThat(rule.function()).isEqualTo(RemediationFunction.LINEAR);
+ assertThat(rule.factor()).isEqualTo(Duration.decode("2h", 8));
+ assertThat(rule.offset()).isNull();
+ }
+
+ @Test
+ public void build_rules_with_default_and_user_debt_definitions() throws Exception {
+ setupData("build_rules_with_default_and_user_debt_definitions");
+
+ Rules rules = provider.provide(ruleDao, debtModel, durations);
+
+ // As both default columns and user columns on debt are set, user debt columns should be used
+ Rule rule = rules.find(RuleKey.of("checkstyle", "AvoidNull"));
+ assertThat(rule.characteristic()).isEqualTo("PORTABILITY");
+ assertThat(rule.function()).isEqualTo(RemediationFunction.LINEAR);
+ assertThat(rule.factor()).isEqualTo(Duration.decode("2h", 8));
+ assertThat(rule.offset()).isNull();
+ }
+
+ @Test
+ public void fail_if_characteristic_not_found() throws Exception {
+ setupData("fail_if_characteristic_not_found");
+
+ try {
+ provider.provide(ruleDao, debtModel, durations);
+ fail();
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(IllegalStateException.class).hasMessage("Characteristic id '999' on rule 'checkstyle:AvoidNull' has not been found");
+ }
+ }
+
+ @Test
+ public void fail_if_no_function() throws Exception {
+ setupData("fail_if_no_function");
+
+ try {
+ provider.provide(ruleDao, debtModel, durations);
+ fail();
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(IllegalStateException.class).hasMessage("Remediation function should not be null on rule 'checkstyle:AvoidNull'");
+ }
+ }
+}