diff options
author | Simon Brandhof <simon.brandhof@gmail.com> | 2014-04-17 23:33:27 +0200 |
---|---|---|
committer | Simon Brandhof <simon.brandhof@gmail.com> | 2014-04-17 23:33:49 +0200 |
commit | f2dd46cf5745f7c14f2bce20f5131e4e242f8c7c (patch) | |
tree | 11ea192820faf6916a522d59886f923ac5bd6c1f /plugins/sonar-core-plugin | |
parent | fa306cf2509a427937642db79e391e48ce85221e (diff) | |
download | sonarqube-f2dd46cf5745f7c14f2bce20f5131e4e242f8c7c.tar.gz sonarqube-f2dd46cf5745f7c14f2bce20f5131e4e242f8c7c.zip |
SONAR-4969 Do not mix batch and server classpaths
Diffstat (limited to 'plugins/sonar-core-plugin')
10 files changed, 73 insertions, 1324 deletions
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java index a87d01690a6..b8770197f47 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java @@ -20,36 +20,84 @@ package org.sonar.plugins.core; import com.google.common.collect.ImmutableList; -import org.sonar.api.*; +import org.sonar.api.CoreProperties; +import org.sonar.api.Properties; +import org.sonar.api.Property; +import org.sonar.api.PropertyType; +import org.sonar.api.SonarPlugin; import org.sonar.api.checks.NoSonarFilter; -import org.sonar.api.config.PropertyDefinition; -import org.sonar.api.resources.Qualifiers; -import org.sonar.batch.components.PastSnapshotFinder; -import org.sonar.batch.debt.IssueChangelogDebtCalculator; -import org.sonar.batch.issue.ignore.IssueExclusionsConfiguration; import org.sonar.core.timemachine.Periods; import org.sonar.plugins.core.batch.IndexProjectPostJob; import org.sonar.plugins.core.charts.DistributionAreaChart; import org.sonar.plugins.core.charts.DistributionBarChart; import org.sonar.plugins.core.charts.XradarChart; import org.sonar.plugins.core.colorizers.JavaColorizerFormat; -import org.sonar.plugins.core.dashboards.*; -import org.sonar.plugins.core.issue.*; -import org.sonar.plugins.core.issue.notification.*; +import org.sonar.plugins.core.dashboards.GlobalDefaultDashboard; +import org.sonar.plugins.core.dashboards.ProjectDefaultDashboard; +import org.sonar.plugins.core.dashboards.ProjectHotspotDashboard; +import org.sonar.plugins.core.dashboards.ProjectIssuesDashboard; +import org.sonar.plugins.core.dashboards.ProjectTimeMachineDashboard; +import org.sonar.plugins.core.issue.CountFalsePositivesDecorator; +import org.sonar.plugins.core.issue.CountUnresolvedIssuesDecorator; +import org.sonar.plugins.core.issue.InitialOpenIssuesSensor; +import org.sonar.plugins.core.issue.InitialOpenIssuesStack; +import org.sonar.plugins.core.issue.IssueHandlers; +import org.sonar.plugins.core.issue.IssueTracking; +import org.sonar.plugins.core.issue.IssueTrackingDecorator; +import org.sonar.plugins.core.issue.IssuesDensityDecorator; +import org.sonar.plugins.core.issue.WeightedIssuesDecorator; +import org.sonar.plugins.core.issue.notification.ChangesOnMyIssueNotificationDispatcher; +import org.sonar.plugins.core.issue.notification.IssueChangesEmailTemplate; +import org.sonar.plugins.core.issue.notification.NewFalsePositiveNotificationDispatcher; +import org.sonar.plugins.core.issue.notification.NewIssuesEmailTemplate; +import org.sonar.plugins.core.issue.notification.NewIssuesNotificationDispatcher; +import org.sonar.plugins.core.issue.notification.SendIssueNotificationsPostJob; import org.sonar.plugins.core.measurefilters.MyFavouritesFilter; import org.sonar.plugins.core.measurefilters.ProjectFilter; import org.sonar.plugins.core.notifications.alerts.NewAlerts; import org.sonar.plugins.core.security.ApplyProjectRolesDecorator; -import org.sonar.plugins.core.sensors.*; -import org.sonar.plugins.core.technicaldebt.DebtDecorator; -import org.sonar.plugins.core.technicaldebt.NewDebtDecorator; -import org.sonar.plugins.core.timemachine.*; +import org.sonar.plugins.core.sensors.BranchCoverageDecorator; +import org.sonar.plugins.core.sensors.CommentDensityDecorator; +import org.sonar.plugins.core.sensors.CoverageDecorator; +import org.sonar.plugins.core.sensors.CoverageMeasurementFilter; +import org.sonar.plugins.core.sensors.DirectoriesDecorator; +import org.sonar.plugins.core.sensors.FileHashSensor; +import org.sonar.plugins.core.sensors.FilesDecorator; +import org.sonar.plugins.core.sensors.ItBranchCoverageDecorator; +import org.sonar.plugins.core.sensors.ItCoverageDecorator; +import org.sonar.plugins.core.sensors.ItLineCoverageDecorator; +import org.sonar.plugins.core.sensors.LineCoverageDecorator; +import org.sonar.plugins.core.sensors.ManualMeasureDecorator; +import org.sonar.plugins.core.sensors.OverallBranchCoverageDecorator; +import org.sonar.plugins.core.sensors.OverallCoverageDecorator; +import org.sonar.plugins.core.sensors.OverallLineCoverageDecorator; +import org.sonar.plugins.core.sensors.ProfileEventsSensor; +import org.sonar.plugins.core.sensors.ProjectLinksSensor; +import org.sonar.plugins.core.sensors.UnitTestDecorator; +import org.sonar.plugins.core.sensors.VersionEventsSensor; +import org.sonar.plugins.core.timemachine.NewCoverageAggregator; +import org.sonar.plugins.core.timemachine.NewCoverageFileAnalyzer; +import org.sonar.plugins.core.timemachine.NewItCoverageFileAnalyzer; +import org.sonar.plugins.core.timemachine.NewOverallCoverageFileAnalyzer; +import org.sonar.plugins.core.timemachine.TendencyDecorator; +import org.sonar.plugins.core.timemachine.TimeMachineConfigurationPersister; +import org.sonar.plugins.core.timemachine.VariationDecorator; import org.sonar.plugins.core.web.TestsViewer; import org.sonar.plugins.core.widgets.*; -import org.sonar.plugins.core.widgets.issues.*; -import org.sonar.plugins.core.widgets.measures.*; +import org.sonar.plugins.core.widgets.issues.ActionPlansWidget; +import org.sonar.plugins.core.widgets.issues.FalsePositiveIssuesWidget; +import org.sonar.plugins.core.widgets.issues.IssueFilterWidget; +import org.sonar.plugins.core.widgets.issues.IssuesWidget; +import org.sonar.plugins.core.widgets.issues.MyUnresolvedIssuesWidget; +import org.sonar.plugins.core.widgets.issues.UnresolvedIssuesPerAssigneeWidget; +import org.sonar.plugins.core.widgets.issues.UnresolvedIssuesStatusesWidget; +import org.sonar.plugins.core.widgets.measures.MeasureFilterAsBubbleChartWidget; +import org.sonar.plugins.core.widgets.measures.MeasureFilterAsCloudWidget; +import org.sonar.plugins.core.widgets.measures.MeasureFilterAsHistogramWidget; +import org.sonar.plugins.core.widgets.measures.MeasureFilterAsPieChartWidget; +import org.sonar.plugins.core.widgets.measures.MeasureFilterListWidget; +import org.sonar.plugins.core.widgets.measures.MeasureFilterTreemapWidget; -import java.util.Arrays; import java.util.List; @Properties({ @@ -292,11 +340,6 @@ public final class CorePlugin extends SonarPlugin { NewFalsePositiveNotificationDispatcher.class, NewFalsePositiveNotificationDispatcher.newMetadata(), - // technical debt - DebtDecorator.class, - NewDebtDecorator.class, - IssueChangelogDebtCalculator.class, - // batch ProfileEventsSensor.class, ProjectLinksSensor.class, @@ -334,64 +377,7 @@ public final class CorePlugin extends SonarPlugin { NewAlerts.class, NewAlerts.newMetadata()); - extensions.addAll(ExclusionProperties.definitions()); - extensions.addAll(IssueExclusionsConfiguration.getPropertyDefinitions()); - extensions.addAll(CoverageMeasurementFilter.getPropertyDefinitions()); - extensions.addAll(PastSnapshotFinder.getPropertyDefinitions()); - extensions.addAll(DebtDecorator.definitions()); - extensions.addAll(propertyDefinitions()); - return extensions.build(); } - static List<PropertyDefinition> propertyDefinitions() { - return Arrays.asList( - PropertyDefinition.builder(CoreProperties.CORE_VIOLATION_LOCALE_PROPERTY) - .defaultValue("en") - .name("Locale used for issue messages") - .description("Deprecated property. Keep default value for backward compatibility.") - .hidden() - .build(), - PropertyDefinition.builder(CoreProperties.CORE_ALLOW_USERS_TO_SIGNUP_PROPERTY) - .defaultValue("" + CoreProperties.CORE_ALLOW_USERS_TO_SIGNUP_DEAULT_VALUE) - .name("Allow users to sign up online") - .description("Users can sign up online.") - .type(PropertyType.BOOLEAN) - .category(CoreProperties.CATEGORY_SECURITY) - .build(), - - PropertyDefinition.builder(CoreProperties.CORE_DEFAULT_GROUP) - .defaultValue(CoreProperties.CORE_DEFAULT_GROUP_DEFAULT_VALUE) - .name("Default user group") - .description("Any new users will automatically join this group.") - .category(CoreProperties.CATEGORY_SECURITY) - .build(), - - PropertyDefinition.builder(CoreProperties.CORE_IMPORT_SOURCES_PROPERTY) - .defaultValue("" + CoreProperties.CORE_IMPORT_SOURCES_DEFAULT_VALUE) - .name("Import sources") - .description("Set to false if sources should not be imported and therefore not available in the Web UI (e.g. for security reasons).") - .type(PropertyType.BOOLEAN) - .onQualifiers(Qualifiers.PROJECT, Qualifiers.MODULE) - .category(CoreProperties.CATEGORY_SECURITY) - .build(), - - PropertyDefinition.builder(CoreProperties.CORE_FORCE_AUTHENTICATION_PROPERTY) - .defaultValue("" + CoreProperties.CORE_FORCE_AUTHENTICATION_DEFAULT_VALUE) - .name("Force user authentication") - .description("Forcing user authentication stops un-logged users to access SonarQube.") - .type(PropertyType.BOOLEAN) - .category(CoreProperties.CATEGORY_SECURITY) - .build(), - - PropertyDefinition.builder(CoreProperties.CORE_PREVENT_AUTOMATIC_PROJECT_CREATION) - .defaultValue(Boolean.toString(false)) - .name("Prevent automatic project creation") - .description("Set to true to prevent automatic project creation at first analysis and force project provisioning.") - .type(PropertyType.BOOLEAN) - .category(CoreProperties.CATEGORY_SECURITY) - .build() - ); - } - } diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/ExclusionProperties.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/ExclusionProperties.java deleted file mode 100644 index b169a572965..00000000000 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/ExclusionProperties.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * 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.plugins.core; - -import com.google.common.collect.ImmutableList; -import org.sonar.api.CoreProperties; -import org.sonar.api.config.PropertyDefinition; -import org.sonar.api.resources.Qualifiers; - -import java.util.List; - -class ExclusionProperties { - - private ExclusionProperties() { - // only static stuff - } - - static List<PropertyDefinition> definitions() { - return ImmutableList.of( - PropertyDefinition.builder(CoreProperties.PROJECT_INCLUSIONS_PROPERTY) - .name("Source File Inclusions") - .multiValues(true) - .category(CoreProperties.CATEGORY_EXCLUSIONS) - .subCategory(CoreProperties.SUBCATEGORY_FILES_EXCLUSIONS) - .onQualifiers(Qualifiers.PROJECT) - .index(3) - .build(), - PropertyDefinition.builder(CoreProperties.PROJECT_TEST_INCLUSIONS_PROPERTY) - .name("Test File Inclusions") - .multiValues(true) - .category(CoreProperties.CATEGORY_EXCLUSIONS) - .subCategory(CoreProperties.SUBCATEGORY_FILES_EXCLUSIONS) - .onQualifiers(Qualifiers.PROJECT) - .index(5) - .build(), - PropertyDefinition.builder(CoreProperties.GLOBAL_EXCLUSIONS_PROPERTY) - .name("Global Source File Exclusions") - .multiValues(true) - .category(CoreProperties.CATEGORY_EXCLUSIONS) - .subCategory(CoreProperties.SUBCATEGORY_FILES_EXCLUSIONS) - .index(0) - .build(), - PropertyDefinition.builder(CoreProperties.GLOBAL_TEST_EXCLUSIONS_PROPERTY) - .name("Global Test File Exclusions") - .multiValues(true) - .category(CoreProperties.CATEGORY_EXCLUSIONS) - .subCategory(CoreProperties.SUBCATEGORY_FILES_EXCLUSIONS) - .index(1) - .build(), - PropertyDefinition.builder(CoreProperties.PROJECT_EXCLUSIONS_PROPERTY) - .name("Source File Exclusions") - .multiValues(true) - .category(CoreProperties.CATEGORY_EXCLUSIONS) - .subCategory(CoreProperties.SUBCATEGORY_FILES_EXCLUSIONS) - .onQualifiers(Qualifiers.PROJECT) - .index(2) - .build(), - PropertyDefinition.builder(CoreProperties.PROJECT_TEST_EXCLUSIONS_PROPERTY) - .name("Test File Exclusions") - .multiValues(true) - .category(CoreProperties.CATEGORY_EXCLUSIONS) - .subCategory(CoreProperties.SUBCATEGORY_FILES_EXCLUSIONS) - .onQualifiers(Qualifiers.PROJECT) - .index(4) - .build(), - PropertyDefinition.builder(CoreProperties.CORE_SKIPPED_MODULES_PROPERTY) - .name("Exclude Modules") - .description("Maven artifact ids of modules to exclude.") - .multiValues(true) - .category(CoreProperties.CATEGORY_EXCLUSIONS) - .subCategory(CoreProperties.SUBCATEGORY_FILES_EXCLUSIONS) - .onlyOnQualifiers(Qualifiers.PROJECT) - .index(0) - .build(), - PropertyDefinition.builder(CoreProperties.CORE_INCLUDED_MODULES_PROPERTY) - .name("Include Modules") - .description("Maven artifact ids of modules to include.") - .multiValues(true) - .category(CoreProperties.CATEGORY_EXCLUSIONS) - .subCategory(CoreProperties.SUBCATEGORY_FILES_EXCLUSIONS) - .onlyOnQualifiers(Qualifiers.PROJECT) - .index(1) - .build()); - } -} diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/CoverageMeasurementFilter.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/CoverageMeasurementFilter.java index e2bcea80dce..eeda60396a9 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/CoverageMeasurementFilter.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/CoverageMeasurementFilter.java @@ -23,34 +23,26 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList.Builder; import com.google.common.collect.ImmutableSet; -import org.sonar.api.CoreProperties; -import org.sonar.api.PropertyType; -import org.sonar.api.config.PropertyDefinition; import org.sonar.api.config.Settings; import org.sonar.api.measures.Measure; import org.sonar.api.measures.Metric; -import org.sonar.api.resources.Qualifiers; import org.sonar.api.resources.Resource; import org.sonar.api.utils.WildcardPattern; import org.sonar.core.measure.MeasurementFilter; import java.util.Collection; import java.util.Iterator; -import java.util.List; public class CoverageMeasurementFilter implements MeasurementFilter { - public static final String PROPERTY_COVERAGE_EXCLUSIONS = "sonar.coverage.exclusions"; - public static final String PROPERTY_COVERAGE_INCLUSIONS = "sonar.coverage.inclusions"; - private final Settings settings; private final ImmutableSet<Metric> coverageMetrics; private Collection<WildcardPattern> resourcePatterns; public CoverageMeasurementFilter(Settings settings, - CoverageDecorator coverageDecorator, - LineCoverageDecorator lineCoverageDecorator, - BranchCoverageDecorator branchCoverageDecorator) { + CoverageDecorator coverageDecorator, + LineCoverageDecorator lineCoverageDecorator, + BranchCoverageDecorator branchCoverageDecorator) { this.settings = settings; this.coverageMetrics = ImmutableSet.<Metric>builder() .addAll(coverageDecorator.generatedMetrics()) @@ -88,22 +80,10 @@ public class CoverageMeasurementFilter implements MeasurementFilter { @VisibleForTesting final void initPatterns() { - Builder<WildcardPattern> builder = ImmutableList.<WildcardPattern>builder(); - for (String pattern : settings.getStringArray(PROPERTY_COVERAGE_EXCLUSIONS)) { + Builder<WildcardPattern> builder = ImmutableList.builder(); + for (String pattern : settings.getStringArray("sonar.coverage.exclusions")) { builder.add(WildcardPattern.create(pattern)); } resourcePatterns = builder.build(); } - - public static List<PropertyDefinition> getPropertyDefinitions() { - return ImmutableList.of( - PropertyDefinition.builder(PROPERTY_COVERAGE_EXCLUSIONS) - .category(CoreProperties.CATEGORY_EXCLUSIONS) - .subCategory(CoreProperties.SUBCATEGORY_COVERAGE_EXCLUSIONS) - .type(PropertyType.STRING) - .multiValues(true) - .onQualifiers(Qualifiers.PROJECT, Qualifiers.MODULE) - .build() - ); - } } diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/technicaldebt/DebtDecorator.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/technicaldebt/DebtDecorator.java deleted file mode 100644 index 2caf164d9c2..00000000000 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/technicaldebt/DebtDecorator.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * 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.plugins.core.technicaldebt; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.collect.ImmutableList; -import org.sonar.api.CoreProperties; -import org.sonar.api.PropertyType; -import org.sonar.api.batch.*; -import org.sonar.api.batch.rule.Rule; -import org.sonar.api.batch.rule.Rules; -import org.sonar.api.component.ResourcePerspectives; -import org.sonar.api.config.PropertyDefinition; -import org.sonar.api.issue.Issuable; -import org.sonar.api.issue.Issue; -import org.sonar.api.issue.internal.DefaultIssue; -import org.sonar.api.measures.*; -import org.sonar.api.resources.Project; -import org.sonar.api.resources.Resource; -import org.sonar.api.resources.ResourceUtils; -import org.sonar.api.rule.RuleKey; -import org.sonar.api.rules.RuleFinder; -import org.sonar.api.technicaldebt.batch.Characteristic; -import org.sonar.api.technicaldebt.batch.TechnicalDebtModel; - -import javax.annotation.CheckForNull; -import javax.annotation.Nullable; - -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import static com.google.common.collect.Lists.newArrayList; -import static com.google.common.collect.Maps.newHashMap; - -/** - * Decorator that computes the technical debt metric - */ -@DependsUpon(DecoratorBarriers.ISSUES_TRACKED) -public final class DebtDecorator implements Decorator { - - private final ResourcePerspectives perspectives; - private final TechnicalDebtModel model; - private final Rules rules; - - /** - * ruleFinder is needed to load "old" rule in order to persist rule measure - */ - private final RuleFinder ruleFinder; - - public DebtDecorator(ResourcePerspectives perspectives, TechnicalDebtModel model, Rules rules, RuleFinder ruleFinder) { - this.perspectives = perspectives; - this.model = model; - this.rules = rules; - this.ruleFinder = ruleFinder; - } - - public boolean shouldExecuteOnProject(Project project) { - return true; - } - - @DependedUpon - public List<Metric> generatesMetrics() { - return Arrays.asList(CoreMetrics.TECHNICAL_DEBT); - } - - public void decorate(Resource resource, DecoratorContext context) { - Issuable issuable = perspectives.as(Issuable.class, resource); - if (issuable != null && shouldSaveMeasure(context)) { - List<Issue> issues = newArrayList(issuable.issues()); - saveMeasures(context, issues); - } - } - - private void saveMeasures(DecoratorContext context, List<Issue> issues) { - Long total = 0L; - SumMap<RuleKey> ruleDebts = new SumMap<RuleKey>(); - SumMap<Characteristic> characteristicDebts = new SumMap<Characteristic>(); - - // Aggregate rules debt from current issues (and populate current characteristic debt) - for (Issue issue : issues) { - Long debt = ((DefaultIssue) issue).debtInMinutes(); - total += computeDebt(debt, issue.ruleKey(), ruleDebts, characteristicDebts); - } - - // Aggregate rules debt from children (and populate children characteristics debt) - for (Measure measure : context.getChildrenMeasures(MeasuresFilters.rules(CoreMetrics.TECHNICAL_DEBT))) { - Long debt = measure.getValue().longValue(); - RuleMeasure ruleMeasure = (RuleMeasure) measure; - total += computeDebt(debt, ruleMeasure.getRule().ruleKey(), ruleDebts, characteristicDebts); - } - - context.saveMeasure(CoreMetrics.TECHNICAL_DEBT, total.doubleValue()); - saveOnRule(context, ruleDebts); - for (Characteristic characteristic : model.characteristics()) { - Long debt = characteristicDebts.get(characteristic); - saveCharacteristicMeasure(context, characteristic, debt != null ? debt.doubleValue() : 0d, false); - } - } - - private Long computeDebt(@Nullable Long debt, RuleKey ruleKey, SumMap<RuleKey> ruleDebts, SumMap<Characteristic> characteristicDebts) { - if (debt != null) { - Rule rule = rules.find(ruleKey); - if (rule != null) { - String characteristicKey = rule.debtSubCharacteristic(); - if (characteristicKey != null) { - Characteristic characteristic = model.characteristicByKey(characteristicKey); - if (characteristic != null) { - ruleDebts.add(ruleKey, debt); - characteristicDebts.add(characteristic, debt); - propagateTechnicalDebtInParents(characteristic.parent(), debt, characteristicDebts); - return debt; - } - } - } - } - return 0L; - } - - private void propagateTechnicalDebtInParents(@Nullable Characteristic characteristic, long value, SumMap<Characteristic> characteristicDebts) { - if (characteristic != null) { - characteristicDebts.add(characteristic, value); - propagateTechnicalDebtInParents(characteristic.parent(), value, characteristicDebts); - } - } - - private void saveOnRule(DecoratorContext context, SumMap<RuleKey> ruleDebts) { - for (Map.Entry<RuleKey, Long> entry : ruleDebts.entrySet()) { - org.sonar.api.rules.Rule oldRule = ruleFinder.findByKey(entry.getKey()); - if (oldRule != null) { - saveRuleMeasure(context, oldRule, entry.getValue().doubleValue(), ResourceUtils.isEntity(context.getResource())); - } - } - } - - @VisibleForTesting - void saveCharacteristicMeasure(DecoratorContext context, Characteristic characteristic, Double value, boolean inMemory) { - // we need the value on projects (root or module) even if value==0 in order to display correctly the SQALE history chart (see SQALE-122) - // BUT we don't want to save zero-values for non top-characteristics (see SQALE-147) - if (value > 0.0 || (ResourceUtils.isProject(context.getResource()) && characteristic.isRoot())) { - Measure measure = new Measure(CoreMetrics.TECHNICAL_DEBT); - measure.setCharacteristic(characteristic); - saveMeasure(context, measure, value, inMemory); - } - } - - @VisibleForTesting - void saveRuleMeasure(DecoratorContext context, org.sonar.api.rules.Rule rule, Double value, boolean inMemory) { - // we need the value on projects (root or module) even if value==0 in order to display correctly the SQALE history chart (see SQALE-122) - // BUT we don't want to save zero-values for non top-characteristics (see SQALE-147) - if (value > 0.0) { - RuleMeasure measure = new RuleMeasure(CoreMetrics.TECHNICAL_DEBT, rule, null, null); - saveMeasure(context, measure, value, inMemory); - } - } - - private void saveMeasure(DecoratorContext context, Measure measure, Double value, boolean inMemory) { - measure.setValue(value); - if (inMemory) { - measure.setPersistenceMode(PersistenceMode.MEMORY); - } - context.saveMeasure(measure); - } - - private boolean shouldSaveMeasure(DecoratorContext context) { - return context.getMeasure(CoreMetrics.TECHNICAL_DEBT) == null; - } - - public static List<PropertyDefinition> definitions() { - return ImmutableList.of( - PropertyDefinition.builder(CoreProperties.HOURS_IN_DAY) - .name("Number of working hours in a day") - .type(PropertyType.INTEGER) - .defaultValue("8") - .category(CoreProperties.CATEGORY_TECHNICAL_DEBT) - .deprecatedKey("sqale.hoursInDay") - .build() - ); - } - - private static class SumMap<E> { - private Map<E, Long> sumByKeys; - - public SumMap() { - sumByKeys = newHashMap(); - } - - public void add(@Nullable E key, Long value) { - if (key != null) { - Long currentValue = sumByKeys.get(key); - sumByKeys.put(key, currentValue != null ? currentValue + value : value); - } - } - - @CheckForNull - public Long get(E key) { - return sumByKeys.get(key); - } - - public Set<Map.Entry<E, Long>> entrySet() { - return sumByKeys.entrySet(); - } - } -} diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/technicaldebt/NewDebtDecorator.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/technicaldebt/NewDebtDecorator.java deleted file mode 100644 index f5f7062a584..00000000000 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/technicaldebt/NewDebtDecorator.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * 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.plugins.core.technicaldebt; - -import com.google.common.collect.ImmutableList; -import org.sonar.api.batch.*; -import org.sonar.api.component.ResourcePerspectives; -import org.sonar.api.issue.Issuable; -import org.sonar.api.issue.Issue; -import org.sonar.api.measures.CoreMetrics; -import org.sonar.api.measures.Measure; -import org.sonar.api.measures.MeasureUtils; -import org.sonar.api.measures.Metric; -import org.sonar.api.resources.Project; -import org.sonar.api.resources.Resource; -import org.sonar.batch.components.Period; -import org.sonar.batch.components.TimeMachineConfiguration; -import org.sonar.batch.debt.IssueChangelogDebtCalculator; - -import javax.annotation.Nullable; - -import java.util.Collection; -import java.util.Date; -import java.util.List; - -import static com.google.common.collect.Lists.newArrayList; - -/** - * Decorator that computes the technical debt metric - */ -@DependsUpon(DecoratorBarriers.ISSUES_TRACKED) -public final class NewDebtDecorator implements Decorator { - - private final ResourcePerspectives perspectives; - private final TimeMachineConfiguration timeMachineConfiguration; - private final IssueChangelogDebtCalculator issueChangelogDebtCalculator; - - public NewDebtDecorator(ResourcePerspectives perspectives, TimeMachineConfiguration timeMachineConfiguration, - IssueChangelogDebtCalculator issueChangelogDebtCalculator) { - this.perspectives = perspectives; - this.timeMachineConfiguration = timeMachineConfiguration; - this.issueChangelogDebtCalculator = issueChangelogDebtCalculator; - } - - public boolean shouldExecuteOnProject(Project project) { - return true; - } - - @DependedUpon - public List<Metric> generatesMetrics() { - return ImmutableList.of( - CoreMetrics.NEW_TECHNICAL_DEBT - ); - } - - public void decorate(Resource resource, DecoratorContext context) { - Issuable issuable = perspectives.as(Issuable.class, resource); - if (issuable != null && shouldSaveNewMetrics(context)) { - List<Issue> issues = newArrayList(issuable.issues()); - saveMeasures(context, issues); - } - } - - private void saveMeasures(DecoratorContext context, Collection<Issue> issues) { - Measure measure = new Measure(CoreMetrics.NEW_TECHNICAL_DEBT); - for (Period period : timeMachineConfiguration.periods()) { - Date periodDate = period.getDate(); - double value = calculateNewTechnicalDebtValue(issues, periodDate); - Collection<Measure> children = context.getChildrenMeasures(measure.getMetric()); - double sum = MeasureUtils.sumOnVariation(true, period.getIndex(), children) + value; - measure.setVariation(period.getIndex(), sum); - } - context.saveMeasure(measure); - } - - private long calculateNewTechnicalDebtValue(Collection<Issue> issues, @Nullable Date periodDate) { - long result = 0; - for (Issue issue : issues) { - Long debt = issueChangelogDebtCalculator.calculateNewTechnicalDebt(issue, periodDate); - if (debt != null) { - result += debt; - } - } - return result; - } - - private boolean shouldSaveNewMetrics(DecoratorContext context) { - return context.getMeasure(CoreMetrics.NEW_TECHNICAL_DEBT) == null; - } - -} diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/technicaldebt/package-info.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/technicaldebt/package-info.java deleted file mode 100644 index defa4e01d36..00000000000 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/technicaldebt/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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. - */ -@ParametersAreNonnullByDefault -package org.sonar.plugins.core.technicaldebt; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/ExclusionPropertiesTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/ExclusionPropertiesTest.java deleted file mode 100644 index 42aed67cb00..00000000000 --- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/ExclusionPropertiesTest.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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.plugins.core; - -import org.junit.Test; -import org.sonar.api.CoreProperties; -import org.sonar.api.config.PropertyDefinition; - -import static org.fest.assertions.Assertions.assertThat; - -public class ExclusionPropertiesTest { - @Test - public void definitions() throws Exception { - assertThat(ExclusionProperties.definitions().size()).isGreaterThan(0); - for (PropertyDefinition definition : ExclusionProperties.definitions()) { - assertThat(definition.category()).isEqualTo(CoreProperties.CATEGORY_EXCLUSIONS); - } - } -} diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/CoverageMeasurementFilterTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/CoverageMeasurementFilterTest.java index 8254fb28094..072dea5844e 100644 --- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/CoverageMeasurementFilterTest.java +++ b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/CoverageMeasurementFilterTest.java @@ -27,6 +27,7 @@ import org.sonar.api.measures.CoreMetrics; import org.sonar.api.measures.Measure; import org.sonar.api.resources.File; import org.sonar.api.resources.Resource; +import org.sonar.core.config.ExclusionProperties; import static org.fest.assertions.Assertions.assertThat; import static org.mockito.Mockito.mock; @@ -40,7 +41,7 @@ public class CoverageMeasurementFilterTest { @Before public void createFilter() { - settings = new Settings(new PropertyDefinitions(CoverageMeasurementFilter.getPropertyDefinitions())); + settings = new Settings(new PropertyDefinitions(ExclusionProperties.all())); filter = new CoverageMeasurementFilter(settings, new CoverageDecorator(), new LineCoverageDecorator(), new BranchCoverageDecorator()); } @@ -57,7 +58,7 @@ public class CoverageMeasurementFilterTest { Measure coverageMeasure = mock(Measure.class); when(coverageMeasure.getMetric()).thenReturn(CoreMetrics.LINES_TO_COVER); - settings.setProperty(CoverageMeasurementFilter.PROPERTY_COVERAGE_EXCLUSIONS, "src/org/polop/*"); + settings.setProperty("sonar.coverage.exclusions", "src/org/polop/*"); filter.initPatterns(); assertThat(filter.accept(resource, coverageMeasure)).isFalse(); } @@ -68,7 +69,7 @@ public class CoverageMeasurementFilterTest { Measure coverageMeasure = mock(Measure.class); when(coverageMeasure.getMetric()).thenReturn(CoreMetrics.COVERAGE); - settings.setProperty(CoverageMeasurementFilter.PROPERTY_COVERAGE_EXCLUSIONS, "src/org/other/*"); + settings.setProperty("sonar.coverage.exclusions", "src/org/other/*"); filter.initPatterns(); assertThat(filter.accept(resource, coverageMeasure)).isTrue(); } diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/technicaldebt/DebtDecoratorTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/technicaldebt/DebtDecoratorTest.java deleted file mode 100644 index 2aac5804446..00000000000 --- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/technicaldebt/DebtDecoratorTest.java +++ /dev/null @@ -1,351 +0,0 @@ -/* - * 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.plugins.core.technicaldebt; - -import com.google.common.collect.Lists; -import org.apache.commons.lang.ObjectUtils; -import org.apache.commons.lang.builder.ToStringBuilder; -import org.apache.commons.lang.builder.ToStringStyle; -import org.hamcrest.Description; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentMatcher; -import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; -import org.sonar.api.batch.DecoratorContext; -import org.sonar.api.batch.rule.Rules; -import org.sonar.api.batch.rule.internal.RulesBuilder; -import org.sonar.api.component.ResourcePerspectives; -import org.sonar.api.issue.Issuable; -import org.sonar.api.issue.Issue; -import org.sonar.api.issue.internal.DefaultIssue; -import org.sonar.api.measures.*; -import org.sonar.api.resources.File; -import org.sonar.api.resources.Project; -import org.sonar.api.resources.Resource; -import org.sonar.api.rule.RuleKey; -import org.sonar.api.rules.RuleFinder; -import org.sonar.api.technicaldebt.batch.Characteristic; -import org.sonar.api.technicaldebt.batch.TechnicalDebtModel; -import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic; -import org.sonar.api.test.IsMeasure; -import org.sonar.api.utils.Duration; - -import java.util.Collections; - -import static com.google.common.collect.Lists.newArrayList; -import static org.fest.assertions.Assertions.assertThat; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.*; - -@RunWith(MockitoJUnitRunner.class) -public class DebtDecoratorTest { - - static final int HOURS_IN_DAY = 8; - - static final Long ONE_DAY_IN_MINUTES = 1L * HOURS_IN_DAY * 60; - - @Mock - DecoratorContext context; - - @Mock - Resource resource; - - @Mock - TechnicalDebtModel debtModel; - - @Mock - Issuable issuable; - - @Mock - ResourcePerspectives perspectives; - - @Mock - RuleFinder ruleFinder; - - RuleKey ruleKey1 = RuleKey.of("repo1", "rule1"); - RuleKey ruleKey2 = RuleKey.of("repo2", "rule2"); - Rules rules; - - DefaultCharacteristic efficiency = new DefaultCharacteristic().setKey("EFFICIENCY"); - DefaultCharacteristic memoryEfficiency = new DefaultCharacteristic().setKey("MEMORY_EFFICIENCY").setParent(efficiency); - - DefaultCharacteristic reusability = new DefaultCharacteristic().setKey("REUSABILITY"); - DefaultCharacteristic modularity = new DefaultCharacteristic().setKey("MODULARITY").setParent(reusability); - - DebtDecorator decorator; - - @Before - public void before() throws Exception { - when(perspectives.as(Issuable.class, resource)).thenReturn(issuable); - RulesBuilder rulesBuilder = new RulesBuilder(); - rulesBuilder.add(ruleKey1).setName("rule1").setDebtSubCharacteristic("MEMORY_EFFICIENCY"); - rulesBuilder.add(ruleKey2).setName("rule2").setDebtSubCharacteristic("MODULARITY"); - rules = rulesBuilder.build(); - - when(ruleFinder.findByKey(ruleKey1)).thenReturn(org.sonar.api.rules.Rule.create(ruleKey1.repository(), ruleKey1.rule())); - when(ruleFinder.findByKey(ruleKey2)).thenReturn(org.sonar.api.rules.Rule.create(ruleKey2.repository(), ruleKey2.rule())); - - when(debtModel.characteristics()).thenReturn(newArrayList(efficiency, memoryEfficiency, reusability, modularity)); - when(debtModel.characteristicByKey("EFFICIENCY")).thenReturn(efficiency); - when(debtModel.characteristicByKey("MEMORY_EFFICIENCY")).thenReturn(memoryEfficiency); - when(debtModel.characteristicByKey("REUSABILITY")).thenReturn(reusability); - when(debtModel.characteristicByKey("MODULARITY")).thenReturn(modularity); - - decorator = new DebtDecorator(perspectives, debtModel, rules, ruleFinder); - } - - @Test - public void generates_metrics() throws Exception { - assertThat(decorator.generatesMetrics()).hasSize(1); - } - - @Test - public void execute_on_project() throws Exception { - assertThat(decorator.shouldExecuteOnProject(null)).isTrue(); - } - - @Test - public void not_save_if_measure_already_computed() { - when(context.getMeasure(CoreMetrics.TECHNICAL_DEBT)).thenReturn(new Measure()); - - decorator.decorate(resource, context); - - verify(context, never()).saveMeasure(argThat(new IsMeasure(CoreMetrics.TECHNICAL_DEBT))); - } - - @Test - public void add_technical_debt_from_one_issue_and_no_parent() throws Exception { - Issue issue = createIssue("rule1", "repo1").setDebt(Duration.create(ONE_DAY_IN_MINUTES)); - when(issuable.issues()).thenReturn(newArrayList(issue)); - - decorator.decorate(resource, context); - - verify(context).saveMeasure(CoreMetrics.TECHNICAL_DEBT, ONE_DAY_IN_MINUTES.doubleValue()); - verify(context).saveMeasure(argThat(new IsRuleMeasure(CoreMetrics.TECHNICAL_DEBT, ruleKey1, ONE_DAY_IN_MINUTES.doubleValue()))); - } - - @Test - public void add_technical_debt_from_one_issue_without_debt() throws Exception { - Issue issue = createIssue("rule1", "repo1").setDebt(null); - when(issuable.issues()).thenReturn(newArrayList(issue)); - - decorator.decorate(resource, context); - - verify(context).saveMeasure(CoreMetrics.TECHNICAL_DEBT, 0.0); - } - - @Test - public void add_technical_debt_from_one_issue_and_propagate_to_parents() throws Exception { - Issue issue = createIssue("rule1", "repo1").setDebt(Duration.create(ONE_DAY_IN_MINUTES)); - when(issuable.issues()).thenReturn(newArrayList(issue)); - - decorator.decorate(resource, context); - - verify(context).saveMeasure(CoreMetrics.TECHNICAL_DEBT, ONE_DAY_IN_MINUTES.doubleValue()); - verify(context).saveMeasure(argThat(new IsRuleMeasure(CoreMetrics.TECHNICAL_DEBT, ruleKey1, ONE_DAY_IN_MINUTES.doubleValue()))); - verify(context).saveMeasure(argThat(new IsCharacteristicMeasure(CoreMetrics.TECHNICAL_DEBT, efficiency, ONE_DAY_IN_MINUTES.doubleValue()))); - verify(context).saveMeasure(argThat(new IsCharacteristicMeasure(CoreMetrics.TECHNICAL_DEBT, memoryEfficiency, ONE_DAY_IN_MINUTES.doubleValue()))); - } - - @Test - public void add_technical_debt_from_issues() throws Exception { - Long technicalDebt1 = ONE_DAY_IN_MINUTES; - Long technicalDebt2 = 2 * ONE_DAY_IN_MINUTES; - - Issue issue1 = createIssue("rule1", "repo1").setDebt(Duration.create(technicalDebt1)); - Issue issue2 = createIssue("rule1", "repo1").setDebt(Duration.create(technicalDebt1)); - Issue issue3 = createIssue("rule2", "repo2").setDebt(Duration.create(technicalDebt2)); - Issue issue4 = createIssue("rule2", "repo2").setDebt(Duration.create(technicalDebt2)); - when(issuable.issues()).thenReturn(newArrayList(issue1, issue2, issue3, issue4)); - - decorator.decorate(resource, context); - - verify(context).saveMeasure(CoreMetrics.TECHNICAL_DEBT, 6d * ONE_DAY_IN_MINUTES); - verify(context).saveMeasure(argThat(new IsRuleMeasure(CoreMetrics.TECHNICAL_DEBT, ruleKey1, 2d * ONE_DAY_IN_MINUTES))); - verify(context).saveMeasure(argThat(new IsRuleMeasure(CoreMetrics.TECHNICAL_DEBT, ruleKey2, 4d * ONE_DAY_IN_MINUTES))); - } - - @Test - public void add_technical_debt_from_current_and_children_measures() throws Exception { - Issue issue1 = createIssue("rule1", "repo1").setDebt(Duration.create(ONE_DAY_IN_MINUTES)); - Issue issue2 = createIssue("rule1", "repo1").setDebt(Duration.create(ONE_DAY_IN_MINUTES)); - when(issuable.issues()).thenReturn(newArrayList(issue1, issue2)); - - when(context.getChildrenMeasures(any(MeasuresFilter.class))).thenReturn(Lists.<Measure>newArrayList( - new RuleMeasure(CoreMetrics.TECHNICAL_DEBT, - org.sonar.api.rules.Rule.create(ruleKey1.repository(), ruleKey1.rule()), null, null) - .setValue(5d * ONE_DAY_IN_MINUTES) - )); - decorator.decorate(resource, context); - - verify(context).saveMeasure(CoreMetrics.TECHNICAL_DEBT, 7d * ONE_DAY_IN_MINUTES); - verify(context).saveMeasure(argThat(new IsRuleMeasure(CoreMetrics.TECHNICAL_DEBT, ruleKey1, 7d * ONE_DAY_IN_MINUTES))); - verify(context).saveMeasure(argThat(new IsCharacteristicMeasure(CoreMetrics.TECHNICAL_DEBT, memoryEfficiency, 7d * ONE_DAY_IN_MINUTES))); - verify(context).saveMeasure(argThat(new IsCharacteristicMeasure(CoreMetrics.TECHNICAL_DEBT, efficiency, 7d * ONE_DAY_IN_MINUTES))); - } - - @Test - public void add_technical_debt_only_from_children_measures() throws Exception { - when(issuable.issues()).thenReturn(Collections.<Issue>emptyList()); - - when(context.getChildrenMeasures(any(MeasuresFilter.class))).thenReturn(Lists.<Measure>newArrayList( - new RuleMeasure(CoreMetrics.TECHNICAL_DEBT, - org.sonar.api.rules.Rule.create(ruleKey1.repository(), ruleKey1.rule()) - , null, null).setValue(5d * ONE_DAY_IN_MINUTES), - - new RuleMeasure(CoreMetrics.TECHNICAL_DEBT, - org.sonar.api.rules.Rule.create(ruleKey2.repository(), ruleKey2.rule()) - , null, null).setValue(10d * ONE_DAY_IN_MINUTES) - )); - decorator.decorate(resource, context); - - verify(context).saveMeasure(CoreMetrics.TECHNICAL_DEBT, 15d * ONE_DAY_IN_MINUTES); - verify(context).saveMeasure(argThat(new IsRuleMeasure(CoreMetrics.TECHNICAL_DEBT, ruleKey1, 5d * ONE_DAY_IN_MINUTES))); - verify(context).saveMeasure(argThat(new IsRuleMeasure(CoreMetrics.TECHNICAL_DEBT, ruleKey2, 10d * ONE_DAY_IN_MINUTES))); - verify(context).saveMeasure(argThat(new IsCharacteristicMeasure(CoreMetrics.TECHNICAL_DEBT, memoryEfficiency, 5d * ONE_DAY_IN_MINUTES))); - verify(context).saveMeasure(argThat(new IsCharacteristicMeasure(CoreMetrics.TECHNICAL_DEBT, efficiency, 5d * ONE_DAY_IN_MINUTES))); - verify(context).saveMeasure(argThat(new IsCharacteristicMeasure(CoreMetrics.TECHNICAL_DEBT, reusability, 10d * ONE_DAY_IN_MINUTES))); - verify(context).saveMeasure(argThat(new IsCharacteristicMeasure(CoreMetrics.TECHNICAL_DEBT, modularity, 10d * ONE_DAY_IN_MINUTES))); - } - - @Test - public void always_save_technical_debt_for_positive_values() throws Exception { - // for a project - DecoratorContext context = mock(DecoratorContext.class); - when(context.getResource()).thenReturn(new Project("foo")); - decorator.saveCharacteristicMeasure(context, (Characteristic) null, 12.0, false); - verify(context, times(1)).saveMeasure(new Measure(CoreMetrics.TECHNICAL_DEBT)); - - // or for a file - context = mock(DecoratorContext.class); - when(context.getResource()).thenReturn(new File("foo")); - decorator.saveCharacteristicMeasure(context, (Characteristic) null, 12.0, false); - verify(context, times(1)).saveMeasure(new Measure(CoreMetrics.TECHNICAL_DEBT)); - } - - @Test - public void always_save_technical_debt_for_project_if_top_characteristic() throws Exception { - DecoratorContext context = mock(DecoratorContext.class); - when(context.getResource()).thenReturn(new Project("foo")); - - // this is a top characteristic - DefaultCharacteristic rootCharacteristic = new DefaultCharacteristic().setKey("root"); - - decorator.saveCharacteristicMeasure(context, rootCharacteristic, 0.0, true); - verify(context, times(1)).saveMeasure(new Measure(CoreMetrics.TECHNICAL_DEBT).setCharacteristic(rootCharacteristic)); - } - - /** - * SQALE-147 - */ - @Test - public void never_save_technical_debt_for_project_if_not_top_characteristic() throws Exception { - DecoratorContext context = mock(DecoratorContext.class); - when(context.getResource()).thenReturn(new Project("foo")); - - DefaultCharacteristic rootCharacteristic = new DefaultCharacteristic().setKey("EFFICIENCY"); - DefaultCharacteristic characteristic = new DefaultCharacteristic().setKey("MEMORY_EFFICIENCY").setParent(rootCharacteristic); - - decorator.saveCharacteristicMeasure(context, characteristic, 0.0, true); - verify(context, never()).saveMeasure(any(Measure.class)); - } - - @Test - public void not_save_technical_debt_for_file_if_zero() throws Exception { - DecoratorContext context = mock(DecoratorContext.class); - when(context.getResource()).thenReturn(new File("foo")); - - decorator.saveCharacteristicMeasure(context, (Characteristic) null, 0.0, true); - verify(context, never()).saveMeasure(new Measure(CoreMetrics.TECHNICAL_DEBT)); - } - - @Test - public void check_definitions() { - assertThat(DebtDecorator.definitions()).hasSize(1); - } - - private DefaultIssue createIssue(String ruleKey, String repositoryKey) { - return new DefaultIssue().setRuleKey(RuleKey.of(repositoryKey, ruleKey)); - } - - class IsCharacteristicMeasure extends ArgumentMatcher<Measure> { - Metric metric = null; - Characteristic characteristic = null; - Double value = null; - - public IsCharacteristicMeasure(Metric metric, Characteristic characteristic, Double value) { - this.metric = metric; - this.characteristic = characteristic; - this.value = value; - } - - @Override - public boolean matches(Object o) { - if (!(o instanceof Measure)) { - return false; - } - Measure m = (Measure) o; - return ObjectUtils.equals(metric, m.getMetric()) && - ObjectUtils.equals(characteristic, m.getCharacteristic()) && - ObjectUtils.equals(value, m.getValue()); - } - - @Override - public void describeTo(Description description) { - description.appendText(new StringBuilder() - .append("value=").append(value).append(",") - .append("characteristic=").append(characteristic.key()).append(",") - .append("metric=").append(metric.getKey()).toString()) - ; - } - } - - class IsRuleMeasure extends ArgumentMatcher<RuleMeasure> { - Metric metric = null; - RuleKey ruleKey = null; - Double value = null; - - public IsRuleMeasure(Metric metric, RuleKey ruleKey, Double value) { - this.metric = metric; - this.ruleKey = ruleKey; - this.value = value; - } - - @Override - public boolean matches(Object o) { - if (!(o instanceof RuleMeasure)) { - return false; - } - RuleMeasure m = (RuleMeasure) o; - return ObjectUtils.equals(metric, m.getMetric()) && - ObjectUtils.equals(ruleKey.repository(), m.getRule().getRepositoryKey()) && - ObjectUtils.equals(ruleKey.rule(), m.getRule().getKey()) && - ObjectUtils.equals(value, m.getValue()); - } - - @Override - public void describeTo(Description description) { - description.appendText(ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE)); - } - } -} diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/technicaldebt/NewDebtDecoratorTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/technicaldebt/NewDebtDecoratorTest.java deleted file mode 100644 index a9391f96da2..00000000000 --- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/technicaldebt/NewDebtDecoratorTest.java +++ /dev/null @@ -1,374 +0,0 @@ -/* - * 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.plugins.core.technicaldebt; - -import org.apache.commons.lang.ObjectUtils; -import org.apache.commons.lang.time.DateUtils; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentMatcher; -import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; -import org.sonar.api.CoreProperties; -import org.sonar.api.batch.DecoratorContext; -import org.sonar.api.component.ResourcePerspectives; -import org.sonar.api.config.Settings; -import org.sonar.api.issue.Issuable; -import org.sonar.api.issue.Issue; -import org.sonar.api.issue.internal.DefaultIssue; -import org.sonar.api.issue.internal.FieldDiffs; -import org.sonar.api.measures.CoreMetrics; -import org.sonar.api.measures.Measure; -import org.sonar.api.measures.Metric; -import org.sonar.api.resources.Resource; -import org.sonar.api.test.IsMeasure; -import org.sonar.api.utils.Duration; -import org.sonar.batch.components.Period; -import org.sonar.batch.components.TimeMachineConfiguration; -import org.sonar.batch.debt.IssueChangelogDebtCalculator; - -import java.util.Date; - -import static com.google.common.collect.Lists.newArrayList; -import static org.fest.assertions.Assertions.assertThat; -import static org.mockito.Matchers.argThat; -import static org.mockito.Mockito.*; - -@RunWith(MockitoJUnitRunner.class) -public class NewDebtDecoratorTest { - - NewDebtDecorator decorator; - - @Mock - TimeMachineConfiguration timeMachineConfiguration; - - @Mock - Resource resource; - - @Mock - Issuable issuable; - - @Mock - DecoratorContext context; - - Date rightNow; - Date elevenDaysAgo; - Date tenDaysAgo; - Date nineDaysAgo; - Date fiveDaysAgo; - Date fourDaysAgo; - - static final int HOURS_IN_DAY = 8; - - static final Long ONE_DAY_IN_MINUTES = 1L * HOURS_IN_DAY * 60; - static final Long TWO_DAYS_IN_MINUTES = 2L * HOURS_IN_DAY * 60; - static final Long FIVE_DAYS_IN_MINUTES = 5L * HOURS_IN_DAY * 60; - - @Before - public void setup() { - Settings settings = new Settings(); - settings.setProperty(CoreProperties.HOURS_IN_DAY, HOURS_IN_DAY); - - ResourcePerspectives perspectives = mock(ResourcePerspectives.class); - when(perspectives.as(Issuable.class, resource)).thenReturn(issuable); - - rightNow = new Date(); - elevenDaysAgo = DateUtils.addDays(rightNow, -11); - tenDaysAgo = DateUtils.addDays(rightNow, -10); - nineDaysAgo = DateUtils.addDays(rightNow, -9); - fiveDaysAgo = DateUtils.addDays(rightNow, -5); - fourDaysAgo = DateUtils.addDays(rightNow, -4); - - when(timeMachineConfiguration.periods()).thenReturn(newArrayList(new Period(1, fiveDaysAgo), new Period(2, tenDaysAgo))); - - decorator = new NewDebtDecorator(perspectives, timeMachineConfiguration, new IssueChangelogDebtCalculator()); - } - - @Test - public void generates_metrics() throws Exception { - assertThat(decorator.generatesMetrics()).hasSize(1); - } - - @Test - public void execute_on_project() throws Exception { - assertThat(decorator.shouldExecuteOnProject(null)).isTrue(); - } - - @Test - public void save_on_one_issue_with_one_new_changelog() { - Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(TWO_DAYS_IN_MINUTES)).setChanges( - newArrayList( - // changelog created at is null because it has just been created on the current analysis - new FieldDiffs().setDiff("technicalDebt", ONE_DAY_IN_MINUTES, TWO_DAYS_IN_MINUTES).setCreationDate(null) - ) - ); - when(issuable.issues()).thenReturn(newArrayList(issue)); - - decorator.decorate(resource, context); - - // remember : period1 is 5daysAgo, period2 is 10daysAgo - verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 1.0 * ONE_DAY_IN_MINUTES, 1.0 * ONE_DAY_IN_MINUTES))); - } - - @Test - public void save_on_one_issue_with_changelog() { - Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)).setChanges( - newArrayList( - new FieldDiffs().setDiff("technicalDebt", TWO_DAYS_IN_MINUTES, FIVE_DAYS_IN_MINUTES).setCreationDate(null), - new FieldDiffs().setDiff("technicalDebt", ONE_DAY_IN_MINUTES, TWO_DAYS_IN_MINUTES).setCreationDate(fourDaysAgo) - ) - ); - when(issuable.issues()).thenReturn(newArrayList(issue)); - - decorator.decorate(resource, context); - - // remember : period1 is 5daysAgo, period2 is 10daysAgo - verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 4.0 * ONE_DAY_IN_MINUTES, 4.0 * ONE_DAY_IN_MINUTES))); - } - - @Test - public void save_on_one_issue_with_changelog_only_in_the_past() { - Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(ONE_DAY_IN_MINUTES)).setChanges( - newArrayList( - // Change before all periods - new FieldDiffs().setDiff("technicalDebt", null, ONE_DAY_IN_MINUTES).setCreationDate(elevenDaysAgo) - ) - ); - when(issuable.issues()).thenReturn(newArrayList(issue)); - - decorator.decorate(resource, context); - - // remember : period1 is 5daysAgo, period2 is 10daysAgo - verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 0.0, 0.0))); - } - - @Test - public void save_on_one_issue_with_changelog_having_null_value() { - Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)).setChanges( - newArrayList( - new FieldDiffs().setDiff("technicalDebt", null, FIVE_DAYS_IN_MINUTES).setCreationDate(null), - new FieldDiffs().setDiff("technicalDebt", ONE_DAY_IN_MINUTES, null).setCreationDate(fourDaysAgo), - new FieldDiffs().setDiff("technicalDebt", null, ONE_DAY_IN_MINUTES).setCreationDate(nineDaysAgo) - ) - ); - when(issuable.issues()).thenReturn(newArrayList(issue)); - - decorator.decorate(resource, context); - - // remember : period1 is 5daysAgo, period2 is 10daysAgo - verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 4.0 * ONE_DAY_IN_MINUTES, 5.0 * ONE_DAY_IN_MINUTES))); - } - - @Test - public void save_on_one_issue_with_changelog_and_periods_have_no_dates() { - when(timeMachineConfiguration.periods()).thenReturn(newArrayList(new Period(1, null), new Period(2, null))); - - Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)).setChanges( - newArrayList( - new FieldDiffs().setDiff("technicalDebt", null, FIVE_DAYS_IN_MINUTES).setCreationDate(null), - new FieldDiffs().setDiff("technicalDebt", ONE_DAY_IN_MINUTES, null).setCreationDate(fourDaysAgo), - new FieldDiffs().setDiff("technicalDebt", null, ONE_DAY_IN_MINUTES).setCreationDate(nineDaysAgo) - ) - ); - when(issuable.issues()).thenReturn(newArrayList(issue)); - - decorator.decorate(resource, context); - - // remember : period1 is 5daysAgo, period2 is 10daysAgo - verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 5.0 * ONE_DAY_IN_MINUTES, 5.0 * ONE_DAY_IN_MINUTES))); - } - - @Test - public void save_on_one_issue_with_changelog_having_not_only_technical_debt_changes() { - Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)).setChanges( - newArrayList( - new FieldDiffs() - .setDiff("actionPlan", "1.0", "1.1").setCreationDate(fourDaysAgo) - .setDiff("technicalDebt", ONE_DAY_IN_MINUTES, TWO_DAYS_IN_MINUTES).setCreationDate(fourDaysAgo) - ) - ); - when(issuable.issues()).thenReturn(newArrayList(issue)); - - decorator.decorate(resource, context); - - // remember : period1 is 5daysAgo, period2 is 10daysAgo - verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 4.0 * ONE_DAY_IN_MINUTES, 4.0 * ONE_DAY_IN_MINUTES))); - } - - @Test - public void save_on_issues_with_changelog() { - Issue issue1 = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)).setChanges( - newArrayList( - new FieldDiffs().setDiff("technicalDebt", TWO_DAYS_IN_MINUTES, FIVE_DAYS_IN_MINUTES).setCreationDate(rightNow), - new FieldDiffs().setDiff("technicalDebt", ONE_DAY_IN_MINUTES, TWO_DAYS_IN_MINUTES).setCreationDate(fourDaysAgo), - new FieldDiffs().setDiff("technicalDebt", null, ONE_DAY_IN_MINUTES).setCreationDate(nineDaysAgo) - ) - ); - Issue issue2 = new DefaultIssue().setKey("B").setCreationDate(tenDaysAgo).setDebt(Duration.create(TWO_DAYS_IN_MINUTES)).setChanges( - newArrayList( - new FieldDiffs().setDiff("technicalDebt", ONE_DAY_IN_MINUTES, TWO_DAYS_IN_MINUTES).setCreationDate(rightNow), - new FieldDiffs().setDiff("technicalDebt", null, ONE_DAY_IN_MINUTES).setCreationDate(nineDaysAgo) - ) - ); - when(issuable.issues()).thenReturn(newArrayList(issue1, issue2)); - - decorator.decorate(resource, context); - - // remember : period1 is 5daysAgo, period2 is 10daysAgo - verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 5.0 * ONE_DAY_IN_MINUTES, 7.0 * ONE_DAY_IN_MINUTES))); - } - - @Test - public void save_on_one_issue_without_changelog() { - when(issuable.issues()).thenReturn(newArrayList( - (Issue) new DefaultIssue().setKey("A").setCreationDate(nineDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES))) - ); - - decorator.decorate(resource, context); - - // remember : period1 is 5daysAgo, period2 is 10daysAgo - verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 0.0, 5.0 * ONE_DAY_IN_MINUTES))); - } - - @Test - public void save_on_one_issue_without_technical_debt_and_without_changelog() { - when(issuable.issues()).thenReturn(newArrayList( - (Issue) new DefaultIssue().setKey("A").setCreationDate(nineDaysAgo).setDebt(null)) - ); - - decorator.decorate(resource, context); - - // remember : period1 is 5daysAgo, period2 is 10daysAgo - verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 0.0, 0.0))); - } - - @Test - public void save_on_one_issue_without_changelog_and_periods_have_no_dates() { - when(timeMachineConfiguration.periods()).thenReturn(newArrayList(new Period(1, null), new Period(2, null))); - - when(issuable.issues()).thenReturn(newArrayList( - (Issue) new DefaultIssue().setKey("A").setCreationDate(nineDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES))) - ); - - decorator.decorate(resource, context); - - // remember : period1 is null, period2 is null - verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 5.0 * ONE_DAY_IN_MINUTES, 5.0 * ONE_DAY_IN_MINUTES))); - } - - @Test - public void save_on_issues_without_changelog() { - when(issuable.issues()).thenReturn(newArrayList( - (Issue) new DefaultIssue().setKey("A").setCreationDate(nineDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)), - new DefaultIssue().setKey("B").setCreationDate(fiveDaysAgo).setDebt(Duration.create(TWO_DAYS_IN_MINUTES)) - )); - - decorator.decorate(resource, context); - - // remember : period1 is 5daysAgo, period2 is 10daysAgo - verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 0.0, 7.0 * ONE_DAY_IN_MINUTES))); - } - - @Test - public void save_on_issues_with_changelog_and_issues_without_changelog() { - // issue1 and issue2 have changelog - Issue issue1 = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)).setChanges( - newArrayList( - new FieldDiffs().setDiff("technicalDebt", TWO_DAYS_IN_MINUTES, FIVE_DAYS_IN_MINUTES).setCreationDate(rightNow), - new FieldDiffs().setDiff("technicalDebt", ONE_DAY_IN_MINUTES, TWO_DAYS_IN_MINUTES).setCreationDate(fourDaysAgo), - new FieldDiffs().setDiff("technicalDebt", null, ONE_DAY_IN_MINUTES).setCreationDate(nineDaysAgo) - ) - ); - Issue issue2 = new DefaultIssue().setKey("B").setCreationDate(tenDaysAgo).setDebt(Duration.create(TWO_DAYS_IN_MINUTES)).setChanges( - newArrayList( - new FieldDiffs().setDiff("technicalDebt", ONE_DAY_IN_MINUTES, TWO_DAYS_IN_MINUTES).setCreationDate(rightNow), - new FieldDiffs().setDiff("technicalDebt", null, ONE_DAY_IN_MINUTES).setCreationDate(nineDaysAgo) - ) - ); - - // issue3 and issue4 have no changelog - Issue issue3 = new DefaultIssue().setKey("C").setCreationDate(nineDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)); - Issue issue4 = new DefaultIssue().setKey("D").setCreationDate(fiveDaysAgo).setDebt(Duration.create(TWO_DAYS_IN_MINUTES)); - when(issuable.issues()).thenReturn(newArrayList(issue1, issue2, issue3, issue4)); - - decorator.decorate(resource, context); - - // remember : period1 is 5daysAgo, period2 is 10daysAgo - verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 5.0 * ONE_DAY_IN_MINUTES, 14.0 * ONE_DAY_IN_MINUTES))); - } - - @Test - public void not_save_if_measure_already_computed() { - when(context.getMeasure(CoreMetrics.NEW_TECHNICAL_DEBT)).thenReturn(new Measure()); - when(issuable.issues()).thenReturn(newArrayList( - (Issue) new DefaultIssue().setKey("A").setCreationDate(nineDaysAgo).setDebt(Duration.create(FIVE_DAYS_IN_MINUTES)), - new DefaultIssue().setKey("B").setCreationDate(fiveDaysAgo).setDebt(Duration.create(TWO_DAYS_IN_MINUTES)) - )); - - decorator.decorate(resource, context); - - verify(context, never()).saveMeasure(argThat(new IsMeasure(CoreMetrics.NEW_TECHNICAL_DEBT))); - } - - /** - * SONAR-5059 - */ - @Test - public void not_return_negative_debt() { - Issue issue = new DefaultIssue().setKey("A").setCreationDate(tenDaysAgo).setDebt(Duration.create(ONE_DAY_IN_MINUTES)).setChanges( - newArrayList( - // changelog created at is null because it has just been created on the current analysis - new FieldDiffs().setDiff("technicalDebt", TWO_DAYS_IN_MINUTES, ONE_DAY_IN_MINUTES).setCreationDate(null) - ) - ); - when(issuable.issues()).thenReturn(newArrayList(issue)); - - decorator.decorate(resource, context); - - // remember : period1 is 5daysAgo, period2 is 10daysAgo - verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_TECHNICAL_DEBT, 0.0, 0.0))); - } - - - class IsVariationMeasure extends ArgumentMatcher<Measure> { - Metric metric = null; - Double var1 = null; - Double var2 = null; - - public IsVariationMeasure(Metric metric, Double var1, Double var2) { - this.metric = metric; - this.var1 = var1; - this.var2 = var2; - } - - public boolean matches(Object o) { - if (!(o instanceof Measure)) { - return false; - } - Measure m = (Measure) o; - return ObjectUtils.equals(metric, m.getMetric()) && - ObjectUtils.equals(var1, m.getVariation1()) && - ObjectUtils.equals(var2, m.getVariation2()); - } - } - -} |