summaryrefslogtreecommitdiffstats
path: root/sonar-server
diff options
context:
space:
mode:
authorJulien Lancelot <julien.lancelot@sonarsource.com>2014-06-11 18:53:57 +0200
committerJulien Lancelot <julien.lancelot@sonarsource.com>2014-06-11 18:54:07 +0200
commit959cb697cf777b944557cf7d03b02eeab282d634 (patch)
treedf76c85f8cd3f6d6076da63d8026f74d3f6ca47b /sonar-server
parent96f308ca2d5542d273b5b0e9e57df9f0da73c9c2 (diff)
downloadsonarqube-959cb697cf777b944557cf7d03b02eeab282d634.tar.gz
sonarqube-959cb697cf777b944557cf7d03b02eeab282d634.zip
SONAR-5392 When migrating to SonarQube 4.3.X with a incompatible plugin, requirements are not copied to rules
Diffstat (limited to 'sonar-server')
-rw-r--r--sonar-server/src/main/java/org/sonar/server/startup/CopyRequirementsFromCharacteristicsToRules.java87
-rw-r--r--sonar-server/src/test/java/org/sonar/server/startup/CopyRequirementsFromCharacteristicsToRulesTest.java31
-rw-r--r--sonar-server/src/test/resources/org/sonar/server/startup/CopyRequirementsFromCharacteristicsToRulesTest/copy_requirements_from_characteristics_to_rules_result.xml2
-rw-r--r--sonar-server/src/test/resources/org/sonar/server/startup/CopyRequirementsFromCharacteristicsToRulesTest/do_nothing_when_already_executed.xml137
-rw-r--r--sonar-server/src/test/resources/org/sonar/server/startup/CopyRequirementsFromCharacteristicsToRulesTest/do_nothing_when_already_executed_result.xml134
5 files changed, 336 insertions, 55 deletions
diff --git a/sonar-server/src/main/java/org/sonar/server/startup/CopyRequirementsFromCharacteristicsToRules.java b/sonar-server/src/main/java/org/sonar/server/startup/CopyRequirementsFromCharacteristicsToRules.java
index 02024698f0d..10ddce7b90f 100644
--- a/sonar-server/src/main/java/org/sonar/server/startup/CopyRequirementsFromCharacteristicsToRules.java
+++ b/sonar-server/src/main/java/org/sonar/server/startup/CopyRequirementsFromCharacteristicsToRules.java
@@ -29,15 +29,14 @@ import org.apache.commons.lang.builder.EqualsBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.ServerComponent;
-import org.sonar.api.platform.ServerUpgradeStatus;
import org.sonar.api.rule.RuleStatus;
-import org.sonar.api.rules.Rule;
import org.sonar.api.server.debt.DebtRemediationFunction;
import org.sonar.api.utils.Duration;
import org.sonar.core.persistence.DbSession;
import org.sonar.core.persistence.MyBatis;
import org.sonar.core.rule.RuleDto;
import org.sonar.core.technicaldebt.db.CharacteristicMapper;
+import org.sonar.core.template.LoadedTemplateDto;
import org.sonar.server.db.DbClient;
import org.sonar.server.rule.RegisterRules;
@@ -60,29 +59,31 @@ public class CopyRequirementsFromCharacteristicsToRules implements ServerCompone
private static final Logger LOGGER = LoggerFactory.getLogger(CopyRequirementsFromCharacteristicsToRules.class);
+ private static final String TEMPLATE_KEY = "CopyRequirementsFromCharacteristicsToRules";
+
private final DbClient dbClient;
- private final ServerUpgradeStatus status;
/**
* @param registerRules used only to be started after init of rules
*/
- public CopyRequirementsFromCharacteristicsToRules(DbClient dbClient, ServerUpgradeStatus status, RegisterRules registerRules) {
+ public CopyRequirementsFromCharacteristicsToRules(DbClient dbClient, RegisterRules registerRules) {
this.dbClient = dbClient;
- this.status = status;
}
public void start() {
- if (status.isUpgraded() && status.getInitialDbVersion() <= 520) {
- doExecute();
- }
+ doExecute();
}
private void doExecute() {
- LOGGER.info("Copying requirement from characteristics to rules");
- copyRequirementsFromCharacteristicsToRules();
+ if (dbClient.loadedTemplateDao().countByTypeAndKey(LoadedTemplateDto.ONE_SHOT_TASK_TYPE, TEMPLATE_KEY) == 0) {
+ LOGGER.info("Copying requirement from characteristics to rules");
+ copyRequirementsFromCharacteristicsToRules();
+
+ LOGGER.info("Deleting requirements from characteristics");
+ removeRequirementsDataFromCharacteristics();
- LOGGER.info("Deleting requirements data");
- removeRequirementsDataFromCharacteristics();
+ dbClient.loadedTemplateDao().insert(new LoadedTemplateDto(TEMPLATE_KEY, LoadedTemplateDto.ONE_SHOT_TASK_TYPE));
+ }
}
private void copyRequirementsFromCharacteristicsToRules() {
@@ -90,20 +91,30 @@ public class CopyRequirementsFromCharacteristicsToRules implements ServerCompone
try {
List<Map<String, Object>> requirementDtos = dbSession.getMapper(CharacteristicMapper.class).selectDeprecatedRequirements();
- final Multimap<Number, RequirementDto> requirementsByRuleId = ArrayListMultimap.create();
- for (Map<String, Object> map : requirementDtos) {
- RequirementDto requirementDto = new RequirementDto(map);
- requirementsByRuleId.put(requirementDto.getRuleId(), requirementDto);
- }
+ if (requirementDtos.isEmpty()) {
+ LOGGER.info("No requirement will be copied", requirementDtos);
+
+ } else {
+ int requirementCopied = 0;
- List<RuleDto> rules = dbClient.ruleDao().findAll(dbSession);
- for (RuleDto rule : rules) {
- Collection<RequirementDto> requirementsForRule = requirementsByRuleId.get(rule.getId());
- if (!requirementsForRule.isEmpty()) {
- convert(rule, requirementsForRule, dbSession);
+ final Multimap<Number, RequirementDto> requirementsByRuleId = ArrayListMultimap.create();
+ for (Map<String, Object> map : requirementDtos) {
+ RequirementDto requirementDto = new RequirementDto(map);
+ requirementsByRuleId.put(requirementDto.getRuleId(), requirementDto);
}
+
+ List<RuleDto> rules = dbClient.ruleDao().findAll(dbSession);
+ for (RuleDto rule : rules) {
+ Collection<RequirementDto> requirementsForRule = requirementsByRuleId.get(rule.getId());
+ if (!requirementsForRule.isEmpty()) {
+ convert(rule, requirementsForRule, dbSession);
+ requirementCopied++;
+ }
+ }
+ dbSession.commit();
+
+ LOGGER.info("{} requirements have been found, {} have be copied", requirementDtos.size(), requirementCopied);
}
- dbSession.commit();
} finally {
MyBatis.closeQuietly(dbSession);
}
@@ -174,10 +185,10 @@ public class CopyRequirementsFromCharacteristicsToRules implements ServerCompone
@CheckForNull
@VisibleForTesting
- static String convertDuration(@Nullable Double oldValue, @Nullable String oldUnit) {
- if (oldValue != null && oldValue > 0) {
+ static String convertDuration(@Nullable Number oldValue, @Nullable String oldUnit) {
+ if (oldValue != null && oldValue.doubleValue() > 0) {
// As value is stored in double, we have to round it in order to have an integer (for instance, if it was 1.6, we'll use 2)
- return Integer.toString((int) Math.round(oldValue)) + convertUnit(oldUnit);
+ return Integer.toString((int) Math.round(oldValue.doubleValue())) + convertUnit(oldUnit);
}
return null;
}
@@ -220,55 +231,53 @@ public class CopyRequirementsFromCharacteristicsToRules implements ServerCompone
* Do not use Integer because Oracle returns BigDecimal
*/
public Number getId() {
- return (Number) map.get("ID");
+ return (Number) map.get("id");
}
/**
* Do not use Integer because Oracle returns BigDecimal
*/
public Number getParentId() {
- return (Number) map.get("PARENTID");
+ return (Number) map.get("parentId");
}
/**
* Do not use Integer because Oracle returns BigDecimal
*/
public Number getRuleId() {
- return (Number) map.get("RULEID");
+ return (Number) map.get("ruleId");
}
public String getFunction() {
- return (String) map.get("FUNCTIONKEY");
+ return (String) map.get("functionKey");
}
@CheckForNull
- public Double getCoefficientValue() {
- return (Double) map.get("COEFFICIENTVALUE");
+ public Number getCoefficientValue() {
+ return (Number) map.get("coefficientValue");
}
@CheckForNull
public String getCoefficientUnit() {
- return (String) map.get("COEFFICIENTUNIT");
+ return (String) map.get("coefficientUnit");
}
@CheckForNull
- public Double getOffsetValue() {
- return (Double) map.get("OFFSETVALUE");
+ public Number getOffsetValue() {
+ return (Number) map.get("offsetValue");
}
@CheckForNull
public String getOffsetUnit() {
- return (String) map.get("OFFSETUNIT");
+ return (String) map.get("offsetUnit");
}
public boolean isEnabled() {
- return (Boolean) map.get("ENABLED");
+ return (Boolean) map.get("enabled");
}
-
-
}
}
diff --git a/sonar-server/src/test/java/org/sonar/server/startup/CopyRequirementsFromCharacteristicsToRulesTest.java b/sonar-server/src/test/java/org/sonar/server/startup/CopyRequirementsFromCharacteristicsToRulesTest.java
index 9c7cfbeeaa6..ac7dcd807dc 100644
--- a/sonar-server/src/test/java/org/sonar/server/startup/CopyRequirementsFromCharacteristicsToRulesTest.java
+++ b/sonar-server/src/test/java/org/sonar/server/startup/CopyRequirementsFromCharacteristicsToRulesTest.java
@@ -25,11 +25,11 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
-import org.sonar.api.platform.ServerUpgradeStatus;
import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.System2;
import org.sonar.core.persistence.TestDatabase;
import org.sonar.core.rule.RuleDto;
+import org.sonar.core.template.LoadedTemplateDao;
import org.sonar.server.db.DbClient;
import org.sonar.server.rule.db.RuleDao;
@@ -43,30 +43,26 @@ public class CopyRequirementsFromCharacteristicsToRulesTest {
public static TestDatabase db = new TestDatabase();
@Mock
- ServerUpgradeStatus status;
-
- @Mock
System2 system2;
+ DbClient dbClient;
+
CopyRequirementsFromCharacteristicsToRules service;
@Before
public void setUp() throws Exception {
when(system2.now()).thenReturn(DateUtils.parseDate("2014-03-13").getTime());
- DbClient dbClient = new DbClient(db.database(), db.myBatis(), new RuleDao(system2));
- service = new CopyRequirementsFromCharacteristicsToRules(dbClient, status, null);
+ dbClient = new DbClient(db.database(), db.myBatis(), new RuleDao(system2), new LoadedTemplateDao(db.myBatis()));
+ service = new CopyRequirementsFromCharacteristicsToRules(dbClient, null);
}
@Test
public void copy_requirements_from_characteristics_to_rules() throws Exception {
db.prepareDbUnit(getClass(), "copy_requirements_from_characteristics_to_rules.xml");
- when(status.isUpgraded()).thenReturn(true);
- when(status.getInitialDbVersion()).thenReturn(498);
-
service.start();
- db.assertDbUnit(getClass(), "copy_requirements_from_characteristics_to_rules_result.xml", "rules");
+ db.assertDbUnit(getClass(), "copy_requirements_from_characteristics_to_rules_result.xml", "rules", "loaded_templates");
}
/**
@@ -76,9 +72,6 @@ public class CopyRequirementsFromCharacteristicsToRulesTest {
public void convert_constant_issue_with_coeff_to_constant_issue_with_offset() throws Exception {
db.prepareDbUnit(getClass(), "convert_constant_issue_with_coeff_to_constant_issue_with_offset.xml");
- when(status.isUpgraded()).thenReturn(true);
- when(status.getInitialDbVersion()).thenReturn(498);
-
service.start();
db.assertDbUnit(getClass(), "convert_constant_issue_with_coeff_to_constant_issue_with_offset_result.xml", "rules");
@@ -88,15 +81,21 @@ public class CopyRequirementsFromCharacteristicsToRulesTest {
public void remove_requirements_data_from_characteristics() throws Exception {
db.prepareDbUnit(getClass(), "remove_requirements_data_from_characteristics.xml");
- when(status.isUpgraded()).thenReturn(true);
- when(status.getInitialDbVersion()).thenReturn(498);
-
service.start();
db.assertDbUnit(getClass(), "remove_requirements_data_from_characteristics_result.xml", "characteristics");
}
@Test
+ public void do_nothing_when_already_executed() throws Exception {
+ db.prepareDbUnit(getClass(), "do_nothing_when_already_executed.xml");
+
+ service.start();
+
+ db.assertDbUnit(getClass(), "do_nothing_when_already_executed_result.xml", "rules");
+ }
+
+ @Test
public void convert_duration() throws Exception {
assertThat(CopyRequirementsFromCharacteristicsToRules.convertDuration(1.0, "h")).isEqualTo("1h");
assertThat(CopyRequirementsFromCharacteristicsToRules.convertDuration(15.0, "d")).isEqualTo("15d");
diff --git a/sonar-server/src/test/resources/org/sonar/server/startup/CopyRequirementsFromCharacteristicsToRulesTest/copy_requirements_from_characteristics_to_rules_result.xml b/sonar-server/src/test/resources/org/sonar/server/startup/CopyRequirementsFromCharacteristicsToRulesTest/copy_requirements_from_characteristics_to_rules_result.xml
index 9fe876218ab..bc8c7c6d925 100644
--- a/sonar-server/src/test/resources/org/sonar/server/startup/CopyRequirementsFromCharacteristicsToRulesTest/copy_requirements_from_characteristics_to_rules_result.xml
+++ b/sonar-server/src/test/resources/org/sonar/server/startup/CopyRequirementsFromCharacteristicsToRulesTest/copy_requirements_from_characteristics_to_rules_result.xml
@@ -73,4 +73,6 @@
remediation_offset="[null]" default_remediation_offset="[null]" updated_at="2014-03-13"
NOTE_CREATED_AT="[null]" NOTE_DATA="[null]" NOTE_UPDATED_AT="[null]" NOTE_USER_LOGIN="[null]" PARENT_ID="[null]" PLUGIN_CONFIG_KEY="[null]" PRIORITY="[null]" cardinality="[null]" created_at="[null]" language="[null]" effort_to_fix_description="[null]"/>
+ <loaded_templates id="1" kee="CopyRequirementsFromCharacteristicsToRules" template_type="ONE_SHOT_TASK"/>
+
</dataset>
diff --git a/sonar-server/src/test/resources/org/sonar/server/startup/CopyRequirementsFromCharacteristicsToRulesTest/do_nothing_when_already_executed.xml b/sonar-server/src/test/resources/org/sonar/server/startup/CopyRequirementsFromCharacteristicsToRulesTest/do_nothing_when_already_executed.xml
new file mode 100644
index 00000000000..ec71824d7b8
--- /dev/null
+++ b/sonar-server/src/test/resources/org/sonar/server/startup/CopyRequirementsFromCharacteristicsToRulesTest/do_nothing_when_already_executed.xml
@@ -0,0 +1,137 @@
+<dataset>
+
+ <!-- Loaded template already existing, nothing should be done -->
+ <loaded_templates id="1" kee="CopyRequirementsFromCharacteristicsToRules" template_type="ONE_SHOT_TASK"/>
+
+ <!-- Rule not linked to a requirement -> Nothing to do -->
+ <rules tags="[null]" system_tags="[null]" id="1" plugin_rule_key="UselessImportCheck" plugin_name="squid" name="UselessImportCheck" description="Useless imports should be removed" status="READY"
+ characteristic_id="[null]" default_characteristic_id="10"
+ remediation_function="[null]" default_remediation_function="LINEAR_OFFSET"
+ remediation_coeff="[null]" default_remediation_coeff="5d"
+ remediation_offset="[null]" default_remediation_offset="10h" updated_at="2014-02-19"
+ NOTE_CREATED_AT="[null]" NOTE_DATA="[null]" NOTE_UPDATED_AT="[null]" NOTE_USER_LOGIN="[null]" PARENT_ID="[null]" PLUGIN_CONFIG_KEY="[null]" PRIORITY="[null]"
+ cardinality="[null]" created_at="[null]" language="[null]" effort_to_fix_description="[null]"/>
+
+ <!-- Rule linked to a disabled requirement -> Update rule to disable characteristic -->
+ <rules tags="[null]" system_tags="[null]" id="2" plugin_rule_key="LeftCurlyBraceStartLineCheck" plugin_name="squid" name="LeftCurlyBraceStartLineCheck" description="Left curly braces should be located at the beginning of lines of code" status="READY"
+ characteristic_id="[null]" default_characteristic_id="10"
+ remediation_function="[null]" default_remediation_function="LINEAR_OFFSET"
+ remediation_coeff="[null]" default_remediation_coeff="5d"
+ remediation_offset="[null]" default_remediation_offset="10h" updated_at="2014-02-19"
+ NOTE_CREATED_AT="[null]" NOTE_DATA="[null]" NOTE_UPDATED_AT="[null]" NOTE_USER_LOGIN="[null]" PARENT_ID="[null]" PLUGIN_CONFIG_KEY="[null]" PRIORITY="[null]" cardinality="[null]" created_at="[null]" language="[null]" effort_to_fix_description="[null]"/>
+
+ <!-- Removed rule linked to a disabled requirement -> Do nothing -->
+ <rules tags="[null]" system_tags="[null]" id="3" plugin_rule_key="CallToFileDeleteOnExitMethod" plugin_name="squid" name="CallToFileDeleteOnExitMethod" description="CallToFileDeleteOnExitMethod" status="REMOVED"
+ characteristic_id="[null]" default_characteristic_id="10"
+ remediation_function="[null]" default_remediation_function="LINEAR_OFFSET"
+ remediation_coeff="[null]" default_remediation_coeff="5d"
+ remediation_offset="[null]" default_remediation_offset="10h" updated_at="2014-02-19"
+ NOTE_CREATED_AT="[null]" NOTE_DATA="[null]" NOTE_UPDATED_AT="[null]" NOTE_USER_LOGIN="[null]" PARENT_ID="[null]" PLUGIN_CONFIG_KEY="[null]" PRIORITY="[null]" cardinality="[null]" created_at="[null]" language="[null]" effort_to_fix_description="[null]"/>
+
+ <!-- Rule linked to one enable requirement="[null]" with same value of debt -> Nothing to do -->
+ <rules tags="[null]" system_tags="[null]" id="4" plugin_rule_key="ObjectFinalizeOverridenCallsSuperFinalizeCheck" plugin_name="squid" name="ObjectFinalizeOverridenCallsSuperFinalizeCheck" description="super.finalize() should be called at the end of Object.finalize() implementations" status="READY"
+ characteristic_id="[null]" default_characteristic_id="10"
+ remediation_function="[null]" default_remediation_function="LINEAR_OFFSET"
+ remediation_coeff="[null]" default_remediation_coeff="5min"
+ remediation_offset="[null]" default_remediation_offset="10h" updated_at="2014-02-19"
+ NOTE_CREATED_AT="[null]" NOTE_DATA="[null]" NOTE_UPDATED_AT="[null]" NOTE_USER_LOGIN="[null]" PARENT_ID="[null]" PLUGIN_CONFIG_KEY="[null]" PRIORITY="[null]" cardinality="[null]" created_at="[null]" language="[null]" effort_to_fix_description="[null]"/>
+
+ <!-- Rule linked to one enable requirement="[null]" with different value of debt -> Update rule -->
+ <rules tags="[null]" system_tags="[null]" id="5" plugin_rule_key="RightCurlyBraceStartLineCheck" plugin_name="squid" name="RightCurlyBraceStartLineCheck" description="Right curly braces should be located at the beginning of lines of code" status="READY"
+ characteristic_id="[null]" default_characteristic_id="20"
+ remediation_function="[null]" default_remediation_function="LINEAR"
+ remediation_coeff="[null]" default_remediation_coeff="5d"
+ remediation_offset="[null]" default_remediation_offset="[null]" updated_at="2014-02-19"
+ NOTE_CREATED_AT="[null]" NOTE_DATA="[null]" NOTE_UPDATED_AT="[null]" NOTE_USER_LOGIN="[null]" PARENT_ID="[null]" PLUGIN_CONFIG_KEY="[null]" PRIORITY="[null]" cardinality="[null]" created_at="[null]" language="[null]" effort_to_fix_description="[null]"/>
+
+ <!-- Rule linked to one enable requirement on Constant per issue function (with a coefficient of 0d -> to be replaced by null)="[null]" with different value of debt -> Update rule -->
+ <rules tags="[null]" system_tags="[null]" id="6" plugin_rule_key="HiddenFieldCheck" plugin_name="squid" name="HiddenFieldCheck" description="HiddenFieldCheck" status="READY"
+ characteristic_id="[null]" default_characteristic_id="20"
+ remediation_function="[null]" default_remediation_function="LINEAR"
+ remediation_coeff="[null]" default_remediation_coeff="5d"
+ remediation_offset="[null]" default_remediation_offset="[null]" updated_at="2014-02-19"
+ NOTE_CREATED_AT="[null]" NOTE_DATA="[null]" NOTE_UPDATED_AT="[null]" NOTE_USER_LOGIN="[null]" PARENT_ID="[null]" PLUGIN_CONFIG_KEY="[null]" PRIORITY="[null]" cardinality="[null]" created_at="[null]" language="[null]" effort_to_fix_description="[null]"/>
+
+ <!-- Rule linked to one enable requirement on Linear function (with a coefficient of 0min -> to be replaced by null)="[null]" with different value of debt -> Update rule -->
+ <rules tags="[null]" system_tags="[null]" id="7" plugin_rule_key="ForLoopCounterChangedCheck" plugin_name="squid" name="ForLoopCounterChangedCheck" description="ForLoopCounterChangedCheck" status="READY"
+ characteristic_id="[null]" default_characteristic_id="20"
+ remediation_function="[null]" default_remediation_function="LINEAR"
+ remediation_coeff="[null]" default_remediation_coeff="5d"
+ remediation_offset="[null]" default_remediation_offset="[null]" updated_at="2014-02-19"
+ NOTE_CREATED_AT="[null]" NOTE_DATA="[null]" NOTE_UPDATED_AT="[null]" NOTE_USER_LOGIN="[null]" PARENT_ID="[null]" PLUGIN_CONFIG_KEY="[null]" PRIORITY="[null]" cardinality="[null]" created_at="[null]" language="[null]" effort_to_fix_description="[null]"/>
+
+ <!-- Rule linked to one enable requirement on Linear with offset function (with a offset of 0h -> should be replaced by 0d)="[null]" with different value of debt -> Update rule -->
+ <rules tags="[null]" system_tags="[null]" id="8" plugin_rule_key="ClassVariableVisibilityCheck" plugin_name="squid" name="ClassVariableVisibilityCheck" description="ClassVariableVisibilityCheck" status="READY"
+ characteristic_id="[null]" default_characteristic_id="20"
+ remediation_function="[null]" default_remediation_function="LINEAR"
+ remediation_coeff="[null]" default_remediation_coeff="5d"
+ remediation_offset="[null]" default_remediation_offset="[null" updated_at="2014-02-19"
+ NOTE_CREATED_AT="[null]" NOTE_DATA="[null]" NOTE_UPDATED_AT="[null]" NOTE_USER_LOGIN="[null]" PARENT_ID="[null]" PLUGIN_CONFIG_KEY="[null]" PRIORITY="[null]" cardinality="[null]" created_at="[null]" language="[null]" effort_to_fix_description="[null]"/>
+
+ <!-- Rule linked to one enable requirement on Linear function (with a coefficient of 0d -> should keep 0d)="[null]" with different value of debt -> Update rule -->
+ <rules tags="[null]" system_tags="[null]" id="9" plugin_rule_key="SwitchLastCaseIsDefaultCheck" plugin_name="squid" name="SwitchLastCaseIsDefaultCheck" description="SwitchLastCaseIsDefaultCheck" status="READY"
+ characteristic_id="[null]" default_characteristic_id="20"
+ remediation_function="[null]" default_remediation_function="LINEAR"
+ remediation_coeff="[null]" default_remediation_coeff="5d"
+ remediation_offset="[null]" default_remediation_offset="[null]" updated_at="2014-02-19"
+ NOTE_CREATED_AT="[null]" NOTE_DATA="[null]" NOTE_UPDATED_AT="[null]" NOTE_USER_LOGIN="[null]" PARENT_ID="[null]" PLUGIN_CONFIG_KEY="[null]" PRIORITY="[null]" cardinality="[null]" created_at="[null]" language="[null]" effort_to_fix_description="[null]"/>
+
+ <!-- No requirement for rule 1 -->
+
+ <!-- Requirements of rule 2 -->
+ <characteristics id="1" parent_id="10" rule_id="2"
+ function_key="linear_offset" factor_value="20.0" factor_unit="mn" offset_value="30.0" offset_unit="h" enabled="[false]"
+ created_at="2013-11-20" updated_at="[null]" ROOT_ID="[null]" KEE="[null]" name="[null]" characteristic_order="[null]"/>
+
+ <characteristics id="2" parent_id="10" rule_id="2"
+ function_key="linear_offset" factor_value="30.0" factor_unit="mn" offset_value="20.0" offset_unit="h" enabled="[false]"
+ created_at="2013-11-20" updated_at="2013-11-22" ROOT_ID="[null]" KEE="[null]" name="[null]" characteristic_order="[null]"/>
+
+ <!-- Requirements of rule 3 -->
+ <characteristics id="3" parent_id="10" rule_id="3"
+ function_key="linear_offset" factor_value="20.0" factor_unit="mn" offset_value="30.0" offset_unit="h" enabled="[false]"
+ created_at="2013-11-20" updated_at="[null]" ROOT_ID="[null]" KEE="[null]" name="[null]" characteristic_order="[null]"/>
+
+ <characteristics id="4" parent_id="10" rule_id="3"
+ function_key="linear_offset" factor_value="30.0" factor_unit="mn" offset_value="20.0" offset_unit="h" enabled="[false]"
+ created_at="2013-11-20" updated_at="2013-11-22" ROOT_ID="[null]" KEE="[null]" name="[null]" characteristic_order="[null]"/>
+
+ <!-- Requirements of rule 4 -->
+ <characteristics id="5" parent_id="10" rule_id="4"
+ function_key="linear_offset" factor_value="5.0" factor_unit="mn" offset_value="9.8" offset_unit="h" enabled="[true]"
+ created_at="2013-11-20" updated_at="[null]" ROOT_ID="[null]" KEE="[null]" name="[null]" characteristic_order="[null]"/>
+
+ <characteristics id="6" parent_id="10" rule_id="4"
+ function_key="linear_offset" factor_value="30.0" factor_unit="mn" offset_value="20.0" offset_unit="h" enabled="[false]"
+ created_at="2013-11-20" updated_at="2013-11-22" ROOT_ID="[null]" KEE="[null]" name="[null]" characteristic_order="[null]"/>
+
+ <!-- Requirements of rule 5 -->
+ <characteristics id="7" parent_id="10" rule_id="5"
+ function_key="linear_offset" factor_value="20.0" factor_unit="mn" offset_value="30.0" offset_unit="h" enabled="[true]"
+ created_at="2013-11-20" updated_at="[null]" ROOT_ID="[null]" KEE="[null]" name="[null]" characteristic_order="[null]"/>
+
+ <characteristics id="8" parent_id="10" rule_id="5"
+ function_key="linear_offset" factor_value="30.0" factor_unit="mn" offset_value="20.0" offset_unit="h" enabled="[false]"
+ created_at="2013-11-20" updated_at="2013-11-22" ROOT_ID="[null]" KEE="[null]" name="[null]" characteristic_order="[null]"/>
+
+ <!-- Requirements of rule 6 -->
+ <characteristics id="9" parent_id="10" rule_id="6"
+ function_key="constant_issue" factor_value="0.0" factor_unit="d" offset_value="15.0" offset_unit="mn" enabled="[true]"
+ created_at="2013-11-20" updated_at="[null]" ROOT_ID="[null]" KEE="[null]" name="[null]" characteristic_order="[null]"/>
+
+ <!-- Requirements of rule 7 -->
+ <characteristics id="10" parent_id="10" rule_id="7"
+ function_key="linear" factor_value="0.0" factor_unit="mn" offset_value="0.0" offset_unit="min" enabled="[true]"
+ created_at="2013-11-20" updated_at="[null]" ROOT_ID="[null]" KEE="[null]" name="[null]" characteristic_order="[null]"/>
+
+ <!-- Requirements of rule 8 -->
+ <characteristics id="11" parent_id="10" rule_id="8"
+ function_key="linear_offset" factor_value="5.0" factor_unit="d" offset_value="0.0" offset_unit="h" enabled="[true]"
+ created_at="2013-11-20" updated_at="[null]" ROOT_ID="[null]" KEE="[null]" name="[null]" characteristic_order="[null]"/>
+
+ <!-- Requirements of rule 9 -->
+ <characteristics id="12" parent_id="10" rule_id="9"
+ function_key="linear" factor_value="0.0" factor_unit="d" offset_value="0.0" offset_unit="h" enabled="[true]"
+ created_at="2013-11-20" updated_at="[null]" ROOT_ID="[null]" KEE="[null]" name="[null]" characteristic_order="[null]"/>
+
+</dataset>
diff --git a/sonar-server/src/test/resources/org/sonar/server/startup/CopyRequirementsFromCharacteristicsToRulesTest/do_nothing_when_already_executed_result.xml b/sonar-server/src/test/resources/org/sonar/server/startup/CopyRequirementsFromCharacteristicsToRulesTest/do_nothing_when_already_executed_result.xml
new file mode 100644
index 00000000000..594b202c4a4
--- /dev/null
+++ b/sonar-server/src/test/resources/org/sonar/server/startup/CopyRequirementsFromCharacteristicsToRulesTest/do_nothing_when_already_executed_result.xml
@@ -0,0 +1,134 @@
+<dataset>
+
+ <!-- Rule not linked to a requirement -> Nothing to do -->
+ <rules tags="[null]" system_tags="[null]" id="1" plugin_rule_key="UselessImportCheck" plugin_name="squid" name="UselessImportCheck" description="Useless imports should be removed" status="READY"
+ characteristic_id="[null]" default_characteristic_id="10"
+ remediation_function="[null]" default_remediation_function="LINEAR_OFFSET"
+ remediation_coeff="[null]" default_remediation_coeff="5d"
+ remediation_offset="[null]" default_remediation_offset="10h" updated_at="2014-02-19"
+ NOTE_CREATED_AT="[null]" NOTE_DATA="[null]" NOTE_UPDATED_AT="[null]" NOTE_USER_LOGIN="[null]" PARENT_ID="[null]" PLUGIN_CONFIG_KEY="[null]" PRIORITY="[null]"
+ cardinality="[null]" created_at="[null]" language="[null]" effort_to_fix_description="[null]"/>
+
+ <!-- Rule linked to a disabled requirement -> Update rule to disable characteristic -->
+ <rules tags="[null]" system_tags="[null]" id="2" plugin_rule_key="LeftCurlyBraceStartLineCheck" plugin_name="squid" name="LeftCurlyBraceStartLineCheck" description="Left curly braces should be located at the beginning of lines of code" status="READY"
+ characteristic_id="[null]" default_characteristic_id="10"
+ remediation_function="[null]" default_remediation_function="LINEAR_OFFSET"
+ remediation_coeff="[null]" default_remediation_coeff="5d"
+ remediation_offset="[null]" default_remediation_offset="10h" updated_at="2014-02-19"
+ NOTE_CREATED_AT="[null]" NOTE_DATA="[null]" NOTE_UPDATED_AT="[null]" NOTE_USER_LOGIN="[null]" PARENT_ID="[null]" PLUGIN_CONFIG_KEY="[null]" PRIORITY="[null]" cardinality="[null]" created_at="[null]" language="[null]" effort_to_fix_description="[null]"/>
+
+ <!-- Removed rule linked to a disabled requirement -> Do nothing -->
+ <rules tags="[null]" system_tags="[null]" id="3" plugin_rule_key="CallToFileDeleteOnExitMethod" plugin_name="squid" name="CallToFileDeleteOnExitMethod" description="CallToFileDeleteOnExitMethod" status="REMOVED"
+ characteristic_id="[null]" default_characteristic_id="10"
+ remediation_function="[null]" default_remediation_function="LINEAR_OFFSET"
+ remediation_coeff="[null]" default_remediation_coeff="5d"
+ remediation_offset="[null]" default_remediation_offset="10h" updated_at="2014-02-19"
+ NOTE_CREATED_AT="[null]" NOTE_DATA="[null]" NOTE_UPDATED_AT="[null]" NOTE_USER_LOGIN="[null]" PARENT_ID="[null]" PLUGIN_CONFIG_KEY="[null]" PRIORITY="[null]" cardinality="[null]" created_at="[null]" language="[null]" effort_to_fix_description="[null]"/>
+
+ <!-- Rule linked to one enable requirement="[null]" with same value of debt -> Nothing to do -->
+ <rules tags="[null]" system_tags="[null]" id="4" plugin_rule_key="ObjectFinalizeOverridenCallsSuperFinalizeCheck" plugin_name="squid" name="ObjectFinalizeOverridenCallsSuperFinalizeCheck" description="super.finalize() should be called at the end of Object.finalize() implementations" status="READY"
+ characteristic_id="[null]" default_characteristic_id="10"
+ remediation_function="[null]" default_remediation_function="LINEAR_OFFSET"
+ remediation_coeff="[null]" default_remediation_coeff="5min"
+ remediation_offset="[null]" default_remediation_offset="10h" updated_at="2014-02-19"
+ NOTE_CREATED_AT="[null]" NOTE_DATA="[null]" NOTE_UPDATED_AT="[null]" NOTE_USER_LOGIN="[null]" PARENT_ID="[null]" PLUGIN_CONFIG_KEY="[null]" PRIORITY="[null]" cardinality="[null]" created_at="[null]" language="[null]" effort_to_fix_description="[null]"/>
+
+ <!-- Rule linked to one enable requirement="[null]" with different value of debt -> Update rule -->
+ <rules tags="[null]" system_tags="[null]" id="5" plugin_rule_key="RightCurlyBraceStartLineCheck" plugin_name="squid" name="RightCurlyBraceStartLineCheck" description="Right curly braces should be located at the beginning of lines of code" status="READY"
+ characteristic_id="[null]" default_characteristic_id="20"
+ remediation_function="[null]" default_remediation_function="LINEAR"
+ remediation_coeff="[null]" default_remediation_coeff="5d"
+ remediation_offset="[null]" default_remediation_offset="[null]" updated_at="2014-02-19"
+ NOTE_CREATED_AT="[null]" NOTE_DATA="[null]" NOTE_UPDATED_AT="[null]" NOTE_USER_LOGIN="[null]" PARENT_ID="[null]" PLUGIN_CONFIG_KEY="[null]" PRIORITY="[null]" cardinality="[null]" created_at="[null]" language="[null]" effort_to_fix_description="[null]"/>
+
+ <!-- Rule linked to one enable requirement on Constant per issue function (with a coefficient of 0d -> to be replaced by null)="[null]" with different value of debt -> Update rule -->
+ <rules tags="[null]" system_tags="[null]" id="6" plugin_rule_key="HiddenFieldCheck" plugin_name="squid" name="HiddenFieldCheck" description="HiddenFieldCheck" status="READY"
+ characteristic_id="[null]" default_characteristic_id="20"
+ remediation_function="[null]" default_remediation_function="LINEAR"
+ remediation_coeff="[null]" default_remediation_coeff="5d"
+ remediation_offset="[null]" default_remediation_offset="[null]" updated_at="2014-02-19"
+ NOTE_CREATED_AT="[null]" NOTE_DATA="[null]" NOTE_UPDATED_AT="[null]" NOTE_USER_LOGIN="[null]" PARENT_ID="[null]" PLUGIN_CONFIG_KEY="[null]" PRIORITY="[null]" cardinality="[null]" created_at="[null]" language="[null]" effort_to_fix_description="[null]"/>
+
+ <!-- Rule linked to one enable requirement on Linear function (with a coefficient of 0min -> to be replaced by null)="[null]" with different value of debt -> Update rule -->
+ <rules tags="[null]" system_tags="[null]" id="7" plugin_rule_key="ForLoopCounterChangedCheck" plugin_name="squid" name="ForLoopCounterChangedCheck" description="ForLoopCounterChangedCheck" status="READY"
+ characteristic_id="[null]" default_characteristic_id="20"
+ remediation_function="[null]" default_remediation_function="LINEAR"
+ remediation_coeff="[null]" default_remediation_coeff="5d"
+ remediation_offset="[null]" default_remediation_offset="[null]" updated_at="2014-02-19"
+ NOTE_CREATED_AT="[null]" NOTE_DATA="[null]" NOTE_UPDATED_AT="[null]" NOTE_USER_LOGIN="[null]" PARENT_ID="[null]" PLUGIN_CONFIG_KEY="[null]" PRIORITY="[null]" cardinality="[null]" created_at="[null]" language="[null]" effort_to_fix_description="[null]"/>
+
+ <!-- Rule linked to one enable requirement on Linear with offset function (with a offset of 0h -> should be replaced by 0d)="[null]" with different value of debt -> Update rule -->
+ <rules tags="[null]" system_tags="[null]" id="8" plugin_rule_key="ClassVariableVisibilityCheck" plugin_name="squid" name="ClassVariableVisibilityCheck" description="ClassVariableVisibilityCheck" status="READY"
+ characteristic_id="[null]" default_characteristic_id="20"
+ remediation_function="[null]" default_remediation_function="LINEAR"
+ remediation_coeff="[null]" default_remediation_coeff="5d"
+ remediation_offset="[null]" default_remediation_offset="[null" updated_at="2014-02-19"
+ NOTE_CREATED_AT="[null]" NOTE_DATA="[null]" NOTE_UPDATED_AT="[null]" NOTE_USER_LOGIN="[null]" PARENT_ID="[null]" PLUGIN_CONFIG_KEY="[null]" PRIORITY="[null]" cardinality="[null]" created_at="[null]" language="[null]" effort_to_fix_description="[null]"/>
+
+ <!-- Rule linked to one enable requirement on Linear function (with a coefficient of 0d -> should keep 0d)="[null]" with different value of debt -> Update rule -->
+ <rules tags="[null]" system_tags="[null]" id="9" plugin_rule_key="SwitchLastCaseIsDefaultCheck" plugin_name="squid" name="SwitchLastCaseIsDefaultCheck" description="SwitchLastCaseIsDefaultCheck" status="READY"
+ characteristic_id="[null]" default_characteristic_id="20"
+ remediation_function="[null]" default_remediation_function="LINEAR"
+ remediation_coeff="[null]" default_remediation_coeff="5d"
+ remediation_offset="[null]" default_remediation_offset="[null]" updated_at="2014-02-19"
+ NOTE_CREATED_AT="[null]" NOTE_DATA="[null]" NOTE_UPDATED_AT="[null]" NOTE_USER_LOGIN="[null]" PARENT_ID="[null]" PLUGIN_CONFIG_KEY="[null]" PRIORITY="[null]" cardinality="[null]" created_at="[null]" language="[null]" effort_to_fix_description="[null]"/>
+
+ <!-- No requirement for rule 1 -->
+
+ <!-- Requirements of rule 2 -->
+ <characteristics id="1" parent_id="10" rule_id="2"
+ function_key="linear_offset" factor_value="20.0" factor_unit="mn" offset_value="30.0" offset_unit="h" enabled="[false]"
+ created_at="2013-11-20" updated_at="[null]" ROOT_ID="[null]" KEE="[null]" name="[null]" characteristic_order="[null]"/>
+
+ <characteristics id="2" parent_id="10" rule_id="2"
+ function_key="linear_offset" factor_value="30.0" factor_unit="mn" offset_value="20.0" offset_unit="h" enabled="[false]"
+ created_at="2013-11-20" updated_at="2013-11-22" ROOT_ID="[null]" KEE="[null]" name="[null]" characteristic_order="[null]"/>
+
+ <!-- Requirements of rule 3 -->
+ <characteristics id="3" parent_id="10" rule_id="3"
+ function_key="linear_offset" factor_value="20.0" factor_unit="mn" offset_value="30.0" offset_unit="h" enabled="[false]"
+ created_at="2013-11-20" updated_at="[null]" ROOT_ID="[null]" KEE="[null]" name="[null]" characteristic_order="[null]"/>
+
+ <characteristics id="4" parent_id="10" rule_id="3"
+ function_key="linear_offset" factor_value="30.0" factor_unit="mn" offset_value="20.0" offset_unit="h" enabled="[false]"
+ created_at="2013-11-20" updated_at="2013-11-22" ROOT_ID="[null]" KEE="[null]" name="[null]" characteristic_order="[null]"/>
+
+ <!-- Requirements of rule 4 -->
+ <characteristics id="5" parent_id="10" rule_id="4"
+ function_key="linear_offset" factor_value="5.0" factor_unit="mn" offset_value="9.8" offset_unit="h" enabled="[true]"
+ created_at="2013-11-20" updated_at="[null]" ROOT_ID="[null]" KEE="[null]" name="[null]" characteristic_order="[null]"/>
+
+ <characteristics id="6" parent_id="10" rule_id="4"
+ function_key="linear_offset" factor_value="30.0" factor_unit="mn" offset_value="20.0" offset_unit="h" enabled="[false]"
+ created_at="2013-11-20" updated_at="2013-11-22" ROOT_ID="[null]" KEE="[null]" name="[null]" characteristic_order="[null]"/>
+
+ <!-- Requirements of rule 5 -->
+ <characteristics id="7" parent_id="10" rule_id="5"
+ function_key="linear_offset" factor_value="20.0" factor_unit="mn" offset_value="30.0" offset_unit="h" enabled="[true]"
+ created_at="2013-11-20" updated_at="[null]" ROOT_ID="[null]" KEE="[null]" name="[null]" characteristic_order="[null]"/>
+
+ <characteristics id="8" parent_id="10" rule_id="5"
+ function_key="linear_offset" factor_value="30.0" factor_unit="mn" offset_value="20.0" offset_unit="h" enabled="[false]"
+ created_at="2013-11-20" updated_at="2013-11-22" ROOT_ID="[null]" KEE="[null]" name="[null]" characteristic_order="[null]"/>
+
+ <!-- Requirements of rule 6 -->
+ <characteristics id="9" parent_id="10" rule_id="6"
+ function_key="constant_issue" factor_value="0.0" factor_unit="d" offset_value="15.0" offset_unit="mn" enabled="[true]"
+ created_at="2013-11-20" updated_at="[null]" ROOT_ID="[null]" KEE="[null]" name="[null]" characteristic_order="[null]"/>
+
+ <!-- Requirements of rule 7 -->
+ <characteristics id="10" parent_id="10" rule_id="7"
+ function_key="linear" factor_value="0.0" factor_unit="mn" offset_value="0.0" offset_unit="min" enabled="[true]"
+ created_at="2013-11-20" updated_at="[null]" ROOT_ID="[null]" KEE="[null]" name="[null]" characteristic_order="[null]"/>
+
+ <!-- Requirements of rule 8 -->
+ <characteristics id="11" parent_id="10" rule_id="8"
+ function_key="linear_offset" factor_value="5.0" factor_unit="d" offset_value="0.0" offset_unit="h" enabled="[true]"
+ created_at="2013-11-20" updated_at="[null]" ROOT_ID="[null]" KEE="[null]" name="[null]" characteristic_order="[null]"/>
+
+ <!-- Requirements of rule 9 -->
+ <characteristics id="12" parent_id="10" rule_id="9"
+ function_key="linear" factor_value="0.0" factor_unit="d" offset_value="0.0" offset_unit="h" enabled="[true]"
+ created_at="2013-11-20" updated_at="[null]" ROOT_ID="[null]" KEE="[null]" name="[null]" characteristic_order="[null]"/>
+
+</dataset>