diff options
author | Julien Lancelot <julien.lancelot@sonarsource.com> | 2014-03-06 20:11:32 +0100 |
---|---|---|
committer | Julien Lancelot <julien.lancelot@sonarsource.com> | 2014-03-06 20:11:32 +0100 |
commit | 35ff7a07d5d86e2c0e6f9ce83645d1d6f34fc33a (patch) | |
tree | e9480c3bdefc4012e98c415685cd9323dd62a2a3 /sonar-server/src | |
parent | 0bfbecd3d0562f62e5e61c42579b2dce45d33a2c (diff) | |
download | sonarqube-35ff7a07d5d86e2c0e6f9ce83645d1d6f34fc33a.tar.gz sonarqube-35ff7a07d5d86e2c0e6f9ce83645d1d6f34fc33a.zip |
SONAR-5056 Synchronize rule debt definitions from plugin debt models
Diffstat (limited to 'sonar-server/src')
13 files changed, 366 insertions, 105 deletions
diff --git a/sonar-server/src/main/java/org/sonar/server/platform/Platform.java b/sonar-server/src/main/java/org/sonar/server/platform/Platform.java index 4a4f73cb465..d08ff9f9a66 100644 --- a/sonar-server/src/main/java/org/sonar/server/platform/Platform.java +++ b/sonar-server/src/main/java/org/sonar/server/platform/Platform.java @@ -63,10 +63,7 @@ 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.DefaultTechnicalDebtManager; -import org.sonar.core.technicaldebt.TechnicalDebtModelRepository; -import org.sonar.core.technicaldebt.TechnicalDebtModelSynchronizer; -import org.sonar.core.technicaldebt.TechnicalDebtXMLImporter; +import org.sonar.core.technicaldebt.*; import org.sonar.core.test.TestPlanPerspectiveLoader; import org.sonar.core.test.TestablePerspectiveLoader; import org.sonar.core.timemachine.Periods; @@ -387,8 +384,11 @@ public final class Platform { // technical debt servicesContainer.addSingleton(DebtService.class); servicesContainer.addSingleton(TechnicalDebtModelSynchronizer.class); + servicesContainer.addSingleton(DebtCharacteristicsSynchronizer.class); servicesContainer.addSingleton(TechnicalDebtModelRepository.class); servicesContainer.addSingleton(TechnicalDebtXMLImporter.class); + servicesContainer.addSingleton(RuleDebtXMLImporter.class); + servicesContainer.addSingleton(CharacteristicsXMLImporter.class); servicesContainer.addSingleton(DefaultTechnicalDebtManager.class); // source @@ -437,6 +437,7 @@ public final class Platform { startupContainer.addSingleton(RuleRegistration.class); startupContainer.addSingleton(RegisterNewProfiles.class); startupContainer.addSingleton(JdbcDriverDeployer.class); + startupContainer.addSingleton(RegisterDebtCharacteristicModel.class); startupContainer.addSingleton(RegisterTechnicalDebtModel.class); startupContainer.addSingleton(DeleteDeprecatedMeasures.class); startupContainer.addSingleton(GeneratePluginIndex.class); diff --git a/sonar-server/src/main/java/org/sonar/server/rule/DeprecatedRuleDefinitions.java b/sonar-server/src/main/java/org/sonar/server/rule/DeprecatedRuleDefinitions.java index 650aae01ff0..f96f117a034 100644 --- a/sonar-server/src/main/java/org/sonar/server/rule/DeprecatedRuleDefinitions.java +++ b/sonar-server/src/main/java/org/sonar/server/rule/DeprecatedRuleDefinitions.java @@ -19,37 +19,58 @@ */ package org.sonar.server.rule; +import com.google.common.base.Predicate; +import com.google.common.collect.Iterables; +import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; +import org.sonar.api.rule.RuleKey; import org.sonar.api.rule.RuleStatus; -import org.sonar.api.server.rule.RuleDefinitions; -import org.sonar.api.server.rule.RuleParamType; import org.sonar.api.rules.RuleParam; import org.sonar.api.rules.RuleRepository; +import org.sonar.api.server.rule.RuleDefinitions; +import org.sonar.api.server.rule.RuleParamType; import org.sonar.check.Cardinality; import org.sonar.core.i18n.RuleI18nManager; +import org.sonar.core.technicaldebt.RuleDebtXMLImporter; +import org.sonar.core.technicaldebt.TechnicalDebtModelRepository; import javax.annotation.CheckForNull; +import java.io.Reader; +import java.util.Collection; +import java.util.List; + +import static com.google.common.collect.Lists.newArrayList; + /** * Inject deprecated RuleRepository into RuleDefinitions for backward-compatibility. * * @since 4.2 */ public class DeprecatedRuleDefinitions implements RuleDefinitions { + private final RuleI18nManager i18n; private final RuleRepository[] repositories; - public DeprecatedRuleDefinitions(RuleI18nManager i18n, RuleRepository[] repositories) { + private final TechnicalDebtModelRepository languageModelFinder; + private final RuleDebtXMLImporter importer; + + public DeprecatedRuleDefinitions(RuleI18nManager i18n, RuleRepository[] repositories, TechnicalDebtModelRepository languageModelFinder, RuleDebtXMLImporter importer) { this.i18n = i18n; this.repositories = repositories; + this.languageModelFinder = languageModelFinder; + this.importer = importer; } - public DeprecatedRuleDefinitions(RuleI18nManager i18n) { - this(i18n, new RuleRepository[0]); + public DeprecatedRuleDefinitions(RuleI18nManager i18n, TechnicalDebtModelRepository languageModelFinder, RuleDebtXMLImporter importer) { + this(i18n, new RuleRepository[0], languageModelFinder, importer); } @Override public void define(Context context) { + // Load rule debt definitions from xml files provided by plugin + List<RuleDebtXMLImporter.RuleDebt> ruleDebts = loadRuleDebtList(); + for (RuleRepository repository : repositories) { // RuleRepository API does not handle difference between new and extended repositories, NewRepository newRepository; @@ -74,11 +95,22 @@ public class DeprecatedRuleDefinitions implements RuleDefinitions { newParam.setDescription(paramDescription(repository.getKey(), rule.getKey(), param)); newParam.setType(RuleParamType.parse(param.getType())); } + updateRuleDebtDefinitions(newRule, repository.getKey(), rule.getKey(), ruleDebts); } newRepository.done(); } } + private void updateRuleDebtDefinitions(NewRule newRule, String repoKey, String ruleKey, List<RuleDebtXMLImporter.RuleDebt> ruleDebts){ + RuleDebtXMLImporter.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()); + } + } + @CheckForNull private String ruleName(String repositoryKey, org.sonar.api.rules.Rule rule) { String name = i18n.getName(repositoryKey, rule.getKey()); @@ -105,4 +137,39 @@ public class DeprecatedRuleDefinitions implements RuleDefinitions { ); return StringUtils.defaultIfBlank(desc, null); } + + public List<RuleDebtXMLImporter.RuleDebt> loadRuleDebtList() { + List<RuleDebtXMLImporter.RuleDebt> ruleDebtList = newArrayList(); + for (String pluginKey : getContributingPluginListWithoutSqale()) { + ruleDebtList.addAll(loadRuleDebtsFromXml(pluginKey)); + } + return ruleDebtList; + } + + public List<RuleDebtXMLImporter.RuleDebt> loadRuleDebtsFromXml(String pluginKey) { + Reader xmlFileReader = null; + try { + xmlFileReader = languageModelFinder.createReaderForXMLFile(pluginKey); + return importer.importXML(xmlFileReader); + } finally { + IOUtils.closeQuietly(xmlFileReader); + } + } + + private Collection<String> getContributingPluginListWithoutSqale() { + Collection<String> pluginList = newArrayList(languageModelFinder.getContributingPluginList()); + pluginList.remove(TechnicalDebtModelRepository.DEFAULT_MODEL); + return pluginList; + } + + @CheckForNull + private RuleDebtXMLImporter.RuleDebt findRequirement(List<RuleDebtXMLImporter.RuleDebt> requirements, final String repoKey, final String ruleKey) { + return Iterables.find(requirements, new Predicate<RuleDebtXMLImporter.RuleDebt>() { + @Override + public boolean apply(RuleDebtXMLImporter.RuleDebt input) { + return input.ruleKey().equals(RuleKey.of(repoKey, ruleKey)); + } + }, null); + } + } diff --git a/sonar-server/src/main/java/org/sonar/server/rule/RuleRegistration.java b/sonar-server/src/main/java/org/sonar/server/rule/RuleRegistration.java index 2ab48037f8e..852273d4009 100644 --- a/sonar-server/src/main/java/org/sonar/server/rule/RuleRegistration.java +++ b/sonar-server/src/main/java/org/sonar/server/rule/RuleRegistration.java @@ -20,6 +20,7 @@ package org.sonar.server.rule; import com.google.common.base.Function; +import com.google.common.base.Predicate; import com.google.common.collect.*; import org.apache.commons.lang.ObjectUtils; import org.apache.commons.lang.StringUtils; @@ -37,7 +38,10 @@ import org.sonar.check.Cardinality; import org.sonar.core.persistence.MyBatis; import org.sonar.core.qualityprofile.db.ActiveRuleDao; import org.sonar.core.rule.*; +import org.sonar.core.technicaldebt.db.CharacteristicDao; +import org.sonar.core.technicaldebt.db.CharacteristicDto; import org.sonar.server.qualityprofile.ProfilesManager; +import org.sonar.server.startup.RegisterDebtCharacteristicModel; import javax.annotation.CheckForNull; @@ -51,6 +55,7 @@ import static com.google.common.collect.Lists.newArrayList; * @since 4.2 */ public class RuleRegistration implements Startable { + private static final Logger LOG = LoggerFactory.getLogger(RuleRegistration.class); private final RuleDefinitionsLoader defLoader; @@ -62,11 +67,16 @@ public class RuleRegistration implements Startable { private final RuleTagDao ruleTagDao; private final RuleTagOperations ruleTagOperations; private final ActiveRuleDao activeRuleDao; + private final CharacteristicDao characteristicDao; private final System2 system = System2.INSTANCE; + /** + * @param registerTechnicalDebtModel used only to be started after init of the technical debt model + */ public RuleRegistration(RuleDefinitionsLoader defLoader, ProfilesManager profilesManager, RuleRegistry ruleRegistry, ESRuleTags esRuleTags, RuleTagOperations ruleTagOperations, - MyBatis myBatis, RuleDao ruleDao, RuleTagDao ruleTagDao, ActiveRuleDao activeRuleDao) { + MyBatis myBatis, RuleDao ruleDao, RuleTagDao ruleTagDao, ActiveRuleDao activeRuleDao, CharacteristicDao characteristicDao, + RegisterDebtCharacteristicModel registerTechnicalDebtModel) { this.defLoader = defLoader; this.profilesManager = profilesManager; this.ruleRegistry = ruleRegistry; @@ -76,6 +86,7 @@ public class RuleRegistration implements Startable { this.ruleDao = ruleDao; this.ruleTagDao = ruleTagDao; this.activeRuleDao = activeRuleDao; + this.characteristicDao = characteristicDao; } @Override @@ -85,8 +96,9 @@ public class RuleRegistration implements Startable { try { RuleDefinitions.Context context = defLoader.load(); Buffer buffer = new Buffer(system.now()); + List<CharacteristicDto> characteristicDtos = characteristicDao.selectEnabledCharacteristics(); selectRulesFromDb(buffer, sqlSession); - enableRuleDefinitions(context, buffer, sqlSession); + enableRuleDefinitions(context, buffer, characteristicDtos, sqlSession); List<RuleDto> removedRules = processRemainingDbRules(buffer, sqlSession); removeActiveRulesOnStillExistingRepositories(removedRules, context); index(buffer); @@ -120,27 +132,27 @@ public class RuleRegistration implements Startable { } } - private void enableRuleDefinitions(RuleDefinitions.Context context, Buffer buffer, SqlSession sqlSession) { + private void enableRuleDefinitions(RuleDefinitions.Context context, Buffer buffer, List<CharacteristicDto> characteristicDtos, SqlSession sqlSession) { for (RuleDefinitions.Repository repoDef : context.repositories()) { - enableRepository(buffer, sqlSession, repoDef); + enableRepository(buffer, sqlSession, repoDef, characteristicDtos); } for (RuleDefinitions.ExtendedRepository extendedRepoDef : context.extendedRepositories()) { if (context.repository(extendedRepoDef.key()) == null) { LOG.warn(String.format("Extension is ignored, repository %s does not exist", extendedRepoDef.key())); } else { - enableRepository(buffer, sqlSession, extendedRepoDef); + enableRepository(buffer, sqlSession, extendedRepoDef, characteristicDtos); } } } - private void enableRepository(Buffer buffer, SqlSession sqlSession, RuleDefinitions.ExtendedRepository repoDef) { + private void enableRepository(Buffer buffer, SqlSession sqlSession, RuleDefinitions.ExtendedRepository repoDef, List<CharacteristicDto> characteristicDtos) { int count = 0; for (RuleDefinitions.Rule ruleDef : repoDef.rules()) { RuleDto dto = buffer.rule(RuleKey.of(ruleDef.repository().key(), ruleDef.key())); if (dto == null) { - dto = enableAndInsert(buffer, sqlSession, ruleDef); + dto = enableAndInsert(buffer, sqlSession, ruleDef, characteristicDtos); } else { - enableAndUpdate(buffer, sqlSession, ruleDef, dto); + enableAndUpdate(buffer, sqlSession, ruleDef, dto, characteristicDtos); } buffer.markProcessed(dto); count++; @@ -151,8 +163,9 @@ public class RuleRegistration implements Startable { sqlSession.commit(); } - private RuleDto enableAndInsert(Buffer buffer, SqlSession sqlSession, RuleDefinitions.Rule ruleDef) { + private RuleDto enableAndInsert(Buffer buffer, SqlSession sqlSession, RuleDefinitions.Rule ruleDef, List<CharacteristicDto> characteristicDtos) { RemediationFunction remediationFunction = ruleDef.remediationFunction(); + RuleDto ruleDto = new RuleDto() .setCardinality(ruleDef.template() ? Cardinality.MULTIPLE : Cardinality.SINGLE) .setConfigKey(ruleDef.internalKey()) @@ -164,12 +177,17 @@ public class RuleRegistration implements Startable { .setSeverity(ruleDef.severity()) .setCreatedAt(buffer.now()) .setUpdatedAt(buffer.now()) - .setStatus(ruleDef.status().name()) - // TODO set default characteristic id - .setDefaultRemediationFunction(remediationFunction != null ? remediationFunction.name() : null) - .setDefaultRemediationFactor(ruleDef.remediationFactor()) - .setDefaultRemediationOffset(ruleDef.remediationOffset()) - .setEffortToFixL10nKey(ruleDef.effortToFixL10nKey()); + .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()); + } + ruleDao.insert(ruleDto, sqlSession); buffer.add(ruleDto); @@ -187,8 +205,8 @@ public class RuleRegistration implements Startable { return ruleDto; } - private void enableAndUpdate(Buffer buffer, SqlSession sqlSession, RuleDefinitions.Rule ruleDef, RuleDto dto) { - if (mergeRule(buffer, ruleDef, dto)) { + private void enableAndUpdate(Buffer buffer, SqlSession sqlSession, RuleDefinitions.Rule ruleDef, RuleDto dto, List<CharacteristicDto> characteristicDtos) { + if (mergeRule(buffer, ruleDef, dto, characteristicDtos)) { ruleDao.update(dto); } mergeParams(buffer, sqlSession, ruleDef, dto); @@ -196,7 +214,7 @@ public class RuleRegistration implements Startable { buffer.markProcessed(dto); } - private boolean mergeRule(Buffer buffer, RuleDefinitions.Rule def, RuleDto dto) { + private boolean mergeRule(Buffer buffer, RuleDefinitions.Rule def, RuleDto dto, List<CharacteristicDto> characteristicDtos) { boolean changed = false; if (!StringUtils.equals(dto.getName(), def.name())) { dto.setName(def.name()); @@ -229,34 +247,42 @@ public class RuleRegistration implements Startable { dto.setLanguage(def.repository().language()); changed = true; } - changed = mergeDebtRule(def, dto) || changed; + changed = mergeDebtDefinitions(def, dto, characteristicDtos) || changed; if (changed) { dto.setUpdatedAt(buffer.now()); } return changed; } - private boolean mergeDebtRule(RuleDefinitions.Rule def, RuleDto dto){ + private boolean mergeDebtDefinitions(RuleDefinitions.Rule def, RuleDto dto, List<CharacteristicDto> characteristicDtos) { boolean changed = false; - // TODO add characteristic id change verification + CharacteristicDto characteristic = findCharacteristic(characteristicDtos, def); + 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; - RemediationFunction remediationFunction = def.remediationFunction(); + if (!ObjectUtils.equals(dto.getDefaultCharacteristicId(), characteristicId)) { + dto.setDefaultCharacteristicId(characteristicId); + changed = true; + } String remediationFunctionString = remediationFunction != null ? remediationFunction.name() : null; if (!StringUtils.equals(dto.getDefaultRemediationFunction(), remediationFunctionString)) { dto.setDefaultRemediationFunction(remediationFunctionString); changed = true; } - if (!StringUtils.equals(dto.getDefaultRemediationFactor(), def.remediationFactor())) { - dto.setDefaultRemediationFactor(def.remediationFactor()); + if (!StringUtils.equals(dto.getDefaultRemediationFactor(), remediationFactor)) { + dto.setDefaultRemediationFactor(remediationFactor); changed = true; } - if (!StringUtils.equals(dto.getDefaultRemediationOffset(), def.remediationOffset())) { - dto.setDefaultRemediationOffset(def.remediationOffset()); + if (!StringUtils.equals(dto.getDefaultRemediationOffset(), remediationOffset)) { + dto.setDefaultRemediationOffset(remediationOffset); changed = true; } - if (!StringUtils.equals(dto.getEffortToFixL10nKey(), def.effortToFixL10nKey())) { - dto.setEffortToFixL10nKey(def.effortToFixL10nKey()); + if (!StringUtils.equals(dto.getEffortToFixL10nKey(), effortToFixL10nKey)) { + dto.setEffortToFixL10nKey(effortToFixL10nKey); changed = true; } return changed; @@ -508,4 +534,21 @@ public class RuleRegistration implements Startable { unprocessedRuleIds.remove(ruleDto.getId()); } } + + @CheckForNull + private CharacteristicDto findCharacteristic(List<CharacteristicDto> characteristicDtos, RuleDefinitions.Rule ruleDef) { + final String key = ruleDef.characteristicKey(); + CharacteristicDto characteristicDto = Iterables.find(characteristicDtos, new Predicate<CharacteristicDto>() { + @Override + public boolean apply(CharacteristicDto input) { + // TODO remove check on null rule id when only characteristics without requirements will be returned + return input.getRuleId() == null && input.getKey().equals(key); + } + }, null); + // TODO check not root characteristic + if (characteristicDto == null) { + LOG.warn(String.format("Characteristic : '%s' has not been found, Technical debt definitions on rule '%s:%s' will be ignored", key, ruleDef.repository(), ruleDef.key())); + } + return characteristicDto; + } } diff --git a/sonar-server/src/main/java/org/sonar/server/startup/RegisterDebtCharacteristicModel.java b/sonar-server/src/main/java/org/sonar/server/startup/RegisterDebtCharacteristicModel.java new file mode 100644 index 00000000000..5395740c127 --- /dev/null +++ b/sonar-server/src/main/java/org/sonar/server/startup/RegisterDebtCharacteristicModel.java @@ -0,0 +1,45 @@ +/* + * 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.server.startup; + +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.DebtCharacteristicsSynchronizer; + +public class RegisterDebtCharacteristicModel { + + private static final Logger LOGGER = LoggerFactory.getLogger(RegisterDebtCharacteristicModel.class); + + private final DebtCharacteristicsSynchronizer manager; + + public RegisterDebtCharacteristicModel(DebtCharacteristicsSynchronizer manager) { + this.manager = manager; + } + + public void start() { + TimeProfiler profiler = new TimeProfiler(LOGGER).start("Register Debt Characteristics Model"); + manager.synchronize(ValidationMessages.create()); + profiler.stop(); + } + +} diff --git a/sonar-server/src/test/java/org/sonar/server/rule/DeprecatedRuleDefinitionsTest.java b/sonar-server/src/test/java/org/sonar/server/rule/DeprecatedRuleDefinitionsTest.java index 5937637d48d..00fd9e91ece 100644 --- a/sonar-server/src/test/java/org/sonar/server/rule/DeprecatedRuleDefinitionsTest.java +++ b/sonar-server/src/test/java/org/sonar/server/rule/DeprecatedRuleDefinitionsTest.java @@ -20,23 +20,43 @@ package org.sonar.server.rule; 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.server.rule.RuleDefinitions; 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.RuleDefinitions; import org.sonar.core.i18n.RuleI18nManager; +import org.sonar.core.technicaldebt.RuleDebtXMLImporter; +import org.sonar.core.technicaldebt.TechnicalDebtModelRepository; +import java.io.Reader; import java.util.Arrays; import java.util.List; +import static com.google.common.collect.Lists.newArrayList; import static org.fest.assertions.Assertions.assertThat; +import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +@RunWith(MockitoJUnitRunner.class) public class DeprecatedRuleDefinitionsTest { + @Mock + RuleI18nManager i18n; + + @Mock + TechnicalDebtModelRepository debtModelRepository; + + @Mock + RuleDebtXMLImporter importer; + static class CheckstyleRules extends RuleRepository { public CheckstyleRules() { super("checkstyle", "java"); @@ -56,12 +76,24 @@ public class DeprecatedRuleDefinitionsTest { } } + static class UseBundles extends RuleRepository { + public UseBundles() { + super("checkstyle", "java"); + setName("Checkstyle"); + } + + @Override + public List<Rule> createRules() { + Rule rule = Rule.create("checkstyle", "ConstantName"); + rule.createParameter("format"); + return Arrays.asList(rule); + } + } + @Test public void wrap_deprecated_rule_repositories() throws Exception { RuleDefinitions.Context context = new RuleDefinitions.Context(); - RuleI18nManager i18n = mock(RuleI18nManager.class); - - new DeprecatedRuleDefinitions(i18n, new RuleRepository[]{new CheckstyleRules()}).define(context); + new DeprecatedRuleDefinitions(i18n, new RuleRepository[]{new CheckstyleRules()}, debtModelRepository, importer).define(context); assertThat(context.repositories()).hasSize(1); RuleDefinitions.Repository checkstyle = context.repository("checkstyle"); @@ -91,38 +123,21 @@ public class DeprecatedRuleDefinitionsTest { @Test public void emulate_the_day_deprecated_api_can_be_dropped() throws Exception { RuleDefinitions.Context context = new RuleDefinitions.Context(); - RuleI18nManager i18n = mock(RuleI18nManager.class); // no more RuleRepository ! - new DeprecatedRuleDefinitions(i18n); + new DeprecatedRuleDefinitions(i18n, debtModelRepository, importer); assertThat(context.repositories()).isEmpty(); } - - static class UseBundles extends RuleRepository { - public UseBundles() { - super("checkstyle", "java"); - setName("Checkstyle"); - } - - @Override - public List<Rule> createRules() { - Rule rule = Rule.create("checkstyle", "ConstantName"); - rule.createParameter("format"); - return Arrays.asList(rule); - } - } - @Test public void use_l10n_bundles() throws Exception { RuleDefinitions.Context context = new RuleDefinitions.Context(); - RuleI18nManager i18n = mock(RuleI18nManager.class); when(i18n.getName("checkstyle", "ConstantName")).thenReturn("Constant Name"); when(i18n.getDescription("checkstyle", "ConstantName")).thenReturn("Checks that constant names conform to the specified format"); when(i18n.getParamDescription("checkstyle", "ConstantName", "format")).thenReturn("Regular expression"); - new DeprecatedRuleDefinitions(i18n, new RuleRepository[]{new UseBundles()}).define(context); + new DeprecatedRuleDefinitions(i18n, new RuleRepository[]{new UseBundles()}, debtModelRepository, importer).define(context); RuleDefinitions.Repository checkstyle = context.repository("checkstyle"); RuleDefinitions.Rule rule = checkstyle.rule("ConstantName"); @@ -134,4 +149,38 @@ public class DeprecatedRuleDefinitionsTest { assertThat(param.name()).isEqualTo("format"); assertThat(param.description()).isEqualTo("Regular expression"); } + + @Test + public void define_rule_debt() throws Exception { + RuleDefinitions.Context context = new RuleDefinitions.Context(); + + List<RuleDebtXMLImporter.RuleDebt> ruleDebts = newArrayList( + new RuleDebtXMLImporter.RuleDebt() + .setCharacteristicKey("MEMORY_EFFICIENCY") + .setRuleKey(RuleKey.of("checkstyle", "ConstantName")) + .setFunction(RemediationFunction.LINEAR_OFFSET) + .setFactor("1d") + .setOffset("10min") + ); + + Reader javaModelReader = mock(Reader.class); + when(debtModelRepository.createReaderForXMLFile("java")).thenReturn(javaModelReader); + when(debtModelRepository.getContributingPluginList()).thenReturn(newArrayList("java")); + when(importer.importXML(eq(javaModelReader))).thenReturn(ruleDebts); + + new DeprecatedRuleDefinitions(i18n, new RuleRepository[]{new CheckstyleRules()}, debtModelRepository, importer).define(context); + + assertThat(context.repositories()).hasSize(1); + RuleDefinitions.Repository checkstyle = context.repository("checkstyle"); + assertThat(checkstyle.rules()).hasSize(1); + + RuleDefinitions.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"); + } + } diff --git a/sonar-server/src/test/java/org/sonar/server/rule/RuleRegistrationTest.java b/sonar-server/src/test/java/org/sonar/server/rule/RuleRegistrationTest.java index 3853bff4914..7b75b8b8401 100644 --- a/sonar-server/src/test/java/org/sonar/server/rule/RuleRegistrationTest.java +++ b/sonar-server/src/test/java/org/sonar/server/rule/RuleRegistrationTest.java @@ -31,7 +31,9 @@ import org.sonar.core.persistence.MyBatis; import org.sonar.core.qualityprofile.db.ActiveRuleDao; import org.sonar.core.rule.RuleDao; import org.sonar.core.rule.RuleTagDao; +import org.sonar.core.technicaldebt.db.CharacteristicDao; import org.sonar.server.qualityprofile.ProfilesManager; +import org.sonar.server.startup.RegisterDebtCharacteristicModel; import static org.fest.assertions.Assertions.assertThat; import static org.mockito.Mockito.*; @@ -53,6 +55,7 @@ public class RuleRegistrationTest extends AbstractDaoTestCase { RuleDao ruleDao; RuleTagDao ruleTagDao; ActiveRuleDao activeRuleDao; + CharacteristicDao characteristicDao; @Before public void before() { @@ -61,8 +64,9 @@ public class RuleRegistrationTest extends AbstractDaoTestCase { ruleTagDao = new RuleTagDao(myBatis); activeRuleDao = new ActiveRuleDao(myBatis); ruleTagOperations = new RuleTagOperations(ruleTagDao, esRuleTags); + characteristicDao = new CharacteristicDao(myBatis); task = new RuleRegistration(new RuleDefinitionsLoader(mock(RuleRepositories.class), new RuleDefinitions[]{new FakeRepository()}), - profilesManager, ruleRegistry, esRuleTags, ruleTagOperations, myBatis, ruleDao, ruleTagDao, activeRuleDao); + profilesManager, ruleRegistry, esRuleTags, ruleTagOperations, myBatis, ruleDao, ruleTagDao, activeRuleDao, characteristicDao, mock(RegisterDebtCharacteristicModel.class)); } @Test @@ -162,6 +166,14 @@ 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"); + task.start(); + + checkTables("remove_rule_debt_definitions_if_characteristic_not_found", EXCLUDED_COLUMN_NAMES, "rules"); + } + + @Test public void not_disable_template_rules_if_parent_is_enabled() { setupData("not_disable_template_rules_if_parent_is_enabled"); task.start(); @@ -189,7 +201,7 @@ public class RuleRegistrationTest extends AbstractDaoTestCase { @Test public void test_high_number_of_rules() { task = new RuleRegistration(new RuleDefinitionsLoader(mock(RuleRepositories.class), new RuleDefinitions[]{new BigRepository()}), - profilesManager, ruleRegistry, esRuleTags, ruleTagOperations, myBatis, ruleDao, ruleTagDao, activeRuleDao); + profilesManager, ruleRegistry, esRuleTags, ruleTagOperations, myBatis, ruleDao, ruleTagDao, activeRuleDao, characteristicDao, mock(RegisterDebtCharacteristicModel.class)); setupData("shared"); task.start(); @@ -204,7 +216,7 @@ public class RuleRegistrationTest extends AbstractDaoTestCase { public void insert_extended_repositories() { task = new RuleRegistration(new RuleDefinitionsLoader(mock(RuleRepositories.class), new RuleDefinitions[]{ new FindbugsRepository(), new FbContribRepository()}), - profilesManager, ruleRegistry, esRuleTags, ruleTagOperations, myBatis, ruleDao, ruleTagDao, activeRuleDao); + profilesManager, ruleRegistry, esRuleTags, ruleTagOperations, myBatis, ruleDao, ruleTagDao, activeRuleDao, characteristicDao, mock(RegisterDebtCharacteristicModel.class)); setupData("empty"); task.start(); @@ -221,7 +233,7 @@ public class RuleRegistrationTest extends AbstractDaoTestCase { .setName("One") .setHtmlDescription("Description of One") .setSeverity(Severity.BLOCKER) - .setCharacteristicKey("COMPILER") + .setCharacteristicKey("MEMORY_EFFICIENCY") .setRemediationFunction(RemediationFunction.LINEAR_OFFSET) .setRemediationFactor("5d") .setRemediationOffset("10h") diff --git a/sonar-server/src/test/java/org/sonar/server/startup/RegisterDebtCharacteristicModelTest.java b/sonar-server/src/test/java/org/sonar/server/startup/RegisterDebtCharacteristicModelTest.java new file mode 100644 index 00000000000..0dcd74a24c6 --- /dev/null +++ b/sonar-server/src/test/java/org/sonar/server/startup/RegisterDebtCharacteristicModelTest.java @@ -0,0 +1,41 @@ +/* + * 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.server.startup; + +import org.junit.Test; +import org.sonar.api.utils.ValidationMessages; +import org.sonar.core.technicaldebt.DebtCharacteristicsSynchronizer; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.*; + +public class RegisterDebtCharacteristicModelTest { + + @Test + public void create_model() throws Exception { + DebtCharacteristicsSynchronizer synchronizer = mock(DebtCharacteristicsSynchronizer.class); + RegisterDebtCharacteristicModel sqaleDefinition = new RegisterDebtCharacteristicModel(synchronizer); + + sqaleDefinition.start(); + + verify(synchronizer, times(1)).synchronize(any(ValidationMessages.class)); + } +} diff --git a/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/insert_new_rules-result.xml b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/insert_new_rules-result.xml index 050c8b4377c..489e2108e85 100644 --- a/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/insert_new_rules-result.xml +++ b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/insert_new_rules-result.xml @@ -1,23 +1,3 @@ -<!-- - ~ 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. - --> - <dataset> <rules id="1" plugin_rule_key="deprecated-key" plugin_name="deprecated-repo" plugin_config_key="[null]" name="Deprecated" description="[null]" @@ -30,7 +10,7 @@ <rules id="2" 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]" + characteristic_id="[null]" default_characteristic_id="2" remediation_function="[null]" default_remediation_function="LINEAR_OFFSET" remediation_factor="[null]" default_remediation_factor="5d" remediation_offset="[null]" default_remediation_offset="10h" diff --git a/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/remove_rule_debt_definitions_if_characteristic_not_found-result.xml b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/remove_rule_debt_definitions_if_characteristic_not_found-result.xml new file mode 100644 index 00000000000..52e53e0cf39 --- /dev/null +++ b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/remove_rule_debt_definitions_if_characteristic_not_found-result.xml @@ -0,0 +1,20 @@ +<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]"/> + + <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" + 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]"/> + +</dataset> diff --git a/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/remove_rule_debt_definitions_if_characteristic_not_found.xml b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/remove_rule_debt_definitions_if_characteristic_not_found.xml new file mode 100644 index 00000000000..f926443c2de --- /dev/null +++ b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/remove_rule_debt_definitions_if_characteristic_not_found.xml @@ -0,0 +1,17 @@ +<dataset> + + <characteristics id="999" kee="NEW" name="New" root_id="1" characteristic_order="1" enabled="[true]"/> + + <rules id="1" plugin_rule_key="rule1" plugin_name="fake" plugin_config_key="old_config_key" name="old name" description="old description" + status="READY" priority="2" cardinality="SINGLE" parent_id="[null]" + characteristic_id="[null]" default_characteristic_id="200" + remediation_function="[null]" default_remediation_function="LINEAR" + remediation_factor="[null]" default_remediation_factor="14min" + remediation_offset="[null]" default_remediation_offset="[null]" + effort_to_fix_l10n_key="[null]"/> + + <rules id="2" plugin_rule_key="rule2" plugin_name="fake" plugin_config_key="old_config_key2" name="old name2" description="old description2" + status="READY" priority="1" cardinality="SINGLE" parent_id="[null]"/> + + +</dataset> diff --git a/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/shared.xml b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/shared.xml index 84192cc4810..17f652e7255 100644 --- a/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/shared.xml +++ b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/shared.xml @@ -1,5 +1,7 @@ <dataset> + <characteristics id="2" kee="MEMORY_EFFICIENCY" name="Memory Efficiency" root_id="1" characteristic_order="1" enabled="[true]"/> + <rules id="1" plugin_rule_key="deprecated-key" plugin_name="deprecated-repo" plugin_config_key="[null]" name="Deprecated" description="[null]" status="READY" priority="4" cardinality="SINGLE" parent_id="[null]"/> diff --git a/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/update_rule_fields.xml b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/update_rule_fields.xml index 416104e8287..cfa18f014e5 100644 --- a/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/update_rule_fields.xml +++ b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/update_rule_fields.xml @@ -1,5 +1,7 @@ <dataset> + <characteristics id="200" kee="MEMORY_EFFICIENCY" name="Memory Efficiency" root_id="1" characteristic_order="1" enabled="[true]"/> + <rules id="1" plugin_rule_key="rule1" plugin_name="fake" plugin_config_key="old_config_key" name="old name" description="old description" status="READY" priority="2" cardinality="SINGLE" parent_id="[null]" characteristic_id="[null]" default_characteristic_id="200" diff --git a/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/update_template_rule_language.xml b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/update_template_rule_language.xml index b5a6352ede7..0ea5e06aa17 100644 --- a/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/update_template_rule_language.xml +++ b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/update_template_rule_language.xml @@ -1,25 +1,7 @@ -<!-- - ~ 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. - --> - <dataset> + <characteristics id="100" kee="MEMORY_EFFICIENCY" name="Memory Efficiency" root_id="1" characteristic_order="1" enabled="[true]"/> + <rules id="1" plugin_rule_key="rule1" plugin_name="fake" plugin_config_key="[null]" name="Rule one" description="[null]" status="READY" priority="4" cardinality="MULTIPLE" parent_id="[null]" language="[null]" characteristic_id="[null]" default_characteristic_id="100" |