]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6547 Clear rules overloaded debt 536/head
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Fri, 25 Sep 2015 09:36:24 +0000 (11:36 +0200)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Mon, 28 Sep 2015 09:28:05 +0000 (11:28 +0200)
server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java
server/sonar-server/src/main/java/org/sonar/server/startup/ClearRulesOverloadedDebt.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/startup/ClearRulesOverloadedDebtTest.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/properties/PropertiesDao.java

index 8ed0d7b5abc9865d509a639fa3a996bde51690ac..028381c3c387aa0d9c90044f496b82f181e4187e 100644 (file)
@@ -20,6 +20,9 @@
 package org.sonar.server.platform;
 
 import com.google.common.collect.Lists;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
 import org.apache.commons.configuration.BaseConfiguration;
 import org.sonar.api.config.EmailSettings;
 import org.sonar.api.issue.action.Actions;
@@ -52,7 +55,13 @@ import org.sonar.core.measure.db.MeasureFilterDao;
 import org.sonar.core.metric.DefaultMetricFinder;
 import org.sonar.core.notification.DefaultNotificationManager;
 import org.sonar.core.permission.PermissionFacade;
-import org.sonar.core.persistence.*;
+import org.sonar.core.persistence.DaoUtils;
+import org.sonar.core.persistence.DatabaseVersion;
+import org.sonar.core.persistence.DefaultDatabase;
+import org.sonar.core.persistence.MyBatis;
+import org.sonar.core.persistence.PreviewDatabaseFactory;
+import org.sonar.core.persistence.SemaphoreUpdater;
+import org.sonar.core.persistence.SemaphoresImpl;
 import org.sonar.core.preview.PreviewCache;
 import org.sonar.core.profiling.Profiling;
 import org.sonar.core.purge.PurgeProfiler;
@@ -78,24 +87,54 @@ import org.sonar.server.activity.index.ActivityNormalizer;
 import org.sonar.server.activity.ws.ActivitiesWebService;
 import org.sonar.server.activity.ws.ActivityMapping;
 import org.sonar.server.authentication.ws.AuthenticationWs;
-import org.sonar.server.batch.*;
+import org.sonar.server.batch.BatchIndex;
+import org.sonar.server.batch.BatchWs;
+import org.sonar.server.batch.GlobalReferentialsAction;
+import org.sonar.server.batch.ProjectReferentialsAction;
+import org.sonar.server.batch.ProjectReferentialsLoader;
 import org.sonar.server.charts.ChartFactory;
 import org.sonar.server.component.DefaultComponentFinder;
 import org.sonar.server.component.DefaultRubyComponentService;
 import org.sonar.server.component.persistence.ComponentDao;
 import org.sonar.server.component.persistence.SnapshotDao;
-import org.sonar.server.component.ws.*;
+import org.sonar.server.component.ws.ComponentAppAction;
+import org.sonar.server.component.ws.ComponentsWs;
+import org.sonar.server.component.ws.EventsWs;
+import org.sonar.server.component.ws.ProjectsWs;
+import org.sonar.server.component.ws.ResourcesWs;
 import org.sonar.server.config.ws.PropertiesWs;
 import org.sonar.server.db.DatabaseChecker;
 import org.sonar.server.db.DbClient;
 import org.sonar.server.db.EmbeddedDatabaseFactory;
 import org.sonar.server.db.migrations.DatabaseMigrations;
 import org.sonar.server.db.migrations.DatabaseMigrator;
-import org.sonar.server.debt.*;
+import org.sonar.server.debt.DebtCharacteristicsXMLImporter;
+import org.sonar.server.debt.DebtModelBackup;
+import org.sonar.server.debt.DebtModelLookup;
+import org.sonar.server.debt.DebtModelOperations;
+import org.sonar.server.debt.DebtModelPluginRepository;
+import org.sonar.server.debt.DebtModelService;
+import org.sonar.server.debt.DebtModelXMLExporter;
+import org.sonar.server.debt.DebtRulesXMLImporter;
 import org.sonar.server.duplication.ws.DuplicationsJsonWriter;
 import org.sonar.server.duplication.ws.DuplicationsParser;
 import org.sonar.server.duplication.ws.DuplicationsWs;
