From 487c103cd245967f6962ef1a84197769abfe0957 Mon Sep 17 00:00:00 2001 From: Simon Brandhof Date: Tue, 14 Jan 2014 23:33:48 +0100 Subject: [PATCH] SONAR-4908 enable extension point RuleDefinitions --- .../java/org/sonar/core/rule/RuleDao.java | 9 +- .../java/org/sonar/core/rule/RuleDaoTest.java | 2 +- .../org/sonar/api/rule/RuleDefinitions.java | 50 +- .../sonar/api/rule/RuleDefinitionsTest.java | 7 +- .../rule/DeprecatedRuleDefinitions.java | 2 +- .../server/rule/RuleDefinitionsLoader.java | 48 ++ .../sonar/server/rule/RuleRegistration.java | 393 +++++++++++++++ .../sonar/server/rule/RuleRepositories.java | 146 ++++++ .../org/sonar/server/rules/RulesConsole.java | 66 --- .../server/startup/RegisterNewProfiles.java | 5 +- .../sonar/server/startup/RegisterRules.java | 457 ------------------ .../startup/RegisterTechnicalDebtModel.java | 3 +- .../java/org/sonar/server/ui/JRubyFacade.java | 31 +- .../rules_configuration_controller.rb | 2 +- .../rule/RuleDefinitionsLoaderTest.java | 77 +++ .../server/rule/RuleRegistrationTest.java | 263 ++++++++++ .../sonar/server/rule/RuleRegistryTest.java | 3 +- .../server/rule/RuleRepositoriesTest.java | 82 ++++ .../sonar/server/rules/RulesConsoleTest.java | 60 --- .../server/startup/RegisterRulesTest.java | 367 -------------- ...ableUserRulesIfParentIsDisabled-result.xml | 2 +- .../disableUserRulesIfParentIsDisabled.xml | 0 ...sableUserRulesIfParentIsEnabled-result.xml | 2 +- ...doNotDisableUserRulesIfParentIsEnabled.xml | 0 .../rule/RuleRegistrationTest/empty.xml | 1 + .../RuleRegistrationTest}/shared.xml | 0 .../shouldNotDisableManualRules-result.xml | 2 +- .../shouldNotDisableManualRules.xml | 0 ..._deprecated_active_rule_params-result.xml} | 2 +- ...disable_deprecated_active_rule_params.xml} | 0 ...isable_deprecated_active_rules-result.xml} | 2 +- ...hould_disable_deprecated_active_rules.xml} | 0 ...disable_deprecated_repositories-result.xml | 0 ...hould_disable_deprecated_rules-result.xml} | 2 +- .../should_disable_deprecated_rules.xml} | 0 ...ld_insert_extended_repositories-result.xml | 9 + .../should_insert_new_rules-result.xml} | 2 +- ...tivate_disabled_template_rules-result.xml} | 2 +- ...ot_reactivate_disabled_template_rules.xml} | 4 +- ..._update_already_disabled_rules-result.xml} | 0 ...uld_not_update_already_disabled_rules.xml} | 0 ...ould_reactivate_disabled_rules-result.xml} | 2 +- .../should_reactivate_disabled_rules.xml} | 2 +- ...ame_and_description_in_database-result.xml | 0 .../should_update_rule_parameters-result.xml} | 2 +- .../should_update_rule_parameters.xml} | 0 ...d_update_template_rule_language-result.xml | 4 +- .../should_update_template_rule_language.xml | 2 +- .../updadeRuleFields-result.xml | 2 +- .../updadeRuleFields.xml | 0 50 files changed, 1103 insertions(+), 1014 deletions(-) create mode 100644 sonar-server/src/main/java/org/sonar/server/rule/RuleDefinitionsLoader.java create mode 100644 sonar-server/src/main/java/org/sonar/server/rule/RuleRegistration.java create mode 100644 sonar-server/src/main/java/org/sonar/server/rule/RuleRepositories.java delete mode 100644 sonar-server/src/main/java/org/sonar/server/rules/RulesConsole.java delete mode 100644 sonar-server/src/main/java/org/sonar/server/startup/RegisterRules.java create mode 100644 sonar-server/src/test/java/org/sonar/server/rule/RuleDefinitionsLoaderTest.java create mode 100644 sonar-server/src/test/java/org/sonar/server/rule/RuleRegistrationTest.java create mode 100644 sonar-server/src/test/java/org/sonar/server/rule/RuleRepositoriesTest.java delete mode 100644 sonar-server/src/test/java/org/sonar/server/rules/RulesConsoleTest.java delete mode 100644 sonar-server/src/test/java/org/sonar/server/startup/RegisterRulesTest.java rename sonar-server/src/test/resources/org/sonar/server/{startup/RegisterRulesTest => rule/RuleRegistrationTest}/disableUserRulesIfParentIsDisabled-result.xml (95%) rename sonar-server/src/test/resources/org/sonar/server/{startup/RegisterRulesTest => rule/RuleRegistrationTest}/disableUserRulesIfParentIsDisabled.xml (100%) rename sonar-server/src/test/resources/org/sonar/server/{startup/RegisterRulesTest => rule/RuleRegistrationTest}/doNotDisableUserRulesIfParentIsEnabled-result.xml (90%) rename sonar-server/src/test/resources/org/sonar/server/{startup/RegisterRulesTest => rule/RuleRegistrationTest}/doNotDisableUserRulesIfParentIsEnabled.xml (100%) create mode 100644 sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/empty.xml rename sonar-server/src/test/resources/org/sonar/server/{startup/RegisterRulesTest => rule/RuleRegistrationTest}/shared.xml (100%) rename sonar-server/src/test/resources/org/sonar/server/{startup/RegisterRulesTest => rule/RuleRegistrationTest}/shouldNotDisableManualRules-result.xml (93%) rename sonar-server/src/test/resources/org/sonar/server/{startup/RegisterRulesTest => rule/RuleRegistrationTest}/shouldNotDisableManualRules.xml (100%) rename sonar-server/src/test/resources/org/sonar/server/{startup/RegisterRulesTest/disableDeprecatedActiveRuleParameters-result.xml => rule/RuleRegistrationTest/should_disable_deprecated_active_rule_params-result.xml} (94%) rename sonar-server/src/test/resources/org/sonar/server/{startup/RegisterRulesTest/disableDeprecatedActiveRuleParameters.xml => rule/RuleRegistrationTest/should_disable_deprecated_active_rule_params.xml} (100%) rename sonar-server/src/test/resources/org/sonar/server/{startup/RegisterRulesTest/disableDeprecatedActiveRules-result.xml => rule/RuleRegistrationTest/should_disable_deprecated_active_rules-result.xml} (93%) rename sonar-server/src/test/resources/org/sonar/server/{startup/RegisterRulesTest/disableDeprecatedActiveRules.xml => rule/RuleRegistrationTest/should_disable_deprecated_active_rules.xml} (100%) rename sonar-server/src/test/resources/org/sonar/server/{startup/RegisterRulesTest => rule/RuleRegistrationTest}/should_disable_deprecated_repositories-result.xml (100%) rename sonar-server/src/test/resources/org/sonar/server/{startup/RegisterRulesTest/disableDeprecatedRules-result.xml => rule/RuleRegistrationTest/should_disable_deprecated_rules-result.xml} (95%) rename sonar-server/src/test/resources/org/sonar/server/{startup/RegisterRulesTest/disableDeprecatedRules.xml => rule/RuleRegistrationTest/should_disable_deprecated_rules.xml} (100%) create mode 100644 sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_insert_extended_repositories-result.xml rename sonar-server/src/test/resources/org/sonar/server/{startup/RegisterRulesTest/should_save_new_repositories-result.xml => rule/RuleRegistrationTest/should_insert_new_rules-result.xml} (93%) rename sonar-server/src/test/resources/org/sonar/server/{startup/RegisterRulesTest/should_reactivate_disabled_template_rules-result.xml => rule/RuleRegistrationTest/should_not_reactivate_disabled_template_rules-result.xml} (90%) rename sonar-server/src/test/resources/org/sonar/server/{startup/RegisterRulesTest/should_reactivate_disabled_template_rules.xml => rule/RuleRegistrationTest/should_not_reactivate_disabled_template_rules.xml} (87%) rename sonar-server/src/test/resources/org/sonar/server/{startup/RegisterRulesTest/notUpdateAlreadyDisabledRule-result.xml => rule/RuleRegistrationTest/should_not_update_already_disabled_rules-result.xml} (100%) rename sonar-server/src/test/resources/org/sonar/server/{startup/RegisterRulesTest/notUpdateAlreadyDisabledRule.xml => rule/RuleRegistrationTest/should_not_update_already_disabled_rules.xml} (100%) rename sonar-server/src/test/resources/org/sonar/server/{startup/RegisterRulesTest/reactivateDisabledRules-result.xml => rule/RuleRegistrationTest/should_reactivate_disabled_rules-result.xml} (86%) rename sonar-server/src/test/resources/org/sonar/server/{startup/RegisterRulesTest/reactivateDisabledRules.xml => rule/RuleRegistrationTest/should_reactivate_disabled_rules.xml} (71%) rename sonar-server/src/test/resources/org/sonar/server/{startup/RegisterRulesTest => rule/RuleRegistrationTest}/should_store_bundle_name_and_description_in_database-result.xml (100%) rename sonar-server/src/test/resources/org/sonar/server/{startup/RegisterRulesTest/updateRuleParameters-result.xml => rule/RuleRegistrationTest/should_update_rule_parameters-result.xml} (91%) rename sonar-server/src/test/resources/org/sonar/server/{startup/RegisterRulesTest/updateRuleParameters.xml => rule/RuleRegistrationTest/should_update_rule_parameters.xml} (100%) rename sonar-server/src/test/resources/org/sonar/server/{startup/RegisterRulesTest => rule/RuleRegistrationTest}/should_update_template_rule_language-result.xml (83%) rename sonar-server/src/test/resources/org/sonar/server/{startup/RegisterRulesTest => rule/RuleRegistrationTest}/should_update_template_rule_language.xml (96%) rename sonar-server/src/test/resources/org/sonar/server/{startup/RegisterRulesTest => rule/RuleRegistrationTest}/updadeRuleFields-result.xml (93%) rename sonar-server/src/test/resources/org/sonar/server/{startup/RegisterRulesTest => rule/RuleRegistrationTest}/updadeRuleFields.xml (100%) diff --git a/sonar-core/src/main/java/org/sonar/core/rule/RuleDao.java b/sonar-core/src/main/java/org/sonar/core/rule/RuleDao.java index 940dcf0c55b..ee0571450d3 100644 --- a/sonar-core/src/main/java/org/sonar/core/rule/RuleDao.java +++ b/sonar-core/src/main/java/org/sonar/core/rule/RuleDao.java @@ -46,13 +46,8 @@ public class RuleDao implements BatchComponent, ServerComponent { } } - public List selectNonManual() { - SqlSession session = mybatis.openSession(); - try { - return getMapper(session).selectNonManual(); - } finally { - MyBatis.closeQuietly(session); - } + public List selectNonManual(SqlSession session) { + return getMapper(session).selectNonManual(); } public RuleDto selectById(Integer id, SqlSession session) { diff --git a/sonar-core/src/test/java/org/sonar/core/rule/RuleDaoTest.java b/sonar-core/src/test/java/org/sonar/core/rule/RuleDaoTest.java index 43e0b9ce660..997f4a91f3f 100644 --- a/sonar-core/src/test/java/org/sonar/core/rule/RuleDaoTest.java +++ b/sonar-core/src/test/java/org/sonar/core/rule/RuleDaoTest.java @@ -83,7 +83,7 @@ public class RuleDaoTest extends AbstractDaoTestCase { @Test public void testSelectNonManual() throws Exception { setupData("selectNonManual"); - List ruleDtos = dao.selectNonManual(); + List ruleDtos = dao.selectNonManual(getMyBatis().openSession()); assertThat(ruleDtos.size()).isEqualTo(1); RuleDto ruleDto = ruleDtos.get(0); diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/rule/RuleDefinitions.java b/sonar-plugin-api/src/main/java/org/sonar/api/rule/RuleDefinitions.java index 939377f2d40..47ee055782d 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/rule/RuleDefinitions.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/rule/RuleDefinitions.java @@ -47,11 +47,11 @@ public interface RuleDefinitions extends ServerExtension { private final ListMultimap extendedRepositoriesByKey = ArrayListMultimap.create(); public NewRepository newRepository(String key, String language) { - return new NewRepositoryImpl(this, key, language); + return new NewRepositoryImpl(this, key, language, false); } - public NewExtendedRepository extendRepository(String key) { - return new NewRepositoryImpl(this, key); + public NewExtendedRepository extendRepository(String key, String language) { + return new NewRepositoryImpl(this, key, language, true); } @CheckForNull @@ -101,19 +101,13 @@ public interface RuleDefinitions extends ServerExtension { private String name; private final Map newRules = Maps.newHashMap(); - private NewRepositoryImpl(Context context, String key, String language) { - this.extended = false; + private NewRepositoryImpl(Context context, String key, String language, boolean extended) { + this.extended = extended; this.context = context; this.key = this.name = key; this.language = language; } - private NewRepositoryImpl(Context context, String key) { - this.extended = true; - this.context = context; - this.key = this.name = key; - } - @Override public NewRepositoryImpl setName(String s) { this.name = s; @@ -146,6 +140,8 @@ public interface RuleDefinitions extends ServerExtension { static interface ExtendedRepository { String key(); + String language(); + @CheckForNull Rule rule(String ruleKey); @@ -153,8 +149,6 @@ public interface RuleDefinitions extends ServerExtension { } static interface Repository extends ExtendedRepository { - String language(); - String name(); } @@ -169,7 +163,7 @@ public interface RuleDefinitions extends ServerExtension { ImmutableMap.Builder ruleBuilder = ImmutableMap.builder(); for (NewRule newRule : newRepository.newRules.values()) { newRule.validate(); - ruleBuilder.put(newRule.key, new Rule(newRule)); + ruleBuilder.put(newRule.key, new Rule(this, newRule)); } this.rulesByKey = ruleBuilder.build(); } @@ -223,7 +217,8 @@ public interface RuleDefinitions extends ServerExtension { private final String repoKey, key; private String name, htmlDescription, metadata, defaultSeverity = Severity.MAJOR; private boolean template; - private final Set tags = Sets.newHashSet(); + private Status status = Status.READY; + private final Set tags = Sets.newTreeSet(); private final Map paramsByKey = Maps.newHashMap(); private NewRule(String repoKey, String key) { @@ -254,6 +249,11 @@ public interface RuleDefinitions extends ServerExtension { return this; } + public NewRule setStatus(Status status) { + this.status = status; + return this; + } + public NewParam newParam(String paramKey) { if (paramsByKey.containsKey(paramKey)) { throw new IllegalArgumentException(String.format("The parameter '%s' is declared several times on the rule %s", paramKey, this)); @@ -308,13 +308,20 @@ public interface RuleDefinitions extends ServerExtension { } } + static enum Status { + BETA, DEPRECATED, READY + } + static class Rule { + private final Repository repository; private final String repoKey, key, name, htmlDescription, metadata, defaultSeverity; private final boolean template; private final Set tags; private final Map params; + private final Status status; - private Rule(NewRule newRule) { + private Rule(Repository repository, NewRule newRule) { + this.repository = repository; this.repoKey = newRule.repoKey; this.key = newRule.key; this.name = newRule.name; @@ -322,7 +329,8 @@ public interface RuleDefinitions extends ServerExtension { this.metadata = newRule.metadata; this.defaultSeverity = newRule.defaultSeverity; this.template = newRule.template; - this.tags = ImmutableSet.copyOf(newRule.tags); + this.status = newRule.status; + this.tags = ImmutableSortedSet.copyOf(newRule.tags); ImmutableMap.Builder paramsBuilder = ImmutableMap.builder(); for (NewParam newParam : newRule.paramsByKey.values()) { paramsBuilder.put(newParam.key, new Param(newParam)); @@ -330,6 +338,10 @@ public interface RuleDefinitions extends ServerExtension { this.params = paramsBuilder.build(); } + public Repository repository() { + return repository; + } + public String key() { return key; } @@ -351,6 +363,10 @@ public interface RuleDefinitions extends ServerExtension { return template; } + public Status status() { + return status; + } + @CheckForNull public Param param(String key) { return params.get(key); diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/rule/RuleDefinitionsTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/rule/RuleDefinitionsTest.java index 87b891d04ac..e04e1c112c5 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/rule/RuleDefinitionsTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/rule/RuleDefinitionsTest.java @@ -66,6 +66,7 @@ public class RuleDefinitionsTest { .setHtmlDescription("Detect java.lang.NullPointerException") .setDefaultSeverity(Severity.BLOCKER) .setMetadata("/something") + .setStatus(RuleDefinitions.Status.BETA) .setTags("one", "two") .addTags("two", "three", "four"); newFindbugs.newRule("ABC").setName("ABC").setHtmlDescription("ABC"); @@ -83,7 +84,9 @@ public class RuleDefinitionsTest { assertThat(npeRule.params()).isEmpty(); assertThat(npeRule.metadata()).isEqualTo("/something"); assertThat(npeRule.template()).isFalse(); + assertThat(npeRule.status()).isEqualTo(RuleDefinitions.Status.BETA); assertThat(npeRule.toString()).isEqualTo("[repository=findbugs, key=NPE]"); + assertThat(npeRule.repository()).isSameAs(findbugs); // test equals() and hashCode() RuleDefinitions.Rule otherRule = findbugs.rule("ABC"); @@ -102,6 +105,7 @@ public class RuleDefinitionsTest { assertThat(rule.defaultSeverity()).isEqualTo(Severity.MAJOR); assertThat(rule.params()).isEmpty(); assertThat(rule.metadata()).isNull(); + assertThat(rule.status()).isEqualTo(RuleDefinitions.Status.READY); assertThat(rule.tags()).isEmpty(); } @@ -139,7 +143,7 @@ public class RuleDefinitionsTest { assertThat(context.extendedRepositories()).isEmpty(); // for example fb-contrib - RuleDefinitions.NewExtendedRepository newFindbugs = context.extendRepository("findbugs"); + RuleDefinitions.NewExtendedRepository newFindbugs = context.extendRepository("findbugs", "java"); newFindbugs.newRule("NPE").setName("NPE").setHtmlDescription("NPE"); newFindbugs.done(); @@ -149,6 +153,7 @@ public class RuleDefinitionsTest { assertThat(context.extendedRepositories("findbugs")).hasSize(1); RuleDefinitions.ExtendedRepository findbugs = context.extendedRepositories("findbugs").get(0); + assertThat(findbugs.language()).isEqualTo("java"); assertThat(findbugs.rule("NPE")).isNotNull(); } 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 cc61dfa0f8b..b1d60ca27a1 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 @@ -54,7 +54,7 @@ public class DeprecatedRuleDefinitions implements RuleDefinitions { newRepository = context.newRepository(repository.getKey(), repository.getLanguage()); newRepository.setName(repository.getName()); } else { - newRepository = (NewRepository) context.extendRepository(repository.getKey()); + newRepository = (NewRepository) context.extendRepository(repository.getKey(), repository.getLanguage()); } for (org.sonar.api.rules.Rule rule : repository.createRules()) { // TODO remove org.sonar.api.rules.Rule#tags diff --git a/sonar-server/src/main/java/org/sonar/server/rule/RuleDefinitionsLoader.java b/sonar-server/src/main/java/org/sonar/server/rule/RuleDefinitionsLoader.java new file mode 100644 index 00000000000..4aefe0ba5fe --- /dev/null +++ b/sonar-server/src/main/java/org/sonar/server/rule/RuleDefinitionsLoader.java @@ -0,0 +1,48 @@ +/* + * 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.rule; + +import org.sonar.api.rule.RuleDefinitions; + +/** + * Loads all instances of RuleDefinitions and initializes RuleRepositories. + */ +public class RuleDefinitionsLoader { + private final RuleDefinitions[] definitions; + private final RuleRepositories repositories; + + public RuleDefinitionsLoader(RuleRepositories repositories, RuleDefinitions[] definitions) { + this.repositories = repositories; + this.definitions = definitions; + } + + public RuleDefinitionsLoader(RuleRepositories repositories) { + this(repositories, new RuleDefinitions[0]); + } + + public RuleDefinitions.Context load() { + RuleDefinitions.Context context = new RuleDefinitions.Context(); + for (RuleDefinitions definition : definitions) { + definition.define(context); + } + repositories.register(context); + return context; + } +} 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 new file mode 100644 index 00000000000..819cf2531aa --- /dev/null +++ b/sonar-server/src/main/java/org/sonar/server/rule/RuleRegistration.java @@ -0,0 +1,393 @@ +/* + * 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.rule; + +import com.google.common.collect.*; +import org.apache.commons.lang.ObjectUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.ibatis.session.SqlSession; +import org.picocontainer.Startable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.sonar.api.rule.RuleDefinitions; +import org.sonar.api.rule.RuleKey; +import org.sonar.api.rules.Rule; +import org.sonar.api.rules.RulePriority; +import org.sonar.api.utils.System2; +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.server.configuration.ProfilesManager; + +import javax.annotation.CheckForNull; +import java.util.*; + +public class RuleRegistration implements Startable { + private static final Logger LOG = LoggerFactory.getLogger(RuleRegistration.class); + + private final RuleDefinitionsLoader defLoader; + private final ProfilesManager profilesManager; + private final RuleRegistry ruleRegistry; + private final MyBatis myBatis; + private final RuleDao ruleDao; + private final ActiveRuleDao activeRuleDao; + private final System2 system = System2.INSTANCE; + + public RuleRegistration(RuleDefinitionsLoader defLoader, ProfilesManager profilesManager, + RuleRegistry ruleRegistry, + MyBatis myBatis, RuleDao ruleDao, ActiveRuleDao activeRuleDao) { + this.defLoader = defLoader; + this.profilesManager = profilesManager; + this.ruleRegistry = ruleRegistry; + this.myBatis = myBatis; + this.ruleDao = ruleDao; + this.activeRuleDao = activeRuleDao; + } + + @Override + public void start() { + SqlSession sqlSession = myBatis.openSession(); + try { + Buffer buffer = new Buffer(system.now()); + selectRulesFromDb(buffer, sqlSession); + enableRuleDefinitions(buffer, sqlSession); + processRemainingDbRules(buffer, sqlSession); + index(buffer); + + } finally { + sqlSession.close(); + } + } + + @Override + public void stop() { + // nothing + } + + private void selectRulesFromDb(Buffer buffer, SqlSession sqlSession) { + for (RuleDto ruleDto : ruleDao.selectNonManual(sqlSession)) { + buffer.add(ruleDto); + buffer.markUnprocessed(ruleDto); + } + for (RuleParamDto paramDto : ruleDao.selectParameters(sqlSession)) { + buffer.add(paramDto); + } + for (RuleTagDto tagDto : ruleDao.selectTags(sqlSession)) { + buffer.add(tagDto); + } + } + + private void enableRuleDefinitions(Buffer buffer, SqlSession sqlSession) { + RuleDefinitions.Context context = defLoader.load(); + for (RuleDefinitions.Repository repoDef : context.repositories()) { + enableRepository(buffer, sqlSession, repoDef); + } + 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); + } + } + } + + private void enableRepository(Buffer buffer, SqlSession sqlSession, RuleDefinitions.ExtendedRepository repoDef) { + 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); + } else { + enableAndUpdate(buffer, sqlSession, ruleDef, dto); + } + buffer.markProcessed(dto); + count++; + if (count % 100 == 0) { + sqlSession.commit(); + } + } + sqlSession.commit(); + } + + private RuleDto enableAndInsert(Buffer buffer, SqlSession sqlSession, RuleDefinitions.Rule ruleDef) { + RuleDto ruleDto = new RuleDto() + .setCardinality(ruleDef.template() ? Cardinality.MULTIPLE : Cardinality.SINGLE) + .setConfigKey(ruleDef.metadata()) + .setDescription(ruleDef.htmlDescription()) + .setLanguage(ruleDef.repository().language()) + .setName(ruleDef.name()) + .setRepositoryKey(ruleDef.repository().key()) + .setRuleKey(ruleDef.key()) + .setSeverity(RulePriority.valueOf(ruleDef.defaultSeverity()).ordinal()) + .setCreatedAt(buffer.now()) + .setUpdatedAt(buffer.now()) + .setStatus(ruleDef.status().name()); + ruleDao.insert(ruleDto, sqlSession); + buffer.add(ruleDto); + + for (RuleDefinitions.Param param : ruleDef.params()) { + RuleParamDto paramDto = new RuleParamDto() + .setRuleId(ruleDto.getId()) + .setDefaultValue(param.defaultValue()) + .setDescription(param.description()) + .setName(param.name()) + .setType(param.type().toString()); + ruleDao.insert(paramDto, sqlSession); + buffer.add(paramDto); + } + for (String tag : ruleDef.tags()) { + RuleTagDto tagDto = new RuleTagDto().setRuleId(ruleDto.getId()).setTag(tag).setType(RuleTagType.SYSTEM); + ruleDao.insert(tagDto, sqlSession); + buffer.add(tagDto); + } + return ruleDto; + } + + private void enableAndUpdate(Buffer buffer, SqlSession sqlSession, RuleDefinitions.Rule ruleDef, RuleDto dto) { + if (mergeRule(buffer, ruleDef, dto)) { + ruleDao.update(dto); + } + mergeParams(buffer, sqlSession, ruleDef, dto); + mergeTags(buffer, sqlSession, ruleDef, dto); + buffer.markProcessed(dto); + } + + private boolean mergeRule(Buffer buffer, RuleDefinitions.Rule def, RuleDto dto) { + boolean changed = false; + if (!StringUtils.equals(dto.getName(), def.name())) { + dto.setName(def.name()); + changed = true; + } + if (!StringUtils.equals(dto.getDescription(), def.htmlDescription())) { + dto.setDescription(def.htmlDescription()); + changed = true; + } + if (!StringUtils.equals(dto.getConfigKey(), def.metadata())) { + dto.setConfigKey(def.metadata()); + changed = true; + } + int severity = RulePriority.valueOf(def.defaultSeverity()).ordinal(); + if (!ObjectUtils.equals(dto.getSeverity(), severity)) { + dto.setSeverity(severity); + changed = true; + } + Cardinality cardinality = def.template() ? Cardinality.MULTIPLE : Cardinality.SINGLE; + if (!cardinality.equals(dto.getCardinality())) { + dto.setCardinality(cardinality); + changed = true; + } + String status = def.status().name(); + if (!StringUtils.equals(dto.getStatus(), status)) { + dto.setStatus(status); + changed = true; + } + if (!StringUtils.equals(dto.getLanguage(), def.repository().language())) { + dto.setLanguage(def.repository().language()); + changed = true; + } + if (changed) { + dto.setUpdatedAt(buffer.now()); + } + return changed; + } + + private void mergeParams(Buffer buffer, SqlSession sqlSession, RuleDefinitions.Rule ruleDef, RuleDto dto) { + Collection paramDtos = buffer.paramsForRuleId(dto.getId()); + Set persistedParamKeys = Sets.newHashSet(); + for (RuleParamDto paramDto : paramDtos) { + RuleDefinitions.Param paramDef = ruleDef.param(paramDto.getName()); + if (paramDef == null) { + activeRuleDao.deleteParametersWithParamId(paramDto.getId(), sqlSession); + ruleDao.deleteParam(paramDto, sqlSession); + } else { + // TODO validate that existing active rules still match constraints + // TODO store param name + if (mergeParam(paramDto, paramDef)) { + ruleDao.update(paramDto, sqlSession); + } + persistedParamKeys.add(paramDto.getName()); + } + } + for (RuleDefinitions.Param param : ruleDef.params()) { + if (!persistedParamKeys.contains(param.key())) { + RuleParamDto paramDto = new RuleParamDto() + .setRuleId(dto.getId()) + .setName(param.key()) + .setDescription(param.description()) + .setDefaultValue(param.defaultValue()) + .setType(param.type().toString()); + ruleDao.insert(paramDto, sqlSession); + buffer.add(paramDto); + } + } + } + + private boolean mergeParam(RuleParamDto paramDto, RuleDefinitions.Param paramDef) { + boolean changed = false; + if (!StringUtils.equals(paramDto.getType(), paramDef.type().toString())) { + paramDto.setType(paramDef.type().toString()); + changed = true; + } + if (!StringUtils.equals(paramDto.getDefaultValue(), paramDef.defaultValue())) { + paramDto.setDefaultValue(paramDef.defaultValue()); + changed = true; + } + if (!StringUtils.equals(paramDto.getDescription(), paramDef.description())) { + paramDto.setDescription(paramDef.description()); + changed = true; + } + return changed; + } + + private void mergeTags(Buffer buffer, SqlSession sqlSession, RuleDefinitions.Rule ruleDef, RuleDto dto) { + Set existingSystemTags = Sets.newHashSet(); + + Collection tagDtos = ImmutableList.copyOf(buffer.tagsForRuleId(dto.getId())); + for (RuleTagDto tagDto : tagDtos) { + String tag = tagDto.getTag(); + + if (tagDto.getType() == RuleTagType.SYSTEM) { + // tag previously declared by plugin + if (!ruleDef.tags().contains(tag)) { + // not declared anymore + ruleDao.deleteTag(tagDto, sqlSession); + buffer.remove(tagDto); + } else { + existingSystemTags.add(tagDto.getTag()); + } + } else { + // tags created by end-users + if (ruleDef.tags().contains(tag)) { + // End-user tag is converted to system tag + ruleDao.deleteTag(tagDto, sqlSession); + buffer.remove(tagDto); + RuleTagDto newTag = new RuleTagDto().setRuleId(dto.getId()).setTag(tag).setType(RuleTagType.SYSTEM); + ruleDao.insert(newTag, sqlSession); + existingSystemTags.add(tag); + buffer.add(newTag); + } + } + } + + for (String tag : ruleDef.tags()) { + if (!existingSystemTags.contains(tag)) { + RuleTagDto newTagDto = new RuleTagDto().setRuleId(dto.getId()).setTag(tag).setType(RuleTagType.SYSTEM); + ruleDao.insert(newTagDto, sqlSession); + buffer.add(newTagDto); + } + } + } + + private void processRemainingDbRules(Buffer buffer, SqlSession sqlSession) { + List removedIds = Lists.newArrayList(); + for (Integer unprocessedRuleId : buffer.unprocessedRuleIds) { + RuleDto ruleDto = buffer.rulesById.get(unprocessedRuleId); + boolean toBeRemoved = true; + if (ruleDto.getParentId() != null && !ruleDto.getStatus().equals(Rule.STATUS_REMOVED)) { + RuleDto parent = buffer.rulesById.get(ruleDto.getParentId()); + if (parent != null) { + // TODO merge params and tags ? + ruleDto.setLanguage(parent.getLanguage()); + ruleDto.setStatus(parent.getStatus()); + ruleDto.setUpdatedAt(buffer.now()); + ruleDao.update(ruleDto, sqlSession); + toBeRemoved = false; + } + } + if (toBeRemoved) { + // TODO log repository key + LOG.info("Disable rule " + ruleDto.getRuleKey()); + ruleDto.setStatus(Rule.STATUS_REMOVED); + ruleDto.setUpdatedAt(buffer.now()); + ruleDao.update(ruleDto, sqlSession); + removedIds.add(ruleDto.getId()); + if (removedIds.size() % 100 == 0) { + sqlSession.commit(); + } + } + } + sqlSession.commit(); + + // call to ProfileManager requires session to be committed + for (Integer removedId : removedIds) { + profilesManager.removeActivatedRules(removedId); + } + } + + private void index(Buffer buffer) { + ruleRegistry.bulkRegisterRules(buffer.rulesById.values(), buffer.paramsByRuleId, buffer.tagsByRuleId); + } + + static class Buffer { + private Date now; + private List unprocessedRuleIds = Lists.newArrayList(); + private Map rulesByKey = Maps.newHashMap(); + private Map rulesById = Maps.newHashMap(); + private Multimap paramsByRuleId = ArrayListMultimap.create(); + private Multimap tagsByRuleId = ArrayListMultimap.create(); + + Buffer(long now) { + this.now = new Date(now); + } + + Date now() { + return now; + } + + void add(RuleDto rule) { + rulesById.put(rule.getId(), rule); + rulesByKey.put(RuleKey.of(rule.getRepositoryKey(), rule.getRuleKey()), rule); + } + + void add(RuleParamDto param) { + paramsByRuleId.put(param.getRuleId(), param); + } + + void add(RuleTagDto tag) { + tagsByRuleId.put(tag.getRuleId(), tag); + } + + void remove(RuleTagDto tag) { + tagsByRuleId.remove(tag.getRuleId(), tag); + } + + @CheckForNull + RuleDto rule(RuleKey key) { + return rulesByKey.get(key); + } + + Collection paramsForRuleId(Integer ruleId) { + return paramsByRuleId.get(ruleId); + } + + Collection tagsForRuleId(Integer ruleId) { + return tagsByRuleId.get(ruleId); + } + + void markUnprocessed(RuleDto ruleDto) { + unprocessedRuleIds.add(ruleDto.getId()); + } + + void markProcessed(RuleDto ruleDto) { + unprocessedRuleIds.remove(ruleDto.getId()); + } + } +} diff --git a/sonar-server/src/main/java/org/sonar/server/rule/RuleRepositories.java b/sonar-server/src/main/java/org/sonar/server/rule/RuleRepositories.java new file mode 100644 index 00000000000..8ecd7c1cc6e --- /dev/null +++ b/sonar-server/src/main/java/org/sonar/server/rule/RuleRepositories.java @@ -0,0 +1,146 @@ +/* + * 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.rule; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSetMultimap; +import com.google.common.collect.ImmutableSortedSet; +import com.google.common.collect.SetMultimap; +import org.sonar.api.ServerComponent; +import org.sonar.api.rule.RuleDefinitions; + +import javax.annotation.CheckForNull; +import java.util.Collection; +import java.util.Map; +import java.util.SortedSet; + +/** + * This component keeps metadata of rule repositories. + *

+ * Rule repositories are not persisted into datastores, so their metadata (name) + * is kept by this component. + * + * @since 4.2 + */ +public class RuleRepositories implements ServerComponent { + + public static class Repository implements Comparable { + private final String key, name, language; + + private Repository(RuleDefinitions.Repository repoDef) { + this.key = repoDef.key(); + this.name = repoDef.name(); + this.language = repoDef.language(); + } + + public String key() { + return key; + } + + public String name() { + return name; + } + + public String language() { + return language; + } + + /** + * Kept for backward-compatibility in Ruby code + */ + public String getKey() { + return key; + } + + /** + * Kept for backward-compatibility in Ruby code + */ + public String getName() { + return name; + } + + /** + * Kept for backward-compatibility in Ruby code + */ + public String getLanguage() { + return language; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Repository that = (Repository) o; + return key.equals(that.key); + } + + @Override + public int hashCode() { + return key.hashCode(); + } + + @Override + public int compareTo(Repository o) { + return name.toLowerCase().compareTo(o.name.toLowerCase()); + } + } + + private SortedSet repositories; + private Map repositoriesByKey; + private SetMultimap repositoriesByLang; + + void register(RuleDefinitions.Context context) { + ImmutableSortedSet.Builder listBuilder = ImmutableSortedSet.naturalOrder(); + ImmutableSetMultimap.Builder langBuilder = ImmutableSetMultimap.builder(); + ImmutableMap.Builder keyBuilder = ImmutableMap.builder(); + for (RuleDefinitions.Repository repoDef : context.repositories()) { + Repository repository = new Repository(repoDef); + listBuilder.add(repository); + langBuilder.put(repository.language(), repository); + keyBuilder.put(repository.key(), repository); + } + repositories = listBuilder.build(); + repositoriesByLang = langBuilder.build(); + repositoriesByKey = keyBuilder.build(); + } + + @CheckForNull + public Repository repository(String key) { + return repositoriesByKey.get(key); + } + + /** + * Repositories for a given language, sorted by name. + */ + public Collection repositoriesForLang(String lang) { + return repositoriesByLang.get(lang); + } + + /** + * Repositories, sorted by name. + */ + public Collection repositories() { + return repositories; + } +} diff --git a/sonar-server/src/main/java/org/sonar/server/rules/RulesConsole.java b/sonar-server/src/main/java/org/sonar/server/rules/RulesConsole.java deleted file mode 100644 index 0e591e9c95a..00000000000 --- a/sonar-server/src/main/java/org/sonar/server/rules/RulesConsole.java +++ /dev/null @@ -1,66 +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.server.rules; - -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.SetMultimap; -import org.sonar.api.ServerComponent; -import org.sonar.api.rules.RuleRepository; - -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Set; - -public final class RulesConsole implements ServerComponent { - - private List repositories = Lists.newArrayList(); - private Map repositoryByKey = Maps.newHashMap(); - private SetMultimap repositoriesByLanguage = HashMultimap.create(); - - - public RulesConsole(RuleRepository[] repositories) { - initRepositories(repositories); - } - - private void initRepositories(RuleRepository[] repositories) { - this.repositories.addAll(Arrays.asList(repositories)); - for (RuleRepository repository : this.repositories) { - if (!repositoryByKey.containsKey(repository.getKey())) { - repositoriesByLanguage.put(repository.getLanguage(), repository); - repositoryByKey.put(repository.getKey(), repository); - } - } - } - - public Set getRepositoriesByLanguage(String language) { - return repositoriesByLanguage.get(language); - } - - public List getRepositories() { - return repositories; - } - - public RuleRepository getRepository(String key) { - return repositoryByKey.get(key); - } -} diff --git a/sonar-server/src/main/java/org/sonar/server/startup/RegisterNewProfiles.java b/sonar-server/src/main/java/org/sonar/server/startup/RegisterNewProfiles.java index 9d67ecce3ec..3f28d90a226 100644 --- a/sonar-server/src/main/java/org/sonar/server/startup/RegisterNewProfiles.java +++ b/sonar-server/src/main/java/org/sonar/server/startup/RegisterNewProfiles.java @@ -38,6 +38,7 @@ import org.sonar.core.template.LoadedTemplateDao; import org.sonar.core.template.LoadedTemplateDto; import org.sonar.jpa.session.DatabaseSessionFactory; import org.sonar.server.platform.PersistentSettings; +import org.sonar.server.rule.RuleRegistration; import org.sonar.server.rule.RuleRegistry; import java.util.*; @@ -61,7 +62,7 @@ public class RegisterNewProfiles { RuleRegistry ruleRegistry, LoadedTemplateDao loadedTemplateDao, DatabaseSessionFactory sessionFactory, - RegisterRules registerRulesBefore) { + RuleRegistration registerRulesBefore) { this.settings = settings; this.ruleFinder = ruleFinder; this.ruleRegistry = ruleRegistry; @@ -75,7 +76,7 @@ public class RegisterNewProfiles { RuleRegistry ruleRegistry, LoadedTemplateDao loadedTemplateDao, DatabaseSessionFactory sessionFactory, - RegisterRules registerRulesBefore) { + RuleRegistration registerRulesBefore) { this(Collections.emptyList(), settings, ruleFinder, ruleRegistry, loadedTemplateDao, sessionFactory, registerRulesBefore); } diff --git a/sonar-server/src/main/java/org/sonar/server/startup/RegisterRules.java b/sonar-server/src/main/java/org/sonar/server/startup/RegisterRules.java deleted file mode 100644 index 560f7c766b5..00000000000 --- a/sonar-server/src/main/java/org/sonar/server/startup/RegisterRules.java +++ /dev/null @@ -1,457 +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.server.startup; - -import com.google.common.base.Objects; -import com.google.common.base.Predicate; -import com.google.common.base.Strings; -import com.google.common.collect.ArrayListMultimap; -import com.google.common.collect.Iterables; -import com.google.common.collect.Maps; -import com.google.common.collect.Multimap; -import org.apache.commons.lang.StringUtils; -import org.apache.ibatis.session.SqlSession; -import org.elasticsearch.common.collect.Lists; -import org.elasticsearch.common.collect.Sets; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.sonar.api.rules.Rule; -import org.sonar.api.rules.RuleParam; -import org.sonar.api.rules.RuleRepository; -import org.sonar.api.utils.SonarException; -import org.sonar.api.utils.TimeProfiler; -import org.sonar.core.i18n.RuleI18nManager; -import org.sonar.core.persistence.MyBatis; -import org.sonar.core.qualityprofile.db.ActiveRuleDao; -import org.sonar.core.rule.*; -import org.sonar.server.configuration.ProfilesManager; -import org.sonar.server.rule.RuleRegistry; - -import java.util.*; - -import static com.google.common.collect.Lists.newArrayList; -import static com.google.common.collect.Maps.newHashMap; -import static com.google.common.collect.Sets.newHashSet; - -public final class RegisterRules { - - private static final Logger LOG = LoggerFactory.getLogger(RegisterRules.class); - private final ProfilesManager profilesManager; - private final List repositories; - private final RuleI18nManager ruleI18nManager; - private final RuleRegistry ruleRegistry; - private final MyBatis myBatis; - private final RuleDao ruleDao; - private final ActiveRuleDao activeRuleDao; - private SqlSession sqlSession; - - public RegisterRules(RuleRepository[] repos, RuleI18nManager ruleI18nManager, ProfilesManager profilesManager, RuleRegistry ruleRegistry, - MyBatis myBatis, RuleDao ruleDao, ActiveRuleDao activeRuleDao) { - this.profilesManager = profilesManager; - this.repositories = newArrayList(repos); - this.ruleI18nManager = ruleI18nManager; - this.ruleRegistry = ruleRegistry; - this.myBatis = myBatis; - this.ruleDao = ruleDao; - this.activeRuleDao = activeRuleDao; - } - - public RegisterRules(RuleI18nManager ruleI18nManager, ProfilesManager profilesManager, RuleRegistry ruleRegistry, MyBatis myBatis, - RuleDao ruleDao, ActiveRuleDao activeRuleDao) { - this(new RuleRepository[0], ruleI18nManager, profilesManager, ruleRegistry, myBatis, ruleDao, activeRuleDao); - } - - public void start() { - sqlSession = myBatis.openSession(); - - RulesByRepository existingRules = new RulesByRepository( - findAllRules(), ruleDao.selectParameters(sqlSession), ruleDao.selectTags(sqlSession)); - - try { - List registeredRules = registerRules(existingRules); - - LOG.info("Removing deprecated rules"); - Set disabledRules = newHashSet(); - disabledRules.addAll(disableDeprecatedRules(existingRules, registeredRules)); - disabledRules.addAll(disableDeprecatedRepositories(existingRules)); - sqlSession.commit(); - removeActiveRulesOnDisabledRules(disabledRules); - - Set allRules = Sets.newHashSet(); - allRules.addAll(existingRules.rules()); - allRules.addAll(registeredRules); - - ruleRegistry.bulkRegisterRules(allRules, existingRules.params, existingRules.tags); - } finally { - sqlSession.close(); - } - } - - private List findAllRules() { - return ruleDao.selectNonManual(); - } - - private List registerRules(RulesByRepository existingRules) { - TimeProfiler profiler = new TimeProfiler(); - List registeredRules = newArrayList(); - for (RuleRepository repository : repositories) { - profiler.start("Register rules [" + repository.getKey() + "/" + StringUtils.defaultString(repository.getLanguage(), "-") + "]"); - registeredRules.addAll(registerRepositoryRules(repository, existingRules)); - profiler.stop(); - } - // Template rules have to be registered after all rules in order for their parent to be updated. - registeredRules.addAll(registerTemplateRules(registeredRules, existingRules)); - return registeredRules; - } - - private List registerRepositoryRules(RuleRepository repository, RulesByRepository existingRules) { - List registeredRules = newArrayList(); - Map ruleByKey = newHashMap(); - - for (Rule rule : repository.createRules()) { - updateRuleFromRepositoryInfo(rule, repository); - validateRule(rule, repository.getKey()); - ruleByKey.put(rule.getKey(), rule); - } - LOG.debug(ruleByKey.size() + " rules"); - - for (RuleDto persistedRule : existingRules.get(repository.getKey())) { - Rule rule = ruleByKey.get(persistedRule.getRuleKey()); - if (rule != null) { - updateExistingRule(persistedRule, existingRules, rule); - ruleDao.update(persistedRule, sqlSession); - registeredRules.add(persistedRule); - ruleByKey.remove(rule.getKey()); - } - } - registeredRules.addAll(saveNewRules(ruleByKey.values(), existingRules)); - return registeredRules; - } - - /** - * Template rules do not exists in rule repositories, only in database, they have to be updated from their parent. - */ - private List registerTemplateRules(List registeredRules, RulesByRepository existingRules) { - List templateRules = newArrayList(); - for (RuleDto persistedRule : existingRules.rules()) { - RuleDto parent = existingRules.ruleById(persistedRule.getParentId()); - if (parent != null && registeredRules.contains(parent)) { - persistedRule.setRepositoryKey(parent.getRepositoryKey()); - persistedRule.setLanguage(parent.getLanguage()); - persistedRule.setStatus(Objects.firstNonNull(persistedRule.getStatus(), Rule.STATUS_READY)); - persistedRule.setCreatedAt(Objects.firstNonNull(persistedRule.getCreatedAt(), new Date())); - persistedRule.setUpdatedAt(new Date()); - - ruleDao.update(persistedRule, sqlSession); - templateRules.add(persistedRule); - } - } - return templateRules; - } - - private void updateRuleFromRepositoryInfo(Rule rule, RuleRepository repository) { - rule.setRepositoryKey(repository.getKey()); - rule.setLanguage(repository.getLanguage()); - rule.setStatus(Objects.firstNonNull(rule.getStatus(), Rule.STATUS_READY)); - } - - private void validateRule(Rule rule, String repositoryKey) { - validateRuleRepositoryName(rule, repositoryKey); - validateRuleDescription(rule, repositoryKey); - } - - private void validateRuleRepositoryName(Rule rule, String repositoryKey) { - String nameFromBundle = ruleI18nManager.getName(repositoryKey, rule.getKey()); - if (!Strings.isNullOrEmpty(nameFromBundle)) { - rule.setName(nameFromBundle); - } - if (Strings.isNullOrEmpty(rule.getName())) { - throw new SonarException("The following rule (repository: " + repositoryKey + ") must have a name: " + rule); - } - } - - private void validateRuleDescription(Rule rule, String repositoryKey) { - String descriptionFromBundle = ruleI18nManager.getDescription(repositoryKey, rule.getKey()); - if (!Strings.isNullOrEmpty(descriptionFromBundle)) { - rule.setDescription(descriptionFromBundle); - } - if (Strings.isNullOrEmpty(rule.getDescription())) { - if (!Strings.isNullOrEmpty(rule.getName()) && Strings.isNullOrEmpty(ruleI18nManager.getName(repositoryKey, rule.getKey()))) { - // specific case - throw new SonarException("No description found for the rule '" + rule.getName() + "' (repository: " + repositoryKey + ") because the entry 'rule." - + repositoryKey + "." + rule.getKey() + ".name' is missing from the bundle."); - } else { - throw new SonarException("The following rule (repository: " + repositoryKey + ") must have a description: " + rule); - } - } - } - - private void updateExistingRule(RuleDto persistedRule, RulesByRepository existingRules, Rule rule) { - LOG.debug("Update existing rule " + rule); - - persistedRule.setName(rule.getName()); - persistedRule.setConfigKey(rule.getConfigKey()); - persistedRule.setDescription(rule.getDescription()); - persistedRule.setSeverity(rule.getSeverity().ordinal()); - persistedRule.setCardinality(rule.getCardinality()); - persistedRule.setStatus(rule.getStatus()); - persistedRule.setLanguage(rule.getLanguage()); - persistedRule.setUpdatedAt(new Date()); - - Collection ruleParams = existingRules.params(persistedRule.getId()); - - // delete deprecated params - deleteDeprecatedParameters(ruleParams, rule); - - // add new params and update existing params - updateParameters(persistedRule, ruleParams, rule); - - synchronizeTags(persistedRule, existingRules, rule); - } - - private void updateParameters(RuleDto persistedRule, Collection ruleParams, Rule rule) { - Map paramsByKey = Maps.newHashMap(); - for (RuleParamDto param: ruleParams) { - paramsByKey.put(param.getName(), param); - } - - if (rule.getParams() != null) { - for (RuleParam param : rule.getParams()) { - RuleParamDto persistedParam = paramsByKey.get(param.getKey()); - if (persistedParam == null) { - persistedParam = new RuleParamDto() - .setRuleId(persistedRule.getId()) - .setName(param.getKey()) - .setType(param.getType()); - ruleDao.insert(persistedParam, sqlSession); - ruleParams.add(persistedParam); - } - String desc = StringUtils.defaultIfEmpty( - ruleI18nManager.getParamDescription(rule.getRepositoryKey(), rule.getKey(), param.getKey()), - param.getDescription() - ); - persistedParam.setDescription(desc); - persistedParam.setType(param.getType()); - persistedParam.setDefaultValue(param.getDefaultValue()); - - ruleDao.update(persistedParam, sqlSession); - } - } - } - - private void deleteDeprecatedParameters(Collection ruleParams, Rule rule) { - if (ruleParams != null && !ruleParams.isEmpty()) { - for (Iterator it = ruleParams.iterator(); it.hasNext(); ) { - RuleParamDto persistedParam = it.next(); - if (rule.getParam(persistedParam.getName()) == null) { - it.remove(); - activeRuleDao.deleteParametersWithParamId(persistedParam.getId(), sqlSession); - ruleDao.deleteParam(persistedParam, sqlSession); - } - } - } - } - - void synchronizeTags(RuleDto persistedRule, RulesByRepository existingRules, Rule rule) { - Set existingSystemTags = Sets.newHashSet(); - List newTags = Lists.newArrayList(); - - Iterator tagsIterator = existingRules.tags(persistedRule.getId()).iterator(); - while (tagsIterator.hasNext()) { - RuleTagDto existingTag = tagsIterator.next(); - - String existingTagValue = existingTag.getTag(); - - if (existingTag.getType() == RuleTagType.SYSTEM) { - existingSystemTags.add(existingTagValue); - if (! rule.getTags().contains(existingTagValue)) { - ruleDao.deleteTag(existingTag, sqlSession); - tagsIterator.remove(); - } - } else { - if (rule.getTags().contains(existingTagValue)) { - // Existing admin tag with same value as system tag must be converted - ruleDao.deleteTag(existingTag, sqlSession); - tagsIterator.remove(); - existingSystemTags.add(existingTagValue); - RuleTagDto newTag = dtoFrom(existingTagValue, persistedRule.getId()); - ruleDao.insert(newTag, sqlSession); - newTags.add(newTag); - } - } - } - - for (String newTag: rule.getTags()) { - if (! existingSystemTags.contains(newTag)) { - RuleTagDto newTagDto = dtoFrom(newTag, persistedRule.getId()); - ruleDao.insert(newTagDto, sqlSession); - newTags.add(newTagDto); - } - } - - existingRules.tags.putAll(persistedRule.getId(), newTags); - } - - - private List saveNewRules(Collection rules, RulesByRepository existingRules) { - List registeredRules = newArrayList(); - for (Rule rule : rules) { - LOG.debug("Save new rule " + rule); - RuleDto newRule = dtoFrom(rule); - newRule.setCreatedAt(new Date()); - ruleDao.insert(newRule, sqlSession); - registeredRules.add(newRule); - - for(RuleParam param : rule.getParams()) { - RuleParamDto newParam = dtoFrom(param, newRule.getId()); - ruleDao.insert(newParam, sqlSession); - existingRules.params.put(newRule.getId(), newParam); - } - - for(String tag : rule.getTags()) { - RuleTagDto newTag = dtoFrom(tag, newRule.getId()); - ruleDao.insert(newTag, sqlSession); - existingRules.tags.put(newRule.getId(), newTag); - } - } - return registeredRules; - } - - private Collection disableDeprecatedRules(RulesByRepository existingRules, List registeredRules) { - List disabledRules = newArrayList(); - for (RuleDto rule : existingRules.rules()) { - if (!registeredRules.contains(rule)) { - disableRule(rule); - disabledRules.add(rule); - } - } - return disabledRules; - } - - private Collection disableDeprecatedRepositories(RulesByRepository existingRules) { - List disabledRules = newArrayList(); - for (final String repositoryKey : existingRules.repositories()) { - if (!Iterables.any(repositories, new Predicate() { - public boolean apply(RuleRepository input) { - return input.getKey().equals(repositoryKey); - } - })) { - for (RuleDto rule : existingRules.get(repositoryKey)) { - disableRule(rule); - disabledRules.add(rule); - } - } - } - return disabledRules; - } - - private void disableRule(RuleDto rule) { - if (!rule.getStatus().equals(Rule.STATUS_REMOVED)) { - LOG.info("Removing rule " + rule.getRuleKey()); - rule.setStatus(Rule.STATUS_REMOVED); - rule.setUpdatedAt(new Date()); - ruleDao.update(rule, sqlSession); - } - } - - private void removeActiveRulesOnDisabledRules(Set disabledRules) { - for (RuleDto rule : disabledRules) { - profilesManager.removeActivatedRules(rule.getId()); - } - } - - static RuleDto dtoFrom(Rule rule) { - return new RuleDto() - .setCardinality(rule.getCardinality()) - .setConfigKey(rule.getConfigKey()) - .setDescription(rule.getDescription()) - .setLanguage(rule.getLanguage()) - .setName(rule.getName()) - .setRepositoryKey(rule.getRepositoryKey()) - .setRuleKey(rule.getKey()) - .setSeverity(rule.getSeverity().ordinal()) - .setStatus(rule.getStatus()); - } - - static RuleParamDto dtoFrom(RuleParam param, Integer ruleId) { - return new RuleParamDto() - .setRuleId(ruleId) - .setDefaultValue(param.getDefaultValue()) - .setDescription(param.getDescription()) - .setName(param.getKey()) - .setType(param.getType()); - } - - static RuleTagDto dtoFrom(String tag, Integer ruleId) { - return new RuleTagDto() - .setRuleId(ruleId) - .setTag(tag) - .setType(RuleTagType.SYSTEM); - } - - static class RulesByRepository { - Multimap ruleRepositoryList; - Map rulesById; - Multimap params; - Multimap tags; - - RulesByRepository(List rules, List params, List tags) { - ruleRepositoryList = ArrayListMultimap.create(); - rulesById = Maps.newHashMap(); - for (RuleDto rule : rules) { - ruleRepositoryList.put(rule.getRepositoryKey(), rule); - rulesById.put(rule.getId(), rule); - } - this.params = ArrayListMultimap.create(); - for (RuleParamDto param: params) { - this.params.put(param.getRuleId(), param); - } - this.tags = ArrayListMultimap.create(); - for (RuleTagDto tag: tags) { - this.tags.put(tag.getRuleId(), tag); - } - } - - Collection get(String repositoryKey) { - return ruleRepositoryList.get(repositoryKey); - } - - Collection repositories() { - return ruleRepositoryList.keySet(); - } - - Collection rules() { - return ruleRepositoryList.values(); - } - - RuleDto ruleById(Integer id) { - return rulesById.get(id); - } - - Collection params(Integer ruleId) { - return params.get(ruleId); - } - - Collection tags(Integer ruleId) { - return tags.get(ruleId); - } - } -} diff --git a/sonar-server/src/main/java/org/sonar/server/startup/RegisterTechnicalDebtModel.java b/sonar-server/src/main/java/org/sonar/server/startup/RegisterTechnicalDebtModel.java index 172b58cb50d..4d84d6e446a 100644 --- a/sonar-server/src/main/java/org/sonar/server/startup/RegisterTechnicalDebtModel.java +++ b/sonar-server/src/main/java/org/sonar/server/startup/RegisterTechnicalDebtModel.java @@ -26,6 +26,7 @@ import org.sonar.api.utils.TimeProfiler; import org.sonar.api.utils.ValidationMessages; import org.sonar.core.technicaldebt.TechnicalDebtModelSynchronizer; import org.sonar.core.technicaldebt.TechnicalDebtRuleCache; +import org.sonar.server.rule.RuleRegistration; public final class RegisterTechnicalDebtModel { @@ -37,7 +38,7 @@ public final class RegisterTechnicalDebtModel { /** * @param registerRulesBeforeModels used only to be started after the creation of check templates */ - public RegisterTechnicalDebtModel(TechnicalDebtModelSynchronizer manager, RuleFinder ruleFinder, RegisterRules registerRulesBeforeModels) { + public RegisterTechnicalDebtModel(TechnicalDebtModelSynchronizer manager, RuleFinder ruleFinder, RuleRegistration registerRulesBeforeModels) { this.manager = manager; this.ruleFinder = ruleFinder; } diff --git a/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java b/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java index 0de182a42b3..373c1d0173d 100644 --- a/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java +++ b/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java @@ -34,7 +34,6 @@ import org.sonar.api.resources.Language; import org.sonar.api.resources.ResourceType; import org.sonar.api.resources.ResourceTypes; import org.sonar.api.rules.RulePriority; -import org.sonar.api.rules.RuleRepository; import org.sonar.api.test.MutableTestPlan; import org.sonar.api.test.MutableTestable; import org.sonar.api.test.TestPlan; @@ -58,18 +57,20 @@ import org.sonar.server.platform.ServerIdGenerator; import org.sonar.server.platform.ServerSettings; import org.sonar.server.platform.SettingsChangeNotifier; import org.sonar.server.plugins.*; +import org.sonar.server.rule.RuleRepositories; import org.sonar.server.rules.ProfilesConsole; -import org.sonar.server.rules.RulesConsole; import org.sonar.server.user.NewUserNotifier; import org.sonar.updatecenter.common.PluginReferential; import org.sonar.updatecenter.common.UpdateCenter; import org.sonar.updatecenter.common.Version; import javax.annotation.Nullable; - import java.net.InetAddress; import java.sql.Connection; -import java.util.*; +import java.util.Collection; +import java.util.Date; +import java.util.List; +import java.util.Map; import static com.google.common.collect.Lists.newArrayList; @@ -245,16 +246,16 @@ public final class JRubyFacade { } /* PROFILES CONSOLE : RULES AND METRIC THRESHOLDS */ - public List getRuleRepositories() { - return get(RulesConsole.class).getRepositories(); + public Collection getRuleRepositories() { + return get(RuleRepositories.class).repositories(); } - public RuleRepository getRuleRepository(String repositoryKey) { - return get(RulesConsole.class).getRepository(repositoryKey); + public RuleRepositories.Repository getRuleRepository(String repositoryKey) { + return get(RuleRepositories.class).repository(repositoryKey); } - public Set getRuleRepositoriesByLanguage(String languageKey) { - return get(RulesConsole.class).getRepositoriesByLanguage(languageKey); + public Collection getRuleRepositoriesByLanguage(String languageKey) { + return get(RuleRepositories.class).repositoriesForLang(languageKey); } // TODO move this to QProfiles @@ -303,7 +304,7 @@ public final class JRubyFacade { public void ruleSeverityChanged(int parentProfileId, int activeRuleId, int oldSeverityId, int newSeverityId, String userName) { getProfilesManager().ruleSeverityChanged(parentProfileId, activeRuleId, RulePriority.values()[oldSeverityId], - RulePriority.values()[newSeverityId], userName); + RulePriority.values()[newSeverityId], userName); } public void ruleDeactivated(int parentProfileId, int deactivatedRuleId, String userName) { @@ -457,10 +458,10 @@ public final class JRubyFacade { // notifier is null when creating the administrator in the migration script 011. if (notifier != null) { notifier.onNewUser(NewUserHandler.Context.builder() - .setLogin(fields.get("login")) - .setName(fields.get("name")) - .setEmail(fields.get("email")) - .build()); + .setLogin(fields.get("login")) + .setName(fields.get("name")) + .setEmail(fields.get("email")) + .build()); } } diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/rules_configuration_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/rules_configuration_controller.rb index de64892a0b3..5c5a24dcdf3 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/rules_configuration_controller.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/rules_configuration_controller.rb @@ -38,7 +38,7 @@ class RulesConfigurationController < ApplicationController init_params() - @select_repositories = ANY_SELECTION + java_facade.getRuleRepositoriesByLanguage(@profile.language).collect { |repo| [repo.getName(true), repo.getKey()] }.sort + @select_repositories = ANY_SELECTION + java_facade.getRuleRepositoriesByLanguage(@profile.language).collect { |repo| [repo.name(), repo.key()] }.sort @select_priority = ANY_SELECTION + RULE_PRIORITIES @select_activation = [[message('any'), 'any'], [message('active'), STATUS_ACTIVE], [message('inactive'), STATUS_INACTIVE]] @select_inheritance = [[message('any'), 'any'], [message('rules_configuration.not_inherited'), 'NOT'], [message('rules_configuration.inherited'), 'INHERITED'], diff --git a/sonar-server/src/test/java/org/sonar/server/rule/RuleDefinitionsLoaderTest.java b/sonar-server/src/test/java/org/sonar/server/rule/RuleDefinitionsLoaderTest.java new file mode 100644 index 00000000000..8433bce0713 --- /dev/null +++ b/sonar-server/src/test/java/org/sonar/server/rule/RuleDefinitionsLoaderTest.java @@ -0,0 +1,77 @@ +/* + * 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.rule; + +import org.junit.Test; +import org.sonar.api.rule.RuleDefinitions; + +import static org.fest.assertions.Assertions.assertThat; + +public class RuleDefinitionsLoaderTest { + @Test + public void no_definitions() { + RuleRepositories repositories = new RuleRepositories(); + + RuleDefinitions.Context context = new RuleDefinitionsLoader(repositories).load(); + + assertThat(context.repositories()).isEmpty(); + assertThat(repositories.repositories()).isEmpty(); + } + + @Test + public void load_definitions() { + RuleRepositories repositories = new RuleRepositories(); + + RuleDefinitions.Context context = new RuleDefinitionsLoader(repositories, new RuleDefinitions[]{ + new FindbugsDefinitions(), new SquidDefinitions() + }).load(); + + assertThat(context.repositories()).hasSize(2); + assertThat(context.repository("findbugs")).isNotNull(); + assertThat(context.repository("squid")).isNotNull(); + assertThat(repositories.repositories()).hasSize(2); + assertThat(repositories.repository("findbugs")).isNotNull(); + assertThat(repositories.repository("squid")).isNotNull(); + } + + static class FindbugsDefinitions implements RuleDefinitions { + @Override + public void define(Context context) { + NewRepository repo = context.newRepository("findbugs", "java"); + repo.setName("Findbugs"); + repo.newRule("ABC") + .setName("ABC") + .setHtmlDescription("Description of ABC"); + repo.done(); + } + } + + static class SquidDefinitions implements RuleDefinitions { + @Override + public void define(Context context) { + NewRepository repo = context.newRepository("squid", "java"); + repo.setName("Squid"); + repo.newRule("DEF") + .setName("DEF") + .setHtmlDescription("Description of DEF"); + repo.done(); + } + } +} 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 new file mode 100644 index 00000000000..6488f3514bc --- /dev/null +++ b/sonar-server/src/test/java/org/sonar/server/rule/RuleRegistrationTest.java @@ -0,0 +1,263 @@ +/* + * 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.rule; + +import org.junit.Before; +import org.junit.Test; +import org.sonar.api.rule.RuleDefinitions; +import org.sonar.api.rule.Severity; +import org.sonar.core.persistence.AbstractDaoTestCase; +import org.sonar.core.persistence.MyBatis; +import org.sonar.core.qualityprofile.db.ActiveRuleDao; +import org.sonar.core.rule.RuleDao; +import org.sonar.server.configuration.ProfilesManager; + +import static org.fest.assertions.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +public class RuleRegistrationTest extends AbstractDaoTestCase { + + private static final String[] EXCLUDED_COLUMN_NAMES = { + "created_at", "updated_at", "note_data", "note_user_login", "note_created_at", "note_updated_at"}; + + RuleRegistration task; + ProfilesManager profilesManager; + RuleRegistry ruleRegistry; + MyBatis myBatis; + RuleDao ruleDao; + ActiveRuleDao activeRuleDao; + + @Before + public void before() { + profilesManager = mock(ProfilesManager.class); + ruleRegistry = mock(RuleRegistry.class); + myBatis = getMyBatis(); + ruleDao = new RuleDao(myBatis); + activeRuleDao = new ActiveRuleDao(myBatis); + task = new RuleRegistration(new RuleDefinitionsLoader(mock(RuleRepositories.class), new RuleDefinitions[]{new FakeRepository()}), + profilesManager, ruleRegistry, myBatis, ruleDao, activeRuleDao); + } + + @Test + public void should_insert_new_rules() { + setupData("shared"); + task.start(); + + checkTables("should_insert_new_rules", EXCLUDED_COLUMN_NAMES, "rules", "rules_parameters", "rule_tags"); + } + + @Test + public void should_update_template_rule_language() { + setupData("should_update_template_rule_language"); + task.start(); + + checkTables("should_update_template_rule_language", EXCLUDED_COLUMN_NAMES, "rules"); + } + + @Test + public void should_notify_for_removed_rules() { + setupData("shared"); + task.start(); + + verify(profilesManager).removeActivatedRules(1); + } + + @Test + public void should_reactivate_disabled_rules() { + setupData("should_reactivate_disabled_rules"); + task.start(); + + checkTables("should_reactivate_disabled_rules", EXCLUDED_COLUMN_NAMES, "rules"); + + assertThat(ruleDao.selectById(1).getUpdatedAt()).isNotNull(); + } + + @Test + public void should_not_reactivate_disabled_template_rules() { + setupData("should_not_reactivate_disabled_template_rules"); + task.start(); + + checkTables("should_not_reactivate_disabled_template_rules", EXCLUDED_COLUMN_NAMES, "rules"); + } + + @Test + public void should_disable_deprecated_active_rules() { + setupData("should_disable_deprecated_active_rules"); + task.start(); + + checkTables("should_disable_deprecated_active_rules", EXCLUDED_COLUMN_NAMES, "rules"); + } + + @Test + public void should_disable_deprecated_active_rule_params() { + setupData("should_disable_deprecated_active_rule_params"); + task.start(); + + checkTables("should_disable_deprecated_active_rule_params", EXCLUDED_COLUMN_NAMES, "rules", "rules_parameters", "active_rules", "active_rule_parameters"); + } + + @Test + public void should_disable_deprecated_rules() { + setupData("should_disable_deprecated_rules"); + task.start(); + + checkTables("should_disable_deprecated_rules", EXCLUDED_COLUMN_NAMES, "rules", "rules_parameters"); + } + + @Test + public void should_update_rule_fields() { + setupData("updadeRuleFields"); + task.start(); + + checkTables("updadeRuleFields", EXCLUDED_COLUMN_NAMES, "rules", "rules_parameters", "rule_tags"); + } + + @Test + public void should_update_rule_parameters() { + setupData("should_update_rule_parameters"); + task.start(); + + checkTables("should_update_rule_parameters", EXCLUDED_COLUMN_NAMES, "rules", "rules_parameters"); + } + + @Test + public void should_not_disable_template_rules_if_parent_is_enabled() { + setupData("doNotDisableUserRulesIfParentIsEnabled"); + task.start(); + + checkTables("doNotDisableUserRulesIfParentIsEnabled", EXCLUDED_COLUMN_NAMES, "rules"); + } + + @Test + public void should_disable_template_rules_if_parent_is_disabled() { + setupData("disableUserRulesIfParentIsDisabled"); + task.start(); + + checkTables("disableUserRulesIfParentIsDisabled", EXCLUDED_COLUMN_NAMES, "rules"); + } + + @Test + public void should_not_disable_manual_rules() { + // the hardcoded repository "manual" is used for manual violations + setupData("shouldNotDisableManualRules"); + task.start(); + + checkTables("shouldNotDisableManualRules", EXCLUDED_COLUMN_NAMES, "rules"); + } + + @Test + public void test_high_number_of_rules() { + task = new RuleRegistration(new RuleDefinitionsLoader(mock(RuleRepositories.class), new RuleDefinitions[]{new BigRepository()}), + profilesManager, ruleRegistry, myBatis, ruleDao, activeRuleDao); + + setupData("shared"); + task.start(); + + // There is already one rule in DB + assertThat(ruleDao.selectAll()).hasSize(BigRepository.SIZE + 1); + assertThat(ruleDao.selectParameters()).hasSize(BigRepository.SIZE * 20); + assertThat(ruleDao.selectTags(getMyBatis().openSession())).hasSize(BigRepository.SIZE * 3); + } + + @Test + public void should_insert_extended_repositories() { + task = new RuleRegistration(new RuleDefinitionsLoader(mock(RuleRepositories.class), new RuleDefinitions[]{ + new FindbugsRepository(), new FbContribRepository()}), + profilesManager, ruleRegistry, myBatis, ruleDao, activeRuleDao); + + setupData("empty"); + task.start(); + + checkTables("should_insert_extended_repositories", EXCLUDED_COLUMN_NAMES, "rules"); + } + + static class FakeRepository implements RuleDefinitions { + @Override + public void define(Context context) { + NewRepository repo = context.newRepository("fake", "java"); + + NewRule rule1 = repo.newRule("rule1") + .setName("One") + .setHtmlDescription("Description of One") + .setDefaultSeverity(Severity.BLOCKER) + .setMetadata("config1") + .setTags("tag1", "tag3", "tag5"); + rule1.newParam("param1").setDescription("parameter one").setDefaultValue("default value one"); + rule1.newParam("param2").setDescription("parameter two").setDefaultValue("default value two"); + + repo.newRule("rule2") + .setName("Two") + .setHtmlDescription("Description of Two") + .setDefaultSeverity(Severity.INFO) + .setStatus(Status.DEPRECATED); + repo.done(); + } + } + + static class BigRepository implements RuleDefinitions { + static final int SIZE = 500; + + @Override + public void define(Context context) { + NewRepository repo = context.newRepository("big", "java"); + for (int i = 0; i < SIZE; i++) { + NewRule rule = repo.newRule("rule" + i) + .setName("name of " + i) + .setHtmlDescription("description of " + i) + .setDefaultSeverity(Severity.BLOCKER) + .setMetadata("config1") + .setTags("tag1", "tag3", "tag5"); + for (int j = 0; j < 20; j++) { + rule.newParam("param" + j); + } + + } + repo.done(); + } + } + + static class FindbugsRepository implements RuleDefinitions { + @Override + public void define(Context context) { + NewRepository repo = context.newRepository("findbugs", "java"); + repo.newRule("rule1") + .setName("Rule One") + .setHtmlDescription("Description of Rule One"); + repo.done(); + } + } + + static class FbContribRepository implements RuleDefinitions { + @Override + public void define(Context context) { + NewExtendedRepository repo = context.extendRepository("findbugs", "java"); + repo.newRule("rule2") + .setName("Rule Two") + .setHtmlDescription("Description of Rule Two"); + repo.done(); + } + } +} + + + + diff --git a/sonar-server/src/test/java/org/sonar/server/rule/RuleRegistryTest.java b/sonar-server/src/test/java/org/sonar/server/rule/RuleRegistryTest.java index b61ff86d41a..0ac7a1b4edf 100644 --- a/sonar-server/src/test/java/org/sonar/server/rule/RuleRegistryTest.java +++ b/sonar-server/src/test/java/org/sonar/server/rule/RuleRegistryTest.java @@ -58,6 +58,7 @@ import static org.elasticsearch.index.query.FilterBuilders.hasChildFilter; import static org.elasticsearch.index.query.FilterBuilders.hasParentFilter; import static org.elasticsearch.index.query.FilterBuilders.termFilter; import static org.fest.assertions.Assertions.assertThat; +import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -261,7 +262,7 @@ public class RuleRegistryTest { List rules = ImmutableList.of(rule1, rule2); assertThat(esSetup.exists("rules", "rule", "3")).isTrue(); - when(ruleDao.selectNonManual()).thenReturn(rules); + when(ruleDao.selectNonManual(any(SqlSession.class))).thenReturn(rules); final Multimap params = ArrayListMultimap.create(); final Multimap tags = ArrayListMultimap.create(); registry.bulkRegisterRules(rules, params, tags); diff --git a/sonar-server/src/test/java/org/sonar/server/rule/RuleRepositoriesTest.java b/sonar-server/src/test/java/org/sonar/server/rule/RuleRepositoriesTest.java new file mode 100644 index 00000000000..94b228b516d --- /dev/null +++ b/sonar-server/src/test/java/org/sonar/server/rule/RuleRepositoriesTest.java @@ -0,0 +1,82 @@ +/* + * 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.rule; + +import org.junit.Test; +import org.sonar.api.rule.RuleDefinitions; + +import static org.fest.assertions.Assertions.assertThat; + +public class RuleRepositoriesTest { + @Test + public void should_register_repositories() { + RuleDefinitions.Context context = new RuleDefinitions.Context(); + new SquidDefinitions().define(context); + new FindbugsDefinitions().define(context); + + RuleRepositories repositories = new RuleRepositories(); + repositories.register(context); + + RuleRepositories.Repository findbugs = repositories.repository("findbugs"); + assertThat(findbugs).isNotNull(); + assertThat(findbugs.key()).isEqualTo("findbugs"); + assertThat(findbugs.name()).isEqualTo("Findbugs"); + assertThat(findbugs.language()).isEqualTo("java"); + assertThat(findbugs.getKey()).isEqualTo("findbugs"); + assertThat(findbugs.getName()).isEqualTo("Findbugs"); + assertThat(findbugs.getLanguage()).isEqualTo("java"); + + RuleRepositories.Repository squid = repositories.repository("squid"); + assertThat(squid).isNotNull(); + assertThat(squid.key()).isEqualTo("squid"); + assertThat(squid.name()).isEqualTo("Squid"); + assertThat(squid.language()).isEqualTo("java"); + + assertThat(repositories.repositories()).containsOnly(findbugs, squid); + assertThat(repositories.repositoriesForLang("java")).containsOnly(findbugs, squid); + + // test equals() and hashCode() + assertThat(findbugs).isEqualTo(findbugs).isNotEqualTo(squid).isNotEqualTo("findbugs").isNotEqualTo(null); + } + + static class FindbugsDefinitions implements RuleDefinitions { + @Override + public void define(Context context) { + NewRepository repo = context.newRepository("findbugs", "java"); + repo.setName("Findbugs"); + repo.newRule("ABC") + .setName("ABC") + .setHtmlDescription("Description of ABC"); + repo.done(); + } + } + + static class SquidDefinitions implements RuleDefinitions { + @Override + public void define(Context context) { + NewRepository repo = context.newRepository("squid", "java"); + repo.setName("Squid"); + repo.newRule("DEF") + .setName("DEF") + .setHtmlDescription("Description of DEF"); + repo.done(); + } + } +} diff --git a/sonar-server/src/test/java/org/sonar/server/rules/RulesConsoleTest.java b/sonar-server/src/test/java/org/sonar/server/rules/RulesConsoleTest.java deleted file mode 100644 index 9acbe5500eb..00000000000 --- a/sonar-server/src/test/java/org/sonar/server/rules/RulesConsoleTest.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.server.rules; - -import org.hamcrest.Matchers; -import org.junit.Test; -import org.sonar.api.rules.Rule; -import org.sonar.api.rules.RuleRepository; - -import java.util.Collections; -import java.util.List; - -import static org.hamcrest.CoreMatchers.not; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; - -public class RulesConsoleTest { - @Test - public void shouldIgnoreRepositoryExtensions() throws Exception { - RuleRepository[] repositories = new RuleRepository[]{ - new FakeRepository("findbugs", "java"), - new FakeRepository("findbugs", "java"), // for example fb-contrib - }; - RulesConsole console = new RulesConsole(repositories); - - assertThat(console.getRepository("findbugs"), not(Matchers.nullValue())); - assertThat(console.getRepositoriesByLanguage("java").size(), is(1)); - } - - private static class FakeRepository extends RuleRepository { - - private FakeRepository(String key, String language) { - super(key, language); - } - - @Override - public List createRules() { - return Collections.emptyList(); - } - } -} - - diff --git a/sonar-server/src/test/java/org/sonar/server/startup/RegisterRulesTest.java b/sonar-server/src/test/java/org/sonar/server/startup/RegisterRulesTest.java deleted file mode 100644 index d28efe203bb..00000000000 --- a/sonar-server/src/test/java/org/sonar/server/startup/RegisterRulesTest.java +++ /dev/null @@ -1,367 +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.server.startup; - -import org.junit.Before; -import org.junit.Test; -import org.sonar.api.rules.Rule; -import org.sonar.api.rules.RulePriority; -import org.sonar.api.rules.RuleRepository; -import org.sonar.api.utils.SonarException; -import org.sonar.core.i18n.RuleI18nManager; -import org.sonar.core.persistence.AbstractDaoTestCase; -import org.sonar.core.persistence.MyBatis; -import org.sonar.core.qualityprofile.db.ActiveRuleDao; -import org.sonar.core.rule.RuleDao; -import org.sonar.server.configuration.ProfilesManager; -import org.sonar.server.rule.RuleRegistry; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import static org.fest.assertions.Assertions.assertThat; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.*; - -public class RegisterRulesTest extends AbstractDaoTestCase { - - private static final String[] EXCLUDED_COLUMN_NAMES = { - "created_at", "updated_at", "note_data", "note_user_login", "note_created_at", "note_updated_at"}; - - RegisterRules task; - ProfilesManager profilesManager; - RuleRegistry ruleRegistry; - RuleI18nManager ruleI18nManager; - MyBatis myBatis; - RuleDao ruleDao; - ActiveRuleDao activeRuleDao; - - @Before - public void init() { - profilesManager = mock(ProfilesManager.class); - ruleRegistry = mock(RuleRegistry.class); - ruleI18nManager = mock(RuleI18nManager.class); - myBatis = getMyBatis(); - ruleDao = new RuleDao(myBatis); - activeRuleDao = new ActiveRuleDao(myBatis); - task = new RegisterRules(new RuleRepository[]{new FakeRepository()}, ruleI18nManager, profilesManager, ruleRegistry, myBatis, ruleDao, activeRuleDao); - } - - @Test - public void should_save_new_repositories() { - setupData("shared"); - task.start(); - - checkTables("should_save_new_repositories", EXCLUDED_COLUMN_NAMES, "rules", "rules_parameters", "rule_tags"); - } - - @Test - public void should_update_template_rule() { - setupData("should_update_template_rule_language"); - task.start(); - - checkTables("should_update_template_rule_language", EXCLUDED_COLUMN_NAMES, "rules"); - } - - @Test - public void should_notify_for_removed_rules() { - setupData("shared"); - task.start(); - - verify(profilesManager).removeActivatedRules(anyInt()); - } - - @Test - public void should_reactivate_disabled_rules() { - setupData("reactivateDisabledRules"); - task.start(); - - checkTables("reactivateDisabledRules", EXCLUDED_COLUMN_NAMES, "rules"); - - assertThat(ruleDao.selectById(1).getUpdatedAt()).isNotNull(); - } - - @Test - public void should_not_reactivate_disabled_template_rules() { - setupData("should_reactivate_disabled_template_rules"); - task.start(); - - checkTables("should_reactivate_disabled_template_rules", EXCLUDED_COLUMN_NAMES, "rules"); - } - - @Test - public void should_not_update_already_disabled_rules() { - setupData("notUpdateAlreadyDisabledRule"); - task.start(); - - checkTables("should_save_new_repositories", EXCLUDED_COLUMN_NAMES, "rules"); - - assertThat(ruleDao.selectById(1).getUpdatedAt()).isNull(); - } - - @Test - public void should_disable_deprecated_active_rules() { - setupData("disableDeprecatedActiveRules"); - task.start(); - - checkTables("disableDeprecatedActiveRules", EXCLUDED_COLUMN_NAMES, "rules"); - } - - @Test - public void should_disable_deprecated_active_rule_parameters() { - setupData("disableDeprecatedActiveRuleParameters"); - task.start(); - - checkTables("disableDeprecatedActiveRuleParameters", EXCLUDED_COLUMN_NAMES, "rules", "rules_parameters", "active_rules", "active_rule_parameters"); - } - - @Test - public void should_disable_deprecated_rules() { - setupData("disableDeprecatedRules"); - task.start(); - - checkTables("disableDeprecatedRules", EXCLUDED_COLUMN_NAMES, "rules", "rules_parameters"); - } - - @Test - public void should_update_rule_fields() { - setupData("updadeRuleFields"); - task.start(); - - checkTables("updadeRuleFields", EXCLUDED_COLUMN_NAMES, "rules", "rules_parameters", "rule_tags"); - } - - @Test - public void should_store_bundle_name_and_description_in_database() { - setupData("updadeRuleFields"); - String i18nName = "The One"; - String i18nDescription = "The Description of One"; - when(ruleI18nManager.getName("fake", "rule1")).thenReturn(i18nName); - when(ruleI18nManager.getDescription("fake", "rule1")).thenReturn(i18nDescription); - task.start(); - - checkTables("should_store_bundle_name_and_description_in_database", EXCLUDED_COLUMN_NAMES, "rules"); - } - - @Test - public void should_update_rule_parameters() { - setupData("updateRuleParameters"); - task.start(); - - checkTables("updateRuleParameters", EXCLUDED_COLUMN_NAMES, "rules", "rules_parameters"); - } - - @Test - public void should_not_disable_template_rules_if_parent_is_enabled() { - setupData("doNotDisableUserRulesIfParentIsEnabled"); - task.start(); - - checkTables("doNotDisableUserRulesIfParentIsEnabled", EXCLUDED_COLUMN_NAMES, "rules"); - } - - @Test - public void should_disable_template_rules_if_parent_is_disabled() { - setupData("disableUserRulesIfParentIsDisabled"); - task.start(); - - checkTables("disableUserRulesIfParentIsDisabled", EXCLUDED_COLUMN_NAMES, "rules"); - } - - @Test - public void should_not_disable_manual_rules() { - // the hardcoded repository "manual" is used for manual violations - setupData("shouldNotDisableManualRules"); - task.start(); - - checkTables("shouldNotDisableManualRules", EXCLUDED_COLUMN_NAMES, "rules"); - } - - @Test - public void volume_testing() { - task = new RegisterRules(new RuleRepository[]{new VolumeRepository()}, ruleI18nManager, profilesManager, ruleRegistry, myBatis, ruleDao, activeRuleDao); - setupData("shared"); - task.start(); - - // There is already one rule in DB - assertThat(ruleDao.selectAll()).hasSize(VolumeRepository.SIZE + 1); - } - - // SONAR-3305 - @Test - public void should_fail_with_rule_without_name() throws Exception { - task = new RegisterRules(new RuleRepository[]{new RuleWithoutNameRepository()}, ruleI18nManager, profilesManager, ruleRegistry, myBatis, ruleDao, activeRuleDao); - setupData("shared"); - - // the rule has no name, it should fail - try { - task.start(); - fail("Rule must have a name"); - } catch (SonarException e) { - assertThat(e.getMessage()).contains("must have a name"); - } - - // now it is ok, the rule has a name in the English bundle - when(ruleI18nManager.getName(anyString(), anyString())).thenReturn("Name"); - when(ruleI18nManager.getDescription(anyString(), anyString())).thenReturn("Description"); - task.start(); - } - - // SONAR-3769 - @Test - public void should_fail_with_rule_with_blank_name() throws Exception { - task = new RegisterRules(new RuleRepository[]{new RuleWithoutNameRepository()}, ruleI18nManager, profilesManager, ruleRegistry, myBatis, ruleDao, activeRuleDao); - setupData("shared"); - - // the rule has no name, it should fail - try { - task.start(); - fail("Rule must have a name"); - } catch (SonarException e) { - assertThat(e.getMessage()).contains("must have a name"); - } - } - - // SONAR-3305 - @Test - public void should_fail_with_rule_without_description() throws Exception { - when(ruleI18nManager.getName(anyString(), anyString())).thenReturn("Name"); - task = new RegisterRules(new RuleRepository[]{new RuleWithoutDescriptionRepository()}, ruleI18nManager, profilesManager, ruleRegistry, myBatis, ruleDao, activeRuleDao); - setupData("shared"); - - // the rule has no name, it should fail - try { - task.start(); - fail("Rule must have a description"); - } catch (SonarException e) { - assertThat(e.getMessage()).contains("must have a description"); - } - - // now it is ok, the rule has a name & a description in the English bundle - when(ruleI18nManager.getName(anyString(), anyString())).thenReturn("Name"); - when(ruleI18nManager.getDescription(anyString(), anyString())).thenReturn("Description"); - task.start(); - } - - // http://jira.codehaus.org/browse/SONAR-3722 - @Test - public void should_fail_with_rule_without_name_in_bundle() throws Exception { - task = new RegisterRules(new RuleRepository[]{new RuleWithoutDescriptionRepository()}, ruleI18nManager, profilesManager, ruleRegistry, myBatis, ruleDao, activeRuleDao); - setupData("shared"); - - // the rule has no name, it should fail - try { - task.start(); - fail("Rule must have a description"); - } catch (SonarException e) { - assertThat(e.getMessage()).contains("No description found for the rule 'Rule 1' (repository: rule-without-description-repo) " + - "because the entry 'rule.rule-without-description-repo.rule1.name' is missing from the bundle."); - } - } - -} - -class FakeRepository extends RuleRepository { - public FakeRepository() { - super("fake", "java"); - } - - @Override - public List createRules() { - Rule rule1 = Rule.create("fake", "rule1", "One"); - rule1.setDescription("Description of One"); - rule1.setSeverity(RulePriority.BLOCKER); - rule1.setConfigKey("config1"); - rule1.createParameter("param1").setDescription("parameter one").setDefaultValue("default value one"); - rule1.createParameter("param2").setDescription("parameter two").setDefaultValue("default value two"); - rule1.setTags("tag1", "tag3", "tag5"); - - Rule rule2 = Rule.create("fake", "rule2", "Two"); - rule2.setDescription("Description of Two"); - rule2.setSeverity(RulePriority.INFO); - rule2.setStatus(Rule.STATUS_DEPRECATED); - - return Arrays.asList(rule1, rule2); - } -} - -class RuleWithoutNameRepository extends RuleRepository { - public RuleWithoutNameRepository() { - super("rule-without-name-repo", "java"); - } - - @Override - public List createRules() { - // Rules must not have empty name - Rule rule1 = Rule.create("fake", "rule1", null); - return Arrays.asList(rule1); - } -} - -class RuleWithoutDescriptionRepository extends RuleRepository { - public RuleWithoutDescriptionRepository() { - super("rule-without-description-repo", "java"); - } - - @Override - public List createRules() { - // Rules must not have empty description - Rule rule1 = Rule.create("fake", "rule1", "Rule 1"); - return Arrays.asList(rule1); - } -} - -class VolumeRepository extends RuleRepository { - static final int SIZE = 500; - - public VolumeRepository() { - super("volume", "java"); - } - - @Override - public List createRules() { - List rules = new ArrayList(); - for (int i = 0; i < SIZE; i++) { - Rule rule = Rule.create("volume", "rule" + i, "name of " + i); - rule.setDescription("description of " + i); - rule.setSeverity(RulePriority.BLOCKER); - for (int j = 0; j < 20; j++) { - rule.createParameter("param" + j); - } - rules.add(rule); - } - return rules; - } -} - -class RuleWithUnkownStatusRepository extends RuleRepository { - public RuleWithUnkownStatusRepository() { - super("rule-with-unknwon-status-repo", "java"); - } - - @Override - public List createRules() { - Rule rule1 = Rule.create("fake", "rule1", "rule1").setDescription("Description").setStatus("UNKNOWN"); - return Arrays.asList(rule1); - } -} diff --git a/sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/disableUserRulesIfParentIsDisabled-result.xml b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/disableUserRulesIfParentIsDisabled-result.xml similarity index 95% rename from sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/disableUserRulesIfParentIsDisabled-result.xml rename to sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/disableUserRulesIfParentIsDisabled-result.xml index 69b3d0ea860..9b4c8e7fec4 100644 --- a/sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/disableUserRulesIfParentIsDisabled-result.xml +++ b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/disableUserRulesIfParentIsDisabled-result.xml @@ -15,7 +15,7 @@ - diff --git a/sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/disableUserRulesIfParentIsDisabled.xml b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/disableUserRulesIfParentIsDisabled.xml similarity index 100% rename from sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/disableUserRulesIfParentIsDisabled.xml rename to sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/disableUserRulesIfParentIsDisabled.xml diff --git a/sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/doNotDisableUserRulesIfParentIsEnabled-result.xml b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/doNotDisableUserRulesIfParentIsEnabled-result.xml similarity index 90% rename from sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/doNotDisableUserRulesIfParentIsEnabled-result.xml rename to sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/doNotDisableUserRulesIfParentIsEnabled-result.xml index 4aa90f36686..ddc9c940e81 100644 --- a/sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/doNotDisableUserRulesIfParentIsEnabled-result.xml +++ b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/doNotDisableUserRulesIfParentIsEnabled-result.xml @@ -6,7 +6,7 @@ - diff --git a/sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/doNotDisableUserRulesIfParentIsEnabled.xml b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/doNotDisableUserRulesIfParentIsEnabled.xml similarity index 100% rename from sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/doNotDisableUserRulesIfParentIsEnabled.xml rename to sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/doNotDisableUserRulesIfParentIsEnabled.xml diff --git a/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/empty.xml b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/empty.xml new file mode 100644 index 00000000000..5ed00ba028b --- /dev/null +++ b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/empty.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/shared.xml b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/shared.xml similarity index 100% rename from sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/shared.xml rename to sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/shared.xml diff --git a/sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/shouldNotDisableManualRules-result.xml b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/shouldNotDisableManualRules-result.xml similarity index 93% rename from sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/shouldNotDisableManualRules-result.xml rename to sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/shouldNotDisableManualRules-result.xml index fed6aea121e..7aa9839d5ad 100644 --- a/sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/shouldNotDisableManualRules-result.xml +++ b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/shouldNotDisableManualRules-result.xml @@ -9,7 +9,7 @@ - diff --git a/sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/shouldNotDisableManualRules.xml b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/shouldNotDisableManualRules.xml similarity index 100% rename from sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/shouldNotDisableManualRules.xml rename to sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/shouldNotDisableManualRules.xml diff --git a/sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/disableDeprecatedActiveRuleParameters-result.xml b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_disable_deprecated_active_rule_params-result.xml similarity index 94% rename from sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/disableDeprecatedActiveRuleParameters-result.xml rename to sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_disable_deprecated_active_rule_params-result.xml index e373f4021ae..d802714fa76 100644 --- a/sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/disableDeprecatedActiveRuleParameters-result.xml +++ b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_disable_deprecated_active_rule_params-result.xml @@ -3,7 +3,7 @@ - diff --git a/sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/disableDeprecatedActiveRuleParameters.xml b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_disable_deprecated_active_rule_params.xml similarity index 100% rename from sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/disableDeprecatedActiveRuleParameters.xml rename to sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_disable_deprecated_active_rule_params.xml diff --git a/sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/disableDeprecatedActiveRules-result.xml b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_disable_deprecated_active_rules-result.xml similarity index 93% rename from sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/disableDeprecatedActiveRules-result.xml rename to sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_disable_deprecated_active_rules-result.xml index 20ae08d4353..9d782421156 100644 --- a/sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/disableDeprecatedActiveRules-result.xml +++ b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_disable_deprecated_active_rules-result.xml @@ -9,7 +9,7 @@ - diff --git a/sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/disableDeprecatedActiveRules.xml b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_disable_deprecated_active_rules.xml similarity index 100% rename from sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/disableDeprecatedActiveRules.xml rename to sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_disable_deprecated_active_rules.xml diff --git a/sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/should_disable_deprecated_repositories-result.xml b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_disable_deprecated_repositories-result.xml similarity index 100% rename from sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/should_disable_deprecated_repositories-result.xml rename to sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_disable_deprecated_repositories-result.xml diff --git a/sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/disableDeprecatedRules-result.xml b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_disable_deprecated_rules-result.xml similarity index 95% rename from sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/disableDeprecatedRules-result.xml rename to sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_disable_deprecated_rules-result.xml index f2d4e54c179..7dfc0d94ec6 100644 --- a/sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/disableDeprecatedRules-result.xml +++ b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_disable_deprecated_rules-result.xml @@ -14,7 +14,7 @@ - diff --git a/sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/disableDeprecatedRules.xml b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_disable_deprecated_rules.xml similarity index 100% rename from sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/disableDeprecatedRules.xml rename to sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_disable_deprecated_rules.xml diff --git a/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_insert_extended_repositories-result.xml b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_insert_extended_repositories-result.xml new file mode 100644 index 00000000000..f8650b84e27 --- /dev/null +++ b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_insert_extended_repositories-result.xml @@ -0,0 +1,9 @@ + + + + + + + \ No newline at end of file diff --git a/sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/should_save_new_repositories-result.xml b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_insert_new_rules-result.xml similarity index 93% rename from sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/should_save_new_repositories-result.xml rename to sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_insert_new_rules-result.xml index 065440b19bd..28f0a4b0036 100644 --- a/sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/should_save_new_repositories-result.xml +++ b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_insert_new_rules-result.xml @@ -11,7 +11,7 @@ - \ No newline at end of file diff --git a/sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/should_reactivate_disabled_template_rules-result.xml b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_not_reactivate_disabled_template_rules-result.xml similarity index 90% rename from sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/should_reactivate_disabled_template_rules-result.xml rename to sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_not_reactivate_disabled_template_rules-result.xml index 3352ac62fbf..92686cf2fac 100644 --- a/sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/should_reactivate_disabled_template_rules-result.xml +++ b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_not_reactivate_disabled_template_rules-result.xml @@ -6,7 +6,7 @@ - diff --git a/sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/should_reactivate_disabled_template_rules.xml b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_not_reactivate_disabled_template_rules.xml similarity index 87% rename from sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/should_reactivate_disabled_template_rules.xml rename to sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_not_reactivate_disabled_template_rules.xml index a90042bd505..17e94e974ca 100644 --- a/sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/should_reactivate_disabled_template_rules.xml +++ b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_not_reactivate_disabled_template_rules.xml @@ -1,9 +1,9 @@ + status="REMOVED" priority="4" cardinality="SINGLE" parent_id="[null]" language="java"/> + status="REMOVED" priority="4" cardinality="SINGLE" parent_id="1" language="java"/> diff --git a/sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/notUpdateAlreadyDisabledRule-result.xml b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_not_update_already_disabled_rules-result.xml similarity index 100% rename from sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/notUpdateAlreadyDisabledRule-result.xml rename to sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_not_update_already_disabled_rules-result.xml diff --git a/sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/notUpdateAlreadyDisabledRule.xml b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_not_update_already_disabled_rules.xml similarity index 100% rename from sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/notUpdateAlreadyDisabledRule.xml rename to sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_not_update_already_disabled_rules.xml diff --git a/sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/reactivateDisabledRules-result.xml b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_reactivate_disabled_rules-result.xml similarity index 86% rename from sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/reactivateDisabledRules-result.xml rename to sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_reactivate_disabled_rules-result.xml index 5efffba3572..18f0f55b16e 100644 --- a/sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/reactivateDisabledRules-result.xml +++ b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_reactivate_disabled_rules-result.xml @@ -3,7 +3,7 @@ - diff --git a/sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/reactivateDisabledRules.xml b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_reactivate_disabled_rules.xml similarity index 71% rename from sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/reactivateDisabledRules.xml rename to sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_reactivate_disabled_rules.xml index 6fa69b5d660..146807e3afc 100644 --- a/sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/reactivateDisabledRules.xml +++ b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_reactivate_disabled_rules.xml @@ -1,6 +1,6 @@ - diff --git a/sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/should_store_bundle_name_and_description_in_database-result.xml b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_store_bundle_name_and_description_in_database-result.xml similarity index 100% rename from sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/should_store_bundle_name_and_description_in_database-result.xml rename to sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_store_bundle_name_and_description_in_database-result.xml diff --git a/sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/updateRuleParameters-result.xml b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_update_rule_parameters-result.xml similarity index 91% rename from sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/updateRuleParameters-result.xml rename to sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_update_rule_parameters-result.xml index d8e3f0e72e3..337a28e1605 100644 --- a/sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/updateRuleParameters-result.xml +++ b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_update_rule_parameters-result.xml @@ -5,7 +5,7 @@ - diff --git a/sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/updateRuleParameters.xml b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_update_rule_parameters.xml similarity index 100% rename from sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/updateRuleParameters.xml rename to sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_update_rule_parameters.xml diff --git a/sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/should_update_template_rule_language-result.xml b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_update_template_rule_language-result.xml similarity index 83% rename from sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/should_update_template_rule_language-result.xml rename to sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_update_template_rule_language-result.xml index 617e118a29f..d59dce6a2a4 100644 --- a/sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/should_update_template_rule_language-result.xml +++ b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_update_template_rule_language-result.xml @@ -7,11 +7,11 @@ - + status="DEPRECATED" priority="4" cardinality="SINGLE" parent_id="3" language="java"/> \ No newline at end of file diff --git a/sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/should_update_template_rule_language.xml b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_update_template_rule_language.xml similarity index 96% rename from sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/should_update_template_rule_language.xml rename to sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_update_template_rule_language.xml index 68bf24c1936..c8e9ce4db16 100644 --- a/sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/should_update_template_rule_language.xml +++ b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/should_update_template_rule_language.xml @@ -5,7 +5,7 @@ + status="READY" priority="4" cardinality="SINGLE" parent_id="1" language="[null]"/> diff --git a/sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/updadeRuleFields-result.xml b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/updadeRuleFields-result.xml similarity index 93% rename from sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/updadeRuleFields-result.xml rename to sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/updadeRuleFields-result.xml index a4b0f4cc8df..59e8c926973 100644 --- a/sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/updadeRuleFields-result.xml +++ b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/updadeRuleFields-result.xml @@ -11,7 +11,7 @@ - diff --git a/sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/updadeRuleFields.xml b/sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/updadeRuleFields.xml similarity index 100% rename from sonar-server/src/test/resources/org/sonar/server/startup/RegisterRulesTest/updadeRuleFields.xml rename to sonar-server/src/test/resources/org/sonar/server/rule/RuleRegistrationTest/updadeRuleFields.xml -- 2.39.5