-import org.sonar.server.issue.*;
+import org.sonar.server.issue.ActionService;
+import org.sonar.server.issue.AssignAction;
+import org.sonar.server.issue.CommentAction;
+import org.sonar.server.issue.DefaultIssueFinder;
+import org.sonar.server.issue.InternalRubyIssueService;
+import org.sonar.server.issue.IssueBulkChangeService;
+import org.sonar.server.issue.IssueChangelogFormatter;
+import org.sonar.server.issue.IssueChangelogService;
+import org.sonar.server.issue.IssueCommentService;
+import org.sonar.server.issue.IssueService;
+import org.sonar.server.issue.IssueStatsFinder;
+import org.sonar.server.issue.PlanAction;
+import org.sonar.server.issue.PublicRubyIssueService;
+import org.sonar.server.issue.ServerIssueStorage;
+import org.sonar.server.issue.SetSeverityAction;
+import org.sonar.server.issue.TransitionAction;
 import org.sonar.server.issue.actionplan.ActionPlanService;
 import org.sonar.server.issue.actionplan.ActionPlanWs;
 import org.sonar.server.issue.db.IssueDao;
@@ -124,22 +163,83 @@ import org.sonar.server.platform.ws.L10nWs;
 import org.sonar.server.platform.ws.RestartHandler;
 import org.sonar.server.platform.ws.ServerWs;
 import org.sonar.server.platform.ws.SystemWs;
-import org.sonar.server.plugins.*;
+import org.sonar.server.plugins.InstalledPluginReferentialFactory;
+import org.sonar.server.plugins.PluginDownloader;
+import org.sonar.server.plugins.ServerExtensionInstaller;
+import org.sonar.server.plugins.ServerPluginJarInstaller;
+import org.sonar.server.plugins.ServerPluginJarsInstaller;
+import org.sonar.server.plugins.ServerPluginRepository;
+import org.sonar.server.plugins.UpdateCenterClient;
+import org.sonar.server.plugins.UpdateCenterMatrixFactory;
 import org.sonar.server.qualitygate.QgateProjectFinder;
 import org.sonar.server.qualitygate.QualityGates;
 import org.sonar.server.qualitygate.RegisterQualityGates;
-import org.sonar.server.qualitygate.ws.*;
-import org.sonar.server.qualityprofile.*;
+import org.sonar.server.qualitygate.ws.QGatesAppAction;
+import org.sonar.server.qualitygate.ws.QGatesCopyAction;
+import org.sonar.server.qualitygate.ws.QGatesCreateAction;
+import org.sonar.server.qualitygate.ws.QGatesCreateConditionAction;
+import org.sonar.server.qualitygate.ws.QGatesDeleteConditionAction;
+import org.sonar.server.qualitygate.ws.QGatesDeselectAction;
+import org.sonar.server.qualitygate.ws.QGatesDestroyAction;
+import org.sonar.server.qualitygate.ws.QGatesListAction;
+import org.sonar.server.qualitygate.ws.QGatesRenameAction;
+import org.sonar.server.qualitygate.ws.QGatesSearchAction;
+import org.sonar.server.qualitygate.ws.QGatesSelectAction;
+import org.sonar.server.qualitygate.ws.QGatesSetAsDefaultAction;
+import org.sonar.server.qualitygate.ws.QGatesShowAction;
+import org.sonar.server.qualitygate.ws.QGatesUnsetDefaultAction;
+import org.sonar.server.qualitygate.ws.QGatesUpdateConditionAction;
+import org.sonar.server.qualitygate.ws.QGatesWs;
+import org.sonar.server.qualityprofile.BuiltInProfiles;
+import org.sonar.server.qualityprofile.QProfileBackuper;
+import org.sonar.server.qualityprofile.QProfileCopier;
+import org.sonar.server.qualityprofile.QProfileExporters;
+import org.sonar.server.qualityprofile.QProfileFactory;
+import org.sonar.server.qualityprofile.QProfileLoader;
+import org.sonar.server.qualityprofile.QProfileLookup;
+import org.sonar.server.qualityprofile.QProfileProjectLookup;
+import org.sonar.server.qualityprofile.QProfileProjectOperations;
+import org.sonar.server.qualityprofile.QProfileReset;
+import org.sonar.server.qualityprofile.QProfileService;
+import org.sonar.server.qualityprofile.QProfiles;
+import org.sonar.server.qualityprofile.RegisterQualityProfiles;
+import org.sonar.server.qualityprofile.RuleActivator;
+import org.sonar.server.qualityprofile.RuleActivatorContextFactory;
 import org.sonar.server.qualityprofile.db.ActiveRuleDao;
 import org.sonar.server.qualityprofile.index.ActiveRuleIndex;
 import org.sonar.server.qualityprofile.index.ActiveRuleNormalizer;
-import org.sonar.server.qualityprofile.ws.*;
-import org.sonar.server.rule.*;
+import org.sonar.server.qualityprofile.ws.BulkRuleActivationActions;
+import org.sonar.server.qualityprofile.ws.ProfilesWs;
+import org.sonar.server.qualityprofile.ws.QProfileRestoreBuiltInAction;
+import org.sonar.server.qualityprofile.ws.QProfilesWs;
+import org.sonar.server.qualityprofile.ws.RuleActivationActions;
+import org.sonar.server.rule.DefaultRuleFinder;
+import org.sonar.server.rule.DeprecatedRulesDefinitionLoader;
+import org.sonar.server.rule.RegisterRules;
+import org.sonar.server.rule.RubyRuleService;
+import org.sonar.server.rule.RuleCreator;
+import org.sonar.server.rule.RuleDefinitionsLoader;
+import org.sonar.server.rule.RuleDeleter;
+import org.sonar.server.rule.RuleOperations;
+import org.sonar.server.rule.RuleRepositories;
+import org.sonar.server.rule.RuleService;
+import org.sonar.server.rule.RuleUpdater;
 import org.sonar.server.rule.db.RuleDao;
 import org.sonar.server.rule.index.RuleIndex;
 import org.sonar.server.rule.index.RuleNormalizer;
-import org.sonar.server.rule.ws.*;
-import org.sonar.server.search.*;
+import org.sonar.server.rule.ws.ActiveRuleCompleter;
+import org.sonar.server.rule.ws.AppAction;
+import org.sonar.server.rule.ws.DeleteAction;
+import org.sonar.server.rule.ws.RuleMapping;
+import org.sonar.server.rule.ws.RulesWebService;
+import org.sonar.server.rule.ws.SearchAction;
+import org.sonar.server.rule.ws.TagsAction;
+import org.sonar.server.rule.ws.UpdateAction;
+import org.sonar.server.search.IndexClient;
+import org.sonar.server.search.IndexQueue;
+import org.sonar.server.search.IndexSynchronizer;
+import org.sonar.server.search.SearchClient;
+import org.sonar.server.search.SearchHealth;
 import org.sonar.server.source.CodeColorizers;
 import org.sonar.server.source.DeprecatedSourceDecorator;
 import org.sonar.server.source.HtmlSourceDecorator;
@@ -148,9 +248,28 @@ import org.sonar.server.source.ws.ScmAction;
 import org.sonar.server.source.ws.ScmWriter;
 import org.sonar.server.source.ws.ShowAction;
 import org.sonar.server.source.ws.SourcesWs;
-import org.sonar.server.startup.*;
+import org.sonar.server.startup.CleanPreviewAnalysisCache;
+import org.sonar.server.startup.ClearRulesOverloadedDebt;
+import org.sonar.server.startup.CopyRequirementsFromCharacteristicsToRules;
+import org.sonar.server.startup.GeneratePluginIndex;
+import org.sonar.server.startup.GwtPublisher;
+import org.sonar.server.startup.JdbcDriverDeployer;
+import org.sonar.server.startup.LogServerId;
+import org.sonar.server.startup.RegisterDashboards;
+import org.sonar.server.startup.RegisterDebtModel;
+import org.sonar.server.startup.RegisterMetrics;
+import org.sonar.server.startup.RegisterNewMeasureFilters;
+import org.sonar.server.startup.RegisterPermissionTemplates;
+import org.sonar.server.startup.RegisterServletFilters;
+import org.sonar.server.startup.RenameDeprecatedPropertyKeys;
+import org.sonar.server.startup.ServerMetadataPersister;
 import org.sonar.server.test.CoverageService;
-import org.sonar.server.test.ws.*;
+import org.sonar.server.test.ws.CoverageShowAction;
+import org.sonar.server.test.ws.CoverageWs;
+import org.sonar.server.test.ws.TestsCoveredFilesAction;
+import org.sonar.server.test.ws.TestsShowAction;
+import org.sonar.server.test.ws.TestsTestCasesAction;
+import org.sonar.server.test.ws.TestsWs;
 import org.sonar.server.text.MacroInterpreter;
 import org.sonar.server.text.RubyTextService;
 import org.sonar.server.ui.JRubyI18n;
@@ -158,18 +277,25 @@ import org.sonar.server.ui.JRubyProfiling;
 import org.sonar.server.ui.PageDecorations;
 import org.sonar.server.ui.Views;
 import org.sonar.server.updatecenter.ws.UpdateCenterWs;
-import org.sonar.server.user.*;
+import org.sonar.server.user.DefaultUserService;
+import org.sonar.server.user.DoPrivileged;
+import org.sonar.server.user.GroupMembershipFinder;
+import org.sonar.server.user.GroupMembershipService;
+import org.sonar.server.user.NewUserNotifier;
+import org.sonar.server.user.SecurityRealmFactory;
 import org.sonar.server.user.ws.FavoritesWs;
 import org.sonar.server.user.ws.UserPropertiesWs;
 import org.sonar.server.user.ws.UsersWs;
-import org.sonar.server.util.*;
+import org.sonar.server.util.BooleanTypeValidation;
+import org.sonar.server.util.FloatTypeValidation;
+import org.sonar.server.util.IntegerTypeValidation;
+import org.sonar.server.util.StringListTypeValidation;
+import org.sonar.server.util.StringTypeValidation;
+import org.sonar.server.util.TextTypeValidation;
+import org.sonar.server.util.TypeValidations;
 import org.sonar.server.ws.ListingWs;
 import org.sonar.server.ws.WebServiceEngine;
 
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-
 class ServerComponents {
 
   private final Object[] rootComponents;
@@ -582,6 +708,7 @@ class ServerComponents {
     startupContainer.addSingleton(RegisterServletFilters.class);
     startupContainer.addSingleton(CleanPreviewAnalysisCache.class);
     startupContainer.addSingleton(CopyRequirementsFromCharacteristicsToRules.class);
+    startupContainer.addSingleton(ClearRulesOverloadedDebt.class);
 
     DoPrivileged.execute(new DoPrivileged.Task() {
       @Override
diff --git a/server/sonar-server/src/main/java/org/sonar/server/startup/ClearRulesOverloadedDebt.java b/server/sonar-server/src/main/java/org/sonar/server/startup/ClearRulesOverloadedDebt.java
new file mode 100644 (file)
index 0000000..91e1538
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 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.picocontainer.Startable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.rule.RuleDto;
+import org.sonar.core.template.LoadedTemplateDto;
+import org.sonar.server.db.DbClient;
+
+import static org.sonar.core.template.LoadedTemplateDto.ONE_SHOT_TASK_TYPE;
+
+/**
+ * Clear the overloaded technical debt of rules when SQALE plugin is not installed.
+ * See <a href="https://jira.sonarsource.com/browse/SONAR-6547">SONAR-6547</a>.
+ *
+ * Should be removed after LTS 5.X
+ *
+ * @since 5.2
+ */
+public class ClearRulesOverloadedDebt implements Startable {
+
+  private static final Logger LOG = LoggerFactory.getLogger(ClearRulesOverloadedDebt.class);
+
+  private static final String TEMPLATE_KEY = "ClearRulesOverloadedDebt";
+
+  private static final String SQALE_LICENSE_PROPERTY = "sonar.sqale.licenseHash.secured";
+
+  private final DbClient dbClient;
+
+  public ClearRulesOverloadedDebt(DbClient dbClient) {
+    this.dbClient = dbClient;
+  }
+
+  @Override
+  public void start() {
+    DbSession session = dbClient.openSession(false);
+    try {
+      if (hasAlreadyBeenExecuted(session)) {
+        return;
+      }
+      if (!isSqalePluginInstalled(session)) {
+        clearDebt(session);
+      }
+      markAsExecuted(session);
+      session.commit();
+    } finally {
+      session.close();
+    }
+  }
+
+  private void clearDebt(DbSession session) {
+    int countClearedRules = 0;
+    for (RuleDto rule : dbClient.ruleDao().findAll(session)) {
+      if (isDebtOverridden(rule)) {
+        rule.setSubCharacteristicId(null);
+        rule.setRemediationFunction(null);
+        rule.setRemediationCoefficient(null);
+        rule.setRemediationOffset(null);
+        dbClient.ruleDao().update(session, rule);
+        countClearedRules++;
+      }
+    }
+    if (countClearedRules > 0) {
+      LOG.warn("The SQALE model has been cleaned to remove useless data left over by previous migrations. The technical debt of {} rules was reset to their default values.",
+        countClearedRules);
+      LOG.warn("=> As a consequence, the overall technical debt of your projects might slightly evolve during the next analysis.");
+    }
+  }
+
+  private static boolean isDebtOverridden(RuleDto ruleDto) {
+    return ruleDto.getSubCharacteristicId() != null || ruleDto.getRemediationFunction() != null || ruleDto.getRemediationCoefficient() != null
+      || ruleDto.getRemediationOffset() != null;
+  }
+
+  private boolean isSqalePluginInstalled(DbSession session) {
+    return dbClient.propertiesDao().selectGlobalProperty(session, SQALE_LICENSE_PROPERTY) != null;
+  }
+
+  private boolean hasAlreadyBeenExecuted(DbSession session) {
+    return dbClient.loadedTemplateDao().countByTypeAndKey(ONE_SHOT_TASK_TYPE, TEMPLATE_KEY, session) > 0;
+  }
+
+  private void markAsExecuted(DbSession session) {
+    dbClient.loadedTemplateDao().insert(new LoadedTemplateDto(TEMPLATE_KEY, ONE_SHOT_TASK_TYPE), session);
+  }
+
+  @Override
+  public void stop() {
+    // Nothing to do
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/startup/ClearRulesOverloadedDebtTest.java b/server/sonar-server/src/test/java/org/sonar/server/startup/ClearRulesOverloadedDebtTest.java
new file mode 100644 (file)
index 0000000..99b6a29
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 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 java.util.Date;
+import javax.annotation.Nullable;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.properties.PropertyDto;
+import org.sonar.core.rule.RuleDto;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.rule.Rule;
+import org.sonar.server.rule.RuleTesting;
+import org.sonar.server.rule.db.RuleDao;
+import org.sonar.server.rule.index.RuleIndex;
+import org.sonar.server.tester.ServerTester;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.sonar.core.template.LoadedTemplateDto.ONE_SHOT_TASK_TYPE;
+import static org.sonar.server.rule.RuleTesting.XOO_X1;
+import static org.sonar.server.rule.RuleTesting.XOO_X2;
+import static org.sonar.server.rule.RuleTesting.XOO_X3;
+
+public class ClearRulesOverloadedDebtTest {
+
+  static final int SUB_CHARACTERISTIC_ID = 1;
+
+  private static final RuleKey RULE_KEY_1 = XOO_X1;
+  private static final RuleKey RULE_KEY_2 = XOO_X2;
+  private static final RuleKey RULE_KEY_3 = XOO_X3;
+
+  @ClassRule
+  public static ServerTester tester = new ServerTester();
+
+  RuleDao ruleDao = tester.get(RuleDao.class);
+  RuleIndex ruleIndex = tester.get(RuleIndex.class);
+  DbClient dbClient = tester.get(DbClient.class);
+  DbSession dbSession = tester.get(DbClient.class).openSession(false);
+
+  ClearRulesOverloadedDebt underTest = new ClearRulesOverloadedDebt(dbClient);
+
+  @Before
+  public void before() {
+    tester.clearDbAndIndexes();
+  }
+
+  @After
+  public void after() {
+    dbSession.close();
+  }
+
+  @Test
+  public void remove_overridden_debt() throws Exception {
+    // Characteristic and remediation function is overridden
+    insertRuleDto(RULE_KEY_1, SUB_CHARACTERISTIC_ID, "LINEAR", null, "1d");
+    // Only characteristic is overridden
+    insertRuleDto(RULE_KEY_2, SUB_CHARACTERISTIC_ID, null, null, null);
+    // Only remediation function is overridden
+    insertRuleDto(RULE_KEY_3, null, "CONSTANT_ISSUE", "5min", null);
+
+    underTest.start();
+
+    verifyRuleHasNotOverriddenDebt(RULE_KEY_1);
+    verifyRuleHasNotOverriddenDebt(RULE_KEY_2);
+    verifyRuleHasNotOverriddenDebt(RULE_KEY_3);
+    verifyTaskRegistered();
+  }
+
+  @Test
+  public void not_update_rule_debt_not_overridden() throws Exception {
+    RuleDto rule = insertRuleDto(RULE_KEY_1, null, null, null, null);
+    Date updateAt = rule.getUpdatedAt();
+
+    underTest.start();
+
+    RuleDto reloaded = ruleDao.getByKey(dbSession, RULE_KEY_1);
+    assertThat(reloaded.getUpdatedAt()).isEqualTo(updateAt);
+    verifyRuleHasNotOverriddenDebt(RULE_KEY_1);
+
+    verifyTaskRegistered();
+  }
+
+  @Test
+  public void not_update_rule_debt_when_sqale_is_installed() throws Exception {
+    insertSqaleProperty();
+    RuleDto rule = insertRuleDto(RULE_KEY_1, SUB_CHARACTERISTIC_ID, "LINEAR", null, "1d");
+    Date updateAt = rule.getUpdatedAt();
+
+    underTest.start();
+
+    RuleDto reloaded = ruleDao.getByKey(dbSession, RULE_KEY_1);
+    assertThat(reloaded.getUpdatedAt()).isEqualTo(updateAt);
+
+    Rule ruleEs = ruleIndex.getByKey(RULE_KEY_1);
+    assertThat(ruleEs.debtOverloaded()).isTrue();
+
+    verifyTaskRegistered();
+  }
+
+  private void verifyRuleHasNotOverriddenDebt(RuleKey ruleKey) {
+    // Refresh session
+    dbSession.commit(true);
+
+    RuleDto ruleDto = ruleDao.getByKey(dbSession, ruleKey);
+    assertThat(ruleDto.getSubCharacteristicId()).isNull();
+    assertThat(ruleDto.getRemediationFunction()).isNull();
+    assertThat(ruleDto.getRemediationCoefficient()).isNull();
+    assertThat(ruleDto.getRemediationOffset()).isNull();
+
+    Rule rule = ruleIndex.getByKey(ruleKey);
+    assertThat(rule.debtOverloaded()).isFalse();
+  }
+
+  private RuleDto insertRuleDto(RuleKey ruleKey, @Nullable Integer subCharId, @Nullable String function, @Nullable String coeff, @Nullable String offset) {
+    RuleDto ruleDto = RuleTesting.newDto(ruleKey)
+      .setSubCharacteristicId(subCharId)
+      .setRemediationFunction(function)
+      .setRemediationOffset(offset)
+      .setRemediationCoefficient(coeff);
+    ruleDao.insert(dbSession,
+      ruleDto
+    );
+    dbSession.commit();
+    return ruleDto;
+  }
+
+  private void insertSqaleProperty() {
+    dbClient.propertiesDao().setProperty(new PropertyDto().setKey("sonar.sqale.licenseHash.secured").setValue("ABCD"), dbSession);
+    dbSession.commit();
+  }
+
+  private void verifyTaskRegistered() {
+    assertThat(dbClient.loadedTemplateDao().countByTypeAndKey(ONE_SHOT_TASK_TYPE, "ClearRulesOverloadedDebt")).isEqualTo(1);
+  }
+
+}
index 11c4a80dd0f6a9dfea8ce12cef695145097a51b5..8b592ef897b4a3a09b38cd7eedeb7ca55c17f5c4 100644 (file)
@@ -21,6 +21,9 @@ package org.sonar.core.properties;
 
 import com.google.common.base.Preconditions;
 import com.google.common.base.Strings;
+import java.util.List;
+import java.util.Map;
+import javax.annotation.Nullable;
 import org.apache.commons.lang.StringUtils;
 import org.apache.ibatis.session.SqlSession;
 import org.sonar.api.BatchComponent;
@@ -29,11 +32,6 @@ import org.sonar.core.persistence.DaoComponent;
 import org.sonar.core.persistence.DbSession;
 import org.sonar.core.persistence.MyBatis;
 
-import javax.annotation.Nullable;
-
-import java.util.List;
-import java.util.Map;
-
 public class PropertiesDao implements BatchComponent, ServerComponent, DaoComponent {
 
   private static final String NOTIFICATION_PREFIX = "notification.";
@@ -85,11 +83,14 @@ public class PropertiesDao implements BatchComponent, ServerComponent, DaoCompon
     return session.getMapper(PropertiesMapper.class).selectGlobalProperties();
   }
 
+  public PropertyDto selectGlobalProperty(DbSession session, String propertyKey) {
+    return session.getMapper(PropertiesMapper.class).selectByKey(new PropertyDto().setKey(propertyKey));
+  }
+
   public PropertyDto selectGlobalProperty(String propertyKey) {
-    SqlSession session = mybatis.openSession(false);
-    PropertiesMapper mapper = session.getMapper(PropertiesMapper.class);
+    DbSession session = mybatis.openSession(false);
     try {
-      return mapper.selectByKey(new PropertyDto().setKey(propertyKey));
+      return selectGlobalProperty(session, propertyKey);
     } finally {
       MyBatis.closeQuietly(session);
     }