import org.sonar.batch.issue.tracking.IssueTracking;
import org.sonar.batch.issue.tracking.IssueTrackingDecorator;
import org.sonar.batch.language.LanguageDistributionDecorator;
-import org.sonar.batch.qualitygate.QualityGateVerifier;
import org.sonar.batch.scan.report.ConsoleReport;
import org.sonar.batch.scan.report.HtmlReport;
import org.sonar.batch.scan.report.IssuesReportBuilder;
SqaleRatingDecorator.class,
SqaleRatingSettings.class,
- // Quality Gate
- QualityGateVerifier.class,
-
// Issue tracking
IssueTrackingDecorator.class,
IssueHandlers.class,
+++ /dev/null
-/*
- * 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.batch.qualitygate;
-
-import org.apache.commons.lang.NotImplementedException;
-import org.apache.commons.lang.StringUtils;
-import org.sonar.api.measures.Measure;
-import org.sonar.api.measures.Metric;
-
-class ConditionUtils {
-
- private ConditionUtils() {
- // only static stuff
- }
-
- /**
- * Get the matching alert level for the given measure
- */
- static Metric.Level getLevel(ResolvedCondition condition, Measure measure) {
- if (evaluateCondition(condition, measure, Metric.Level.ERROR)) {
- return Metric.Level.ERROR;
- }
- if (evaluateCondition(condition, measure, Metric.Level.WARN)) {
- return Metric.Level.WARN;
- }
- return Metric.Level.OK;
- }
-
- private static boolean evaluateCondition(ResolvedCondition condition, Measure measure, Metric.Level alertLevel) {
- String valueToEval = getValueToEval(condition, alertLevel);
- if (StringUtils.isEmpty(valueToEval)) {
- return false;
- }
-
- Comparable criteriaValue = getValueForComparison(condition.metric(), valueToEval);
- Comparable measureValue = getMeasureValue(condition, measure);
- if (measureValue != null) {
- return doesReachThresholds(measureValue, criteriaValue, condition);
- }
- return false;
- }
-
- private static boolean doesReachThresholds(Comparable measureValue, Comparable criteriaValue, ResolvedCondition condition) {
- int comparison = measureValue.compareTo(criteriaValue);
- return !(isNotEquals(comparison, condition)
- || isGreater(comparison, condition)
- || isSmaller(comparison, condition)
- || isEquals(comparison, condition));
- }
-
- private static boolean isNotEquals(int comparison, ResolvedCondition condition) {
- return "NE".equals(condition.operator()) && comparison == 0;
- }
-
- private static boolean isGreater(int comparison, ResolvedCondition condition) {
- return "GT".equals(condition.operator()) && comparison != 1;
- }
-
- private static boolean isSmaller(int comparison, ResolvedCondition condition) {
- return "LT".equals(condition.operator()) && comparison != -1;
- }
-
- private static boolean isEquals(int comparison, ResolvedCondition condition) {
- return "EQ".equals(condition.operator()) && comparison != 0;
- }
-
- private static String getValueToEval(ResolvedCondition condition, Metric.Level alertLevel) {
- if (alertLevel.equals(Metric.Level.ERROR)) {
- return condition.errorThreshold();
- } else if (alertLevel.equals(Metric.Level.WARN)) {
- return condition.warningThreshold();
- } else {
- throw new IllegalStateException(alertLevel.toString());
- }
- }
-
- private static Comparable getValueForComparison(Metric metric, String value) {
- Comparable valueToCompare = null;
- try {
- if (isADouble(metric)) {
- valueToCompare = Double.parseDouble(value);
- } else if (isAInteger(metric)) {
- valueToCompare = parseInteger(value);
- } else if (isAString(metric)) {
- valueToCompare = value;
- } else if (isABoolean(metric)) {
- valueToCompare = Integer.parseInt(value);
- } else if (isAWorkDuration(metric)) {
- valueToCompare = Long.parseLong(value);
- } else {
- throw new NotImplementedException(metric.getType().toString());
- }
- } catch (NumberFormatException badValueFormat) {
- throw new IllegalArgumentException(String.format("Quality Gate: Unable to parse value '%s' to compare against %s", value, metric.getName()));
- }
- return valueToCompare;
- }
-
- private static Comparable<Integer> parseInteger(String value) {
- return value.contains(".") ? Integer.parseInt(value.substring(0, value.indexOf('.'))) : Integer.parseInt(value);
- }
-
- private static Comparable getMeasureValue(ResolvedCondition condition, Measure measure) {
- Metric metric = condition.metric();
- if (isADouble(metric)) {
- return getValue(condition, measure);
- }
- if (isAInteger(metric)) {
- return parseInteger(condition, measure);
- }
- if (isAWorkDuration(metric)) {
- return parseLong(condition, measure);
- }
- if (condition.period() == null) {
- return getMeasureValueForStringOrBoolean(metric, measure);
- }
- throw new NotImplementedException(metric.getType().toString());
- }
-
- private static Comparable getMeasureValueForStringOrBoolean(Metric metric, Measure measure) {
- if (isAString(metric)) {
- return measure.getData();
- }
- if (isABoolean(metric)) {
- return measure.getValue().intValue();
- }
- throw new NotImplementedException(metric.getType().toString());
- }
-
- private static Comparable<Integer> parseInteger(ResolvedCondition condition, Measure measure) {
- Double value = getValue(condition, measure);
- return value != null ? value.intValue() : null;
- }
-
- private static Comparable<Long> parseLong(ResolvedCondition condition, Measure measure) {
- Double value = getValue(condition, measure);
- return value != null ? value.longValue() : null;
- }
-
- private static boolean isADouble(Metric metric) {
- return metric.getType() == Metric.ValueType.FLOAT ||
- metric.getType() == Metric.ValueType.PERCENT ||
- metric.getType() == Metric.ValueType.RATING;
- }
-
- private static boolean isAInteger(Metric metric) {
- return metric.getType() == Metric.ValueType.INT ||
- metric.getType() == Metric.ValueType.MILLISEC;
- }
-
- private static boolean isAString(Metric metric) {
- return metric.getType() == Metric.ValueType.STRING ||
- metric.getType() == Metric.ValueType.LEVEL;
- }
-
- private static boolean isABoolean(Metric metric) {
- return metric.getType() == Metric.ValueType.BOOL;
- }
-
- private static boolean isAWorkDuration(Metric metric) {
- return metric.getType() == Metric.ValueType.WORK_DUR;
- }
-
- static Double getValue(ResolvedCondition condition, Measure measure) {
- Integer period = condition.period();
- Double value;
- if (period == null) {
- value = measure.getValue();
- } else {
- switch (period.intValue()) {
- case 1:
- value = measure.getVariation1();
- break;
- case 2:
- value = measure.getVariation2();
- break;
- case 3:
- value = measure.getVariation3();
- break;
- case 4:
- value = measure.getVariation4();
- break;
- case 5:
- value = measure.getVariation5();
- break;
- default:
- throw new IllegalStateException("Following index period is not allowed : " + Double.toString(period));
- }
- }
- return value;
- }
-}
+++ /dev/null
-/*
- * 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.batch.qualitygate;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-import org.sonar.api.batch.BatchSide;
-
-import javax.annotation.Nullable;
-
-import java.util.Collection;
-
-@BatchSide
-public class QualityGate {
-
- private final String name;
-
- private final Collection<ResolvedCondition> conditions;
-
- QualityGate(@Nullable String name) {
- this.name = name;
- this.conditions = Lists.newArrayList();
- }
-
- void add(ResolvedCondition condition) {
- this.conditions.add(condition);
- }
-
- static QualityGate disabled() {
- return new QualityGate(null);
- }
-
- public String name() {
- return name;
- }
-
- public Collection<ResolvedCondition> conditions() {
- return ImmutableList.copyOf(conditions);
- }
-
- public boolean isEnabled() {
- return name != null;
- }
-}
+++ /dev/null
-/*
- * 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.batch.qualitygate;
-
-import com.google.common.collect.Lists;
-import com.google.gson.JsonArray;
-import com.google.gson.JsonObject;
-import org.sonar.api.measures.Metric.Level;
-
-import java.util.List;
-
-/**
- * Holds the details of a quality gate evaluation (status per condition)
- *
- * @since 4.4
- */
-class QualityGateDetails {
-
- private static final String FIELD_LEVEL = "level";
-
- private Level level = Level.OK;
-
- private List<EvaluatedCondition> conditions = Lists.newArrayList();
-
- void setLevel(Level level) {
- this.level = level;
- }
-
- void addCondition(ResolvedCondition condition, Level level, Double actualValue) {
- conditions.add(new EvaluatedCondition(condition, level, actualValue));
- }
-
- String toJson() {
- JsonObject details = new JsonObject();
- details.addProperty(FIELD_LEVEL, level.toString());
- JsonArray conditionResults = new JsonArray();
- for (EvaluatedCondition condition: this.conditions) {
- conditionResults.add(condition.toJson());
- }
- details.add("conditions", conditionResults);
- return details.toString();
- }
-
- static class EvaluatedCondition {
-
- private ResolvedCondition condition;
-
- private Level level;
-
- private String actualValue;
-
- EvaluatedCondition(ResolvedCondition condition, Level level, Double actualValue) {
- this.condition = condition;
- this.level = level;
- this.actualValue = actualValue == null ? "" : actualValue.toString();
- }
-
- JsonObject toJson() {
- JsonObject result = new JsonObject();
- result.addProperty("metric", condition.metricKey());
- result.addProperty("op", condition.operator());
- if (condition.period() != null) {
- result.addProperty("period", condition.period());
- }
- if (condition.warningThreshold() != null) {
- result.addProperty("warning", condition.warningThreshold());
- }
- if (condition.errorThreshold() != null) {
- result.addProperty("error", condition.errorThreshold());
- }
- result.addProperty("actual", actualValue);
- result.addProperty(FIELD_LEVEL, level.toString());
- return result;
- }
- }
-}
+++ /dev/null
-/*
- * 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.batch.qualitygate;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonObject;
-import com.google.gson.JsonParser;
-import org.picocontainer.injectors.ProviderAdapter;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.config.Settings;
-import org.sonar.api.measures.MetricFinder;
-import org.sonar.api.utils.MessageException;
-import org.sonar.batch.bootstrap.ServerClient;
-import org.sonar.api.utils.HttpDownloader;
-
-import java.net.HttpURLConnection;
-
-public class QualityGateProvider extends ProviderAdapter {
-
- private static final Logger LOG = LoggerFactory.getLogger(QualityGateProvider.class);
-
- private static final String PROPERTY_QUALITY_GATE = "sonar.qualitygate";
-
- private static final String SHOW_URL = "/api/qualitygates/show";
-
- private static final String ATTRIBUTE_CONDITIONS = "conditions";
-
- private QualityGate instance;
-
- public QualityGate provide(Settings settings, ServerClient client, MetricFinder metricFinder) {
- if (instance == null) {
- instance = init(settings, client, metricFinder, LOG);
- }
- return instance;
- }
-
- @VisibleForTesting
- QualityGate init(Settings settings, ServerClient client, MetricFinder metricFinder, Logger logger) {
- QualityGate result = QualityGate.disabled();
- String qualityGateSetting = settings.getString(PROPERTY_QUALITY_GATE);
- if (qualityGateSetting == null) {
- logger.info("No quality gate is configured.");
- } else {
- result = load(qualityGateSetting, client, metricFinder);
- logger.info("Loaded quality gate '{}'", result.name());
- }
- return result;
- }
-
- private QualityGate load(String qualityGateSetting, ServerClient client, MetricFinder metricFinder) {
- QualityGate configuredGate = null;
- try {
- configuredGate = fetch(qualityGateSetting, client, metricFinder);
- } catch (HttpDownloader.HttpException serverError) {
- if (serverError.getResponseCode() == HttpURLConnection.HTTP_NOT_FOUND) {
- throw MessageException.of("Quality gate '" + qualityGateSetting + "' was not found.");
- } else {
- throw serverError;
- }
- }
-
- return configuredGate;
- }
-
- private QualityGate fetch(String qualityGateSetting, ServerClient client, MetricFinder metricFinder) {
- String jsonText = null;
- try {
- long qGateId = Long.parseLong(qualityGateSetting);
- jsonText = client.request(SHOW_URL + "?id=" + qGateId, false);
- } catch (NumberFormatException configIsNameInsteadOfId) {
- jsonText = client.request(SHOW_URL + "?name=" + qualityGateSetting, false);
- }
-
- JsonParser parser = new JsonParser();
- JsonObject root = parser.parse(jsonText).getAsJsonObject();
-
- QualityGate configuredGate = new QualityGate(root.get("name").getAsString());
-
- if (root.has(ATTRIBUTE_CONDITIONS)) {
- for (JsonElement condition : root.get(ATTRIBUTE_CONDITIONS).getAsJsonArray()) {
- JsonObject conditionObject = condition.getAsJsonObject();
- configuredGate.add(new ResolvedCondition(conditionObject, metricFinder.findByKey(conditionObject.get("metric").getAsString())));
- }
- }
-
- return configuredGate;
- }
-}
+++ /dev/null
-/*
- * 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.batch.qualitygate;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-import java.util.Collection;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-import org.apache.commons.lang.StringUtils;
-import org.sonar.api.batch.Decorator;
-import org.sonar.api.batch.DecoratorBarriers;
-import org.sonar.api.batch.DecoratorContext;
-import org.sonar.api.batch.DependedUpon;
-import org.sonar.api.batch.DependsUpon;
-import org.sonar.api.i18n.I18n;
-import org.sonar.api.measures.CoreMetrics;
-import org.sonar.api.measures.Measure;
-import org.sonar.api.measures.Metric;
-import org.sonar.api.resources.Project;
-import org.sonar.api.resources.Resource;
-import org.sonar.api.resources.ResourceUtils;
-import org.sonar.api.utils.Duration;
-import org.sonar.api.utils.Durations;
-import org.sonar.core.qualitygate.db.QualityGateConditionDto;
-
-public class QualityGateVerifier implements Decorator {
-
- private static final String VARIATION_METRIC_PREFIX = "new_";
- private static final String VARIATION = "variation";
- private static final Map<String, String> OPERATOR_LABELS = ImmutableMap.of(
- QualityGateConditionDto.OPERATOR_EQUALS, "=",
- QualityGateConditionDto.OPERATOR_NOT_EQUALS, "!=",
- QualityGateConditionDto.OPERATOR_GREATER_THAN, ">",
- QualityGateConditionDto.OPERATOR_LESS_THAN, "<");
-
- private QualityGate qualityGate;
-
- private I18n i18n;
- private Durations durations;
-
- public QualityGateVerifier(QualityGate qualityGate, I18n i18n, Durations durations) {
- this.qualityGate = qualityGate;
- this.i18n = i18n;
- this.durations = durations;
- }
-
- @DependedUpon
- public Metric generatesQualityGateStatus() {
- return CoreMetrics.ALERT_STATUS;
- }
-
- @DependsUpon
- public String dependsOnVariations() {
- return DecoratorBarriers.END_OF_TIME_MACHINE;
- }
-
- @DependsUpon
- public Collection<Metric> dependsUponMetrics() {
- Set<Metric> metrics = Sets.newHashSet();
- for (ResolvedCondition condition : qualityGate.conditions()) {
- metrics.add(condition.metric());
- }
- return metrics;
- }
-
- @Override
- public boolean shouldExecuteOnProject(Project project) {
- return qualityGate.isEnabled();
- }
-
- @Override
- public void decorate(Resource resource, DecoratorContext context) {
- if (ResourceUtils.isRootProject(resource)) {
- checkProjectConditions(resource, context);
- }
- }
-
- private void checkProjectConditions(Resource project, DecoratorContext context) {
- Metric.Level globalLevel = Metric.Level.OK;
- QualityGateDetails details = new QualityGateDetails();
- List<String> labels = Lists.newArrayList();
-
- for (ResolvedCondition condition : qualityGate.conditions()) {
- Measure measure = context.getMeasure(condition.metric());
- if (measure != null) {
- Metric.Level level = ConditionUtils.getLevel(condition, measure);
-
- measure.setAlertStatus(level);
- String text = getText(project, condition, level);
- if (!StringUtils.isBlank(text)) {
- measure.setAlertText(text);
- labels.add(text);
- }
-
- context.saveMeasure(measure);
-
- if (Metric.Level.WARN == level && globalLevel != Metric.Level.ERROR) {
- globalLevel = Metric.Level.WARN;
-
- } else if (Metric.Level.ERROR == level) {
- globalLevel = Metric.Level.ERROR;
- }
-
- details.addCondition(condition, level, ConditionUtils.getValue(condition, measure));
- }
- }
-
- Measure globalMeasure = new Measure(CoreMetrics.ALERT_STATUS, globalLevel);
- globalMeasure.setAlertStatus(globalLevel);
- globalMeasure.setAlertText(StringUtils.join(labels, ", "));
- context.saveMeasure(globalMeasure);
-
- details.setLevel(globalLevel);
- Measure detailsMeasure = new Measure(CoreMetrics.QUALITY_GATE_DETAILS, details.toJson());
- context.saveMeasure(detailsMeasure);
-
- }
-
- private String getText(Resource project, ResolvedCondition condition, Metric.Level level) {
- if (level == Metric.Level.OK) {
- return null;
- }
- return getAlertLabel(project, condition, level);
- }
-
- private String getAlertLabel(Resource project, ResolvedCondition condition, Metric.Level level) {
- Integer alertPeriod = condition.period();
- String metric = i18n.message(Locale.ENGLISH, "metric." + condition.metricKey() + ".name", condition.metric().getName());
-
- StringBuilder stringBuilder = new StringBuilder();
- stringBuilder.append(metric);
-
- if (alertPeriod != null && !condition.metricKey().startsWith(VARIATION_METRIC_PREFIX)) {
- String variation = i18n.message(Locale.ENGLISH, VARIATION, VARIATION).toLowerCase();
- stringBuilder.append(" ").append(variation);
- }
-
- stringBuilder
- .append(" ").append(operatorLabel(condition.operator())).append(" ")
- .append(alertValue(condition, level));
-
- // TODO Disabled because snapshot is no more created by the batch, but should be reactivated when the decorator will be moved to the batch
- // if (alertPeriod != null) {
- // Snapshot snapshot = resourceCache.get(project).snapshot();
- // stringBuilder.append(" ").append(periods.label(snapshot, alertPeriod));
- // }
-
- return stringBuilder.toString();
- }
-
- private String alertValue(ResolvedCondition condition, Metric.Level level) {
- String value = level.equals(Metric.Level.ERROR) ? condition.errorThreshold() : condition.warningThreshold();
- if (condition.metric().getType().equals(Metric.ValueType.WORK_DUR)) {
- return formatDuration(value);
- } else {
- return value;
- }
- }
-
- private String formatDuration(String value) {
- return durations.format(Locale.ENGLISH, Duration.create(Long.parseLong(value)), Durations.DurationFormat.SHORT);
- }
-
- private String operatorLabel(String operator) {
- return OPERATOR_LABELS.get(operator);
- }
-
- @Override
- public String toString() {
- return getClass().getSimpleName();
- }
-}
+++ /dev/null
-/*
- * 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.batch.qualitygate;
-
-import javax.annotation.CheckForNull;
-
-import com.google.gson.JsonObject;
-import org.sonar.api.measures.Metric;
-
-public class ResolvedCondition {
-
- private static final String ATTRIBUTE_PERIOD = "period";
-
- private static final String ATTRIBUTE_ERROR = "error";
-
- private static final String ATTRIBUTE_WARNING = "warning";
-
- private JsonObject json;
-
- private Metric metric;
-
- public ResolvedCondition(JsonObject jsonObject, Metric metric) {
- this.json = jsonObject;
- this.metric = metric;
- }
-
- public Long id() {
- return json.get("id").getAsLong();
- }
-
- public String metricKey() {
- return json.get("metric").getAsString();
- }
-
- public Metric metric() {
- return metric;
- }
-
- public String operator() {
- return json.get("op").getAsString();
- }
-
- @CheckForNull
- public String warningThreshold() {
- return json.has(ATTRIBUTE_WARNING) ? json.get(ATTRIBUTE_WARNING).getAsString() : null;
- }
-
- @CheckForNull
- public String errorThreshold() {
- return json.has(ATTRIBUTE_ERROR) ? json.get(ATTRIBUTE_ERROR).getAsString() : null;
- }
-
- @CheckForNull
- public Integer period() {
- return json.has(ATTRIBUTE_PERIOD) ? json.get(ATTRIBUTE_PERIOD).getAsInt() : null;
- }
-}
+++ /dev/null
-/*
- * 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.batch.qualitygate;
-
-import javax.annotation.ParametersAreNonnullByDefault;
import org.sonar.batch.mediumtest.ScanTaskObservers;
import org.sonar.batch.phases.PhasesTimeProfiler;
import org.sonar.batch.profiling.PhasesSumUpTimeProfiler;
-import org.sonar.batch.qualitygate.QualityGateProvider;
import org.sonar.batch.report.ComponentsPublisher;
import org.sonar.batch.report.CoveragePublisher;
import org.sonar.batch.report.DuplicationsPublisher;
// Duplications
DuplicationCache.class,
- // Quality Gate
- new QualityGateProvider(),
-
ProjectSettings.class,
// Report
+++ /dev/null
-/*
- * 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.batch.qualitygate;
-
-import org.apache.commons.lang.NotImplementedException;
-import org.junit.Before;
-import org.junit.Test;
-import org.sonar.api.measures.Measure;
-import org.sonar.api.measures.Metric;
-import org.sonar.core.qualitygate.db.QualityGateConditionDto;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class ConditionUtilsTest {
-
- private Metric metric;
- private Measure measure;
- private ResolvedCondition condition;
-
- @Before
- public void setup() {
- metric = new Metric.Builder("test-metric", "name", Metric.ValueType.FLOAT).create();
- measure = new Measure();
- measure.setMetric(metric);
- condition = mock(ResolvedCondition.class);
- when(condition.period()).thenReturn(null);
- }
-
- @Test
- public void testInputNumbers() {
- metric.setType(Metric.ValueType.FLOAT);
- measure.setValue(10.2d);
- when(condition.operator()).thenReturn(QualityGateConditionDto.OPERATOR_LESS_THAN);
- when(condition.metric()).thenReturn(metric);
-
- try {
- metric.setType(Metric.ValueType.FLOAT);
- when(condition.errorThreshold()).thenReturn("20");
- ConditionUtils.getLevel(condition, measure);
- } catch (NumberFormatException ex) {
- fail();
- }
-
- try {
- metric.setType(Metric.ValueType.INT);
- when(condition.errorThreshold()).thenReturn("20.1");
- ConditionUtils.getLevel(condition, measure);
- } catch (NumberFormatException ex) {
- fail();
- }
-
- try {
- metric.setType(Metric.ValueType.PERCENT);
- when(condition.errorThreshold()).thenReturn("20.1");
- ConditionUtils.getLevel(condition, measure);
- } catch (NumberFormatException ex) {
- fail();
- }
- }
-
- @Test
- public void testEquals() {
-
- metric.setType(Metric.ValueType.FLOAT);
- measure.setValue(10.2d);
- when(condition.operator()).thenReturn(QualityGateConditionDto.OPERATOR_EQUALS);
- when(condition.metric()).thenReturn(metric);
-
- when(condition.errorThreshold()).thenReturn("10.2");
- assertThat(ConditionUtils.getLevel(condition, measure)).isEqualTo(Metric.Level.ERROR);
-
- when(condition.errorThreshold()).thenReturn("10.1");
- assertThat(ConditionUtils.getLevel(condition, measure)).isEqualTo(Metric.Level.OK);
-
- metric.setType(Metric.ValueType.STRING);
- measure.setData("TEST");
- measure.setValue(null);
-
- when(condition.errorThreshold()).thenReturn("TEST");
- assertThat(ConditionUtils.getLevel(condition, measure)).isEqualTo(Metric.Level.ERROR);
-
- when(condition.errorThreshold()).thenReturn("TEST2");
- assertThat(ConditionUtils.getLevel(condition, measure)).isEqualTo(Metric.Level.OK);
-
- }
-
- @Test
- public void testNotEquals() {
-
- metric.setType(Metric.ValueType.FLOAT);
- measure.setValue(10.2d);
- when(condition.operator()).thenReturn(QualityGateConditionDto.OPERATOR_NOT_EQUALS);
- when(condition.metric()).thenReturn(metric);
-
- when(condition.errorThreshold()).thenReturn("10.2");
- assertThat(ConditionUtils.getLevel(condition, measure)).isEqualTo(Metric.Level.OK);
-
- when(condition.errorThreshold()).thenReturn("10.1");
- assertThat(ConditionUtils.getLevel(condition, measure)).isEqualTo(Metric.Level.ERROR);
-
- metric.setType(Metric.ValueType.STRING);
- measure.setData("TEST");
- measure.setValue(null);
-
- when(condition.errorThreshold()).thenReturn("TEST");
- assertThat(ConditionUtils.getLevel(condition, measure)).isEqualTo(Metric.Level.OK);
-
- when(condition.errorThreshold()).thenReturn("TEST2");
- assertThat(ConditionUtils.getLevel(condition, measure)).isEqualTo(Metric.Level.ERROR);
-
- }
-
- @Test
- public void testGreater() {
- metric.setType(Metric.ValueType.FLOAT);
- measure.setValue(10.2d);
- when(condition.operator()).thenReturn(QualityGateConditionDto.OPERATOR_GREATER_THAN);
- when(condition.metric()).thenReturn(metric);
-
- when(condition.errorThreshold()).thenReturn("10.1");
- assertThat(ConditionUtils.getLevel(condition, measure)).isEqualTo(Metric.Level.ERROR);
-
- when(condition.errorThreshold()).thenReturn("10.2");
- assertThat(ConditionUtils.getLevel(condition, measure)).isEqualTo(Metric.Level.OK);
-
- when(condition.errorThreshold()).thenReturn("10.3");
- assertThat(ConditionUtils.getLevel(condition, measure)).isEqualTo(Metric.Level.OK);
- }
-
- @Test
- public void testSmaller() {
- metric.setType(Metric.ValueType.FLOAT);
- measure.setValue(10.2d);
- when(condition.operator()).thenReturn(QualityGateConditionDto.OPERATOR_LESS_THAN);
- when(condition.metric()).thenReturn(metric);
-
- when(condition.errorThreshold()).thenReturn("10.1");
- assertThat(ConditionUtils.getLevel(condition, measure)).isEqualTo(Metric.Level.OK);
-
- when(condition.errorThreshold()).thenReturn("10.2");
- assertThat(ConditionUtils.getLevel(condition, measure)).isEqualTo(Metric.Level.OK);
-
- when(condition.errorThreshold()).thenReturn("10.3");
- assertThat(ConditionUtils.getLevel(condition, measure)).isEqualTo(Metric.Level.ERROR);
- }
-
- @Test
- public void testPercent() {
- metric.setType(Metric.ValueType.PERCENT);
- measure.setValue(10.2d);
- when(condition.operator()).thenReturn(QualityGateConditionDto.OPERATOR_EQUALS);
- when(condition.metric()).thenReturn(metric);
-
- when(condition.errorThreshold()).thenReturn("10.2");
- assertThat(ConditionUtils.getLevel(condition, measure)).isEqualTo(Metric.Level.ERROR);
- }
-
- @Test
- public void testFloat() {
- metric.setType(Metric.ValueType.FLOAT);
- measure.setValue(10.2d);
- when(condition.operator()).thenReturn(QualityGateConditionDto.OPERATOR_EQUALS);
- when(condition.metric()).thenReturn(metric);
-
- when(condition.errorThreshold()).thenReturn("10.2");
- assertThat(ConditionUtils.getLevel(condition, measure)).isEqualTo(Metric.Level.ERROR);
- }
-
- @Test
- public void testInteger() {
- metric.setType(Metric.ValueType.INT);
- measure.setValue(10.2d);
- when(condition.operator()).thenReturn(QualityGateConditionDto.OPERATOR_EQUALS);
- when(condition.metric()).thenReturn(metric);
-
- when(condition.errorThreshold()).thenReturn("10");
- assertThat(ConditionUtils.getLevel(condition, measure)).isEqualTo(Metric.Level.ERROR);
-
- when(condition.errorThreshold()).thenReturn("10.2");
- assertThat(ConditionUtils.getLevel(condition, measure)).isEqualTo(Metric.Level.ERROR);
- }
-
- @Test
- public void testLevel() {
- metric.setType(Metric.ValueType.LEVEL);
- measure.setData(Metric.Level.ERROR.toString());
- when(condition.operator()).thenReturn(QualityGateConditionDto.OPERATOR_EQUALS);
- when(condition.metric()).thenReturn(metric);
-
- when(condition.errorThreshold()).thenReturn(Metric.Level.ERROR.toString());
- assertThat(ConditionUtils.getLevel(condition, measure)).isEqualTo(Metric.Level.ERROR);
-
- when(condition.errorThreshold()).thenReturn(Metric.Level.OK.toString());
- assertThat(ConditionUtils.getLevel(condition, measure)).isEqualTo(Metric.Level.OK);
-
- when(condition.operator()).thenReturn(QualityGateConditionDto.OPERATOR_NOT_EQUALS);
- assertThat(ConditionUtils.getLevel(condition, measure)).isEqualTo(Metric.Level.ERROR);
- }
-
- @Test
- public void testBooleans() {
- metric.setType(Metric.ValueType.BOOL);
- measure.setValue(0d);
- when(condition.operator()).thenReturn(QualityGateConditionDto.OPERATOR_EQUALS);
- when(condition.metric()).thenReturn(metric);
-
- when(condition.errorThreshold()).thenReturn("1");
- assertThat(ConditionUtils.getLevel(condition, measure)).isEqualTo(Metric.Level.OK);
-
- when(condition.errorThreshold()).thenReturn("0");
- assertThat(ConditionUtils.getLevel(condition, measure)).isEqualTo(Metric.Level.ERROR);
-
- when(condition.operator()).thenReturn(QualityGateConditionDto.OPERATOR_NOT_EQUALS);
- when(condition.errorThreshold()).thenReturn("1");
- assertThat(ConditionUtils.getLevel(condition, measure)).isEqualTo(Metric.Level.ERROR);
-
- when(condition.errorThreshold()).thenReturn("0");
- assertThat(ConditionUtils.getLevel(condition, measure)).isEqualTo(Metric.Level.OK);
-
- when(condition.errorThreshold()).thenReturn("polop");
- try {
- ConditionUtils.getLevel(condition, measure);
- fail();
- } catch(Exception expected) {
- assertThat(expected).isInstanceOf(IllegalArgumentException.class).hasMessage("Quality Gate: Unable to parse value 'polop' to compare against name");
- }
- }
-
- @Test
- public void test_work_duration() {
- metric.setType(Metric.ValueType.WORK_DUR);
- measure.setValue(60.0d);
- when(condition.operator()).thenReturn(QualityGateConditionDto.OPERATOR_EQUALS);
- when(condition.metric()).thenReturn(metric);
-
- when(condition.errorThreshold()).thenReturn("60");
- assertThat(ConditionUtils.getLevel(condition, measure)).isEqualTo(Metric.Level.ERROR);
-
- when(condition.errorThreshold()).thenReturn("polop");
- try {
- ConditionUtils.getLevel(condition, measure);
- fail();
- } catch(Exception expected) {
- assertThat(expected).isInstanceOf(IllegalArgumentException.class).hasMessage("Quality Gate: Unable to parse value 'polop' to compare against name");
- }
- }
-
- @Test
- public void testErrorAndWarningLevel() {
- metric.setType(Metric.ValueType.FLOAT);
- measure.setValue(10.2d);
- when(condition.operator()).thenReturn(QualityGateConditionDto.OPERATOR_EQUALS);
- when(condition.metric()).thenReturn(metric);
-
- when(condition.errorThreshold()).thenReturn("10.2");
- assertThat(ConditionUtils.getLevel(condition, measure)).isEqualTo(Metric.Level.ERROR);
-
- when(condition.errorThreshold()).thenReturn("10.1");
- assertThat(ConditionUtils.getLevel(condition, measure)).isEqualTo(Metric.Level.OK);
-
- when(condition.errorThreshold()).thenReturn("10.3");
- when(condition.warningThreshold()).thenReturn("10.2");
- assertThat(ConditionUtils.getLevel(condition, measure)).isEqualTo(Metric.Level.WARN);
- }
-
- @Test
- public void testUnsupportedType() {
- metric.setType(Metric.ValueType.DATA);
- measure.setValue(3.14159265358);
- when(condition.operator()).thenReturn(QualityGateConditionDto.OPERATOR_EQUALS);
- when(condition.metric()).thenReturn(metric);
-
- when(condition.errorThreshold()).thenReturn("1.60217657");
- try {
- ConditionUtils.getLevel(condition, measure);
- fail();
- } catch (Exception expected) {
- assertThat(expected).isInstanceOf(NotImplementedException.class);
- }
- }
-
-}
+++ /dev/null
-/*
- * 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.batch.qualitygate;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-import org.slf4j.Logger;
-import org.sonar.api.config.Settings;
-import org.sonar.api.measures.MetricFinder;
-import org.sonar.api.utils.HttpDownloader;
-import org.sonar.api.utils.MessageException;
-import org.sonar.batch.bootstrap.ServerClient;
-
-import java.net.HttpURLConnection;
-import java.net.URI;
-import java.util.Iterator;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-@RunWith(MockitoJUnitRunner.class)
-public class QualityGateProviderTest {
-
- @Mock
- private Settings settings;
-
- @Mock
- private ServerClient client;
-
- @Mock
- private MetricFinder metricFinder;
-
- @Mock
- private Logger logger;
-
- @Test
- public void should_load_empty_quality_gate_from_default_settings() {
- QualityGateProvider provider = new QualityGateProvider();
- assertThat(provider.provide(settings, client, metricFinder).conditions()).isEmpty();
- assertThat(provider.init(settings, client, metricFinder, logger).isEnabled()).isFalse();
- verify(logger, times(1)).info("No quality gate is configured.");
- verify(settings, times(2)).getString("sonar.qualitygate");
- }
-
- @Test
- public void should_load_empty_quality_gate_using_name() {
- String qGateName = "Sonar way";
- when(settings.getString("sonar.qualitygate")).thenReturn(qGateName);
- when(client.request("/api/qualitygates/show?name=Sonar way", false)).thenReturn("{'id':12345,'name':'Sonar way'}");
- QualityGate qGate = new QualityGateProvider().init(settings, client, metricFinder, logger);
- assertThat(qGate.name()).isEqualTo(qGateName);
- assertThat(qGate.isEnabled()).isTrue();
- assertThat(qGate.conditions()).isEmpty();
- verify(logger).info("Loaded quality gate '{}'", qGateName);
- }
-
- @Test
- public void should_load_quality_gate_using_id() {
- long qGateId = 12345L;
- String qGateName = "Sonar way";
- when(settings.getString("sonar.qualitygate")).thenReturn(Long.toString(qGateId));
- when(client.request("/api/qualitygates/show?id=12345", false)).thenReturn("{'id':12345,'name':'Sonar way','conditions':["
- + "{'id':1,'metric':'metric1','op':'EQ','warning':'POLOP'},"
- + "{'id':2,'metric':'metric2','op':'NE','error':'PALAP','period':3}"
- + "]}");
-
- QualityGate qGate = new QualityGateProvider().init(settings, client, metricFinder, logger);
-
- assertThat(qGate.name()).isEqualTo(qGateName);
- assertThat(qGate.conditions()).hasSize(2);
- Iterator<ResolvedCondition> conditions = qGate.conditions().iterator();
- ResolvedCondition cond1 = conditions.next();
- assertThat(cond1.warningThreshold()).isEqualTo("POLOP");
- assertThat(cond1.errorThreshold()).isNull();
- assertThat(cond1.period()).isNull();
- ResolvedCondition cond2 = conditions.next();
- assertThat(cond2.warningThreshold()).isNull();
- assertThat(cond2.errorThreshold()).isEqualTo("PALAP");
- assertThat(cond2.period()).isEqualTo(3);
-
- verify(logger).info("Loaded quality gate '{}'", qGateName);
- verify(metricFinder).findByKey("metric1");
- verify(metricFinder).findByKey("metric2");
- }
-
- @Test(expected = MessageException.class)
- public void should_stop_analysis_if_gate_not_found() {
- String qGateName = "Sonar way";
- when(settings.getString("sonar.qualitygate")).thenReturn(qGateName);
- when(client.request("/api/qualitygates/show?name=Sonar way", false)).thenThrow(
- new HttpDownloader.HttpException(URI.create("/api/qualitygates/show?name=Sonar%20way"), HttpURLConnection.HTTP_NOT_FOUND));
- new QualityGateProvider().provide(settings, client, metricFinder);
- }
-
- @Test(expected = HttpDownloader.HttpException.class)
- public void should_stop_analysis_if_server_error() {
- String qGateName = "Sonar way";
- when(settings.getString("sonar.qualitygate")).thenReturn(qGateName);
- when(client.request("/api/qualitygates/show?name=Sonar way", false)).thenThrow(
- new HttpDownloader.HttpException(URI.create("/api/qualitygates/show?name=Sonar%20way"), HttpURLConnection.HTTP_NOT_ACCEPTABLE));
- new QualityGateProvider().provide(settings, client, metricFinder);
- }
-
-}
+++ /dev/null
-/*
- * 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.batch.qualitygate;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-import java.util.ArrayList;
-import java.util.Locale;
-import org.apache.commons.lang.NotImplementedException;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.mockito.ArgumentMatcher;
-import org.sonar.api.batch.DecoratorBarriers;
-import org.sonar.api.batch.DecoratorContext;
-import org.sonar.api.database.model.Snapshot;
-import org.sonar.api.i18n.I18n;
-import org.sonar.api.measures.CoreMetrics;
-import org.sonar.api.measures.Measure;
-import org.sonar.api.measures.Metric;
-import org.sonar.api.measures.Metric.Level;
-import org.sonar.api.resources.File;
-import org.sonar.api.resources.Project;
-import org.sonar.api.resources.Resource;
-import org.sonar.api.test.IsMeasure;
-import org.sonar.api.utils.Duration;
-import org.sonar.api.utils.Durations;
-import org.sonar.core.qualitygate.db.QualityGateConditionDto;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.argThat;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-public class QualityGateVerifierTest {
-
- QualityGateVerifier verifier;
- DecoratorContext context;
- QualityGate qualityGate;
-
- Measure measureClasses;
- Measure measureCoverage;
- Measure measureComplexity;
- Resource project;
- Snapshot snapshot;
- I18n i18n;
- Durations durations;
-
- @Before
- public void before() {
- context = mock(DecoratorContext.class);
- i18n = mock(I18n.class);
- when(i18n.message(any(Locale.class), eq("variation"), eq("variation"))).thenReturn("variation");
- durations = mock(Durations.class);
-
- measureClasses = new Measure(CoreMetrics.CLASSES, 20d);
- measureCoverage = new Measure(CoreMetrics.COVERAGE, 35d);
- measureComplexity = new Measure(CoreMetrics.COMPLEXITY, 50d);
-
- when(context.getMeasure(CoreMetrics.CLASSES)).thenReturn(measureClasses);
- when(context.getMeasure(CoreMetrics.COVERAGE)).thenReturn(measureCoverage);
- when(context.getMeasure(CoreMetrics.COMPLEXITY)).thenReturn(measureComplexity);
-
- snapshot = mock(Snapshot.class);
- qualityGate = mock(QualityGate.class);
- when(qualityGate.isEnabled()).thenReturn(true);
-
- project = new Project("foo");
-
- verifier = new QualityGateVerifier(qualityGate, i18n, durations);
- }
-
- @Test
- public void should_be_executed_if_quality_gate_is_enabled() {
- assertThat(verifier.shouldExecuteOnProject((Project) project)).isTrue();
- when(qualityGate.isEnabled()).thenReturn(false);
- assertThat(verifier.shouldExecuteOnProject((Project) project)).isFalse();
- }
-
- @Test
- public void test_toString() {
- assertThat(verifier.toString()).isEqualTo("QualityGateVerifier");
- }
-
- @Test
- public void generates_quality_gates_status() {
- assertThat(verifier.generatesQualityGateStatus()).isEqualTo(CoreMetrics.ALERT_STATUS);
- }
-
- @Test
- public void depends_on_variations() {
- assertThat(verifier.dependsOnVariations()).isEqualTo(DecoratorBarriers.END_OF_TIME_MACHINE);
- }
-
- @Test
- public void depends_upon_metrics() {
- when(qualityGate.conditions()).thenReturn(ImmutableList.of(new ResolvedCondition(null, CoreMetrics.CLASSES)));
- assertThat(verifier.dependsUponMetrics()).containsOnly(CoreMetrics.CLASSES);
- }
-
- @Test
- public void ok_when_no_alerts() {
- ArrayList<ResolvedCondition> conditions = Lists.newArrayList(
- mockCondition(CoreMetrics.CLASSES, QualityGateConditionDto.OPERATOR_GREATER_THAN, null, "20"),
- mockCondition(CoreMetrics.COVERAGE, QualityGateConditionDto.OPERATOR_GREATER_THAN, null, "35.0"));
- when(qualityGate.conditions()).thenReturn(conditions);
-
- verifier.decorate(project, context);
-
- verify(context).saveMeasure(argThat(hasLevel(measureClasses, Metric.Level.OK)));
- verify(context).saveMeasure(argThat(hasLevel(measureCoverage, Metric.Level.OK)));
- verify(context).saveMeasure(argThat(new IsMeasure(CoreMetrics.ALERT_STATUS, Metric.Level.OK.toString())));
- verify(context).saveMeasure(argThat(new IsMeasure(CoreMetrics.QUALITY_GATE_DETAILS, "{\"level\":\"OK\","
- + "\"conditions\":"
- + "["
- + "{\"metric\":\"classes\",\"op\":\"GT\",\"warning\":\"20\",\"actual\":\"20.0\",\"level\":\"OK\"},"
- + "{\"metric\":\"coverage\",\"op\":\"GT\",\"warning\":\"35.0\",\"actual\":\"35.0\",\"level\":\"OK\"}"
- + "]"
- + "}")));
- }
-
- @Test
- public void check_root_modules_only() {
- ArrayList<ResolvedCondition> conditions = Lists.newArrayList(
- mockCondition(CoreMetrics.CLASSES, QualityGateConditionDto.OPERATOR_GREATER_THAN, null, "20"),
- mockCondition(CoreMetrics.COVERAGE, QualityGateConditionDto.OPERATOR_GREATER_THAN, null, "35.0"));
- when(qualityGate.conditions()).thenReturn(conditions);
-
- verifier.decorate(File.create("src/Foo.php"), context);
-
- verify(context, never()).saveMeasure(any(Measure.class));
- }
-
- @Test
- public void generate_warnings() {
- ArrayList<ResolvedCondition> conditions = Lists.newArrayList(
- mockCondition(CoreMetrics.CLASSES, QualityGateConditionDto.OPERATOR_GREATER_THAN, null, "100"),
- mockCondition(CoreMetrics.COVERAGE, QualityGateConditionDto.OPERATOR_LESS_THAN, null, "95.0")); // generates warning because coverage
- // 35% < 95%
- when(qualityGate.conditions()).thenReturn(conditions);
-
- verifier.decorate(project, context);
-
- verify(context).saveMeasure(argThat(matchesMetric(CoreMetrics.ALERT_STATUS, Metric.Level.WARN, null)));
-
- verify(context).saveMeasure(argThat(hasLevel(measureClasses, Metric.Level.OK)));
- verify(context).saveMeasure(argThat(hasLevel(measureCoverage, Metric.Level.WARN)));
-
- }
-
- @Test
- public void globalStatusShouldBeErrorIfWarningsAndErrors() {
- ArrayList<ResolvedCondition> conditions = Lists.newArrayList(
- mockCondition(CoreMetrics.CLASSES, QualityGateConditionDto.OPERATOR_LESS_THAN, null, "100"), // generates warning because classes 20 <
- // 100
- mockCondition(CoreMetrics.COVERAGE, QualityGateConditionDto.OPERATOR_LESS_THAN, "50.0", "80.0")); // generates error because coverage
- // 35% < 50%
- when(qualityGate.conditions()).thenReturn(conditions);
-
- verifier.decorate(project, context);
-
- verify(context).saveMeasure(argThat(matchesMetric(CoreMetrics.ALERT_STATUS, Metric.Level.ERROR, null)));
-
- verify(context).saveMeasure(argThat(hasLevel(measureClasses, Metric.Level.WARN)));
- verify(context).saveMeasure(argThat(hasLevel(measureCoverage, Metric.Level.ERROR)));
- }
-
- @Test
- public void globalLabelShouldAggregateAllLabels() {
- when(i18n.message(any(Locale.class), eq("metric.classes.name"), anyString())).thenReturn("Classes");
- when(i18n.message(any(Locale.class), eq("metric.coverage.name"), anyString())).thenReturn("Coverages");
- ArrayList<ResolvedCondition> conditions = Lists.newArrayList(
- mockCondition(CoreMetrics.CLASSES, QualityGateConditionDto.OPERATOR_LESS_THAN, null, "10000"), // there are 20 classes, error
- // threshold is higher => alert
- mockCondition(CoreMetrics.COVERAGE, QualityGateConditionDto.OPERATOR_LESS_THAN, "50.0", "80.0"));// coverage is 35%, warning threshold
- // is higher => alert
- when(qualityGate.conditions()).thenReturn(conditions);
-
- verifier.decorate(project, context);
-
- verify(context).saveMeasure(argThat(matchesMetric(CoreMetrics.ALERT_STATUS, Metric.Level.ERROR, "Classes < 10000, Coverages < 50.0")));
- }
-
- @Test
- public void alertLabelUsesL10nMetricName() {
- Metric metric = new Metric.Builder("rating", "Rating", Metric.ValueType.INT).create();
-
- // metric name is declared in l10n bundle
- when(i18n.message(any(Locale.class), eq("metric.rating.name"), anyString())).thenReturn("THE RATING");
-
- when(context.getMeasure(metric)).thenReturn(new Measure(metric, 4d));
- ArrayList<ResolvedCondition> conditions = Lists.newArrayList(mockCondition(metric, QualityGateConditionDto.OPERATOR_LESS_THAN, "10", null));
- when(qualityGate.conditions()).thenReturn(conditions);
- verifier.decorate(project, context);
-
- verify(context).saveMeasure(argThat(matchesMetric(CoreMetrics.ALERT_STATUS, Metric.Level.ERROR, "THE RATING < 10")));
- }
-
- @Test
- public void alertLabelUsesMetricNameIfMissingL10nBundle() {
- // the third argument is Metric#getName()
- when(i18n.message(any(Locale.class), eq("metric.classes.name"), eq("Classes"))).thenReturn("Classes");
- ArrayList<ResolvedCondition> conditions = Lists.newArrayList(
- // there are 20 classes, error threshold is higher => alert
- mockCondition(CoreMetrics.CLASSES, QualityGateConditionDto.OPERATOR_LESS_THAN, "10000", null)
- );
- when(qualityGate.conditions()).thenReturn(conditions);
-
- verifier.decorate(project, context);
-
- verify(context).saveMeasure(argThat(matchesMetric(CoreMetrics.ALERT_STATUS, Metric.Level.ERROR, "Classes < 10000")));
- }
-
- @Test
- public void shouldBeOkIfPeriodVariationIsEnough() {
- measureClasses.setVariation1(0d);
- measureCoverage.setVariation2(50d);
- measureComplexity.setVariation3(2d);
-
- ArrayList<ResolvedCondition> conditions = Lists.newArrayList(
- mockCondition(CoreMetrics.CLASSES, QualityGateConditionDto.OPERATOR_GREATER_THAN, null, "10", 1), // ok because no variation
- mockCondition(CoreMetrics.COVERAGE, QualityGateConditionDto.OPERATOR_LESS_THAN, null, "40.0", 2), // ok because coverage increases of
- // 50%, which is more
- // than 40%
- mockCondition(CoreMetrics.COMPLEXITY, QualityGateConditionDto.OPERATOR_GREATER_THAN, null, "5", 3) // ok because complexity increases
- // of 2, which is less
- // than 5
- );
- when(qualityGate.conditions()).thenReturn(conditions);
-
- verifier.decorate(project, context);
-
- verify(context).saveMeasure(argThat(matchesMetric(CoreMetrics.ALERT_STATUS, Metric.Level.OK, null)));
-
- verify(context).saveMeasure(argThat(hasLevel(measureClasses, Metric.Level.OK)));
- verify(context).saveMeasure(argThat(hasLevel(measureCoverage, Metric.Level.OK)));
- verify(context).saveMeasure(argThat(hasLevel(measureComplexity, Metric.Level.OK)));
- }
-
- @Test
- public void shouldGenerateWarningIfPeriodVariationIsNotEnough() {
- measureClasses.setVariation1(40d);
- measureCoverage.setVariation2(5d);
- measureComplexity.setVariation3(70d);
-
- ArrayList<ResolvedCondition> conditions = Lists.newArrayList(
- mockCondition(CoreMetrics.CLASSES, QualityGateConditionDto.OPERATOR_GREATER_THAN, null, "30", 1), // generates warning because classes
- // increases of 40,
- // which is greater than 30
- mockCondition(CoreMetrics.COVERAGE, QualityGateConditionDto.OPERATOR_LESS_THAN, null, "10.0", 2), // generates warning because
- // coverage increases of 5%,
- // which is smaller than 10%
- mockCondition(CoreMetrics.COMPLEXITY, QualityGateConditionDto.OPERATOR_GREATER_THAN, null, "60", 3) // generates warning because
- // complexity increases of
- // 70, which is smaller than 60
- );
- when(qualityGate.conditions()).thenReturn(conditions);
-
- verifier.decorate(project, context);
-
- verify(context).saveMeasure(argThat(matchesMetric(CoreMetrics.ALERT_STATUS, Metric.Level.WARN, null)));
-
- verify(context).saveMeasure(argThat(hasLevel(measureClasses, Metric.Level.WARN)));
- verify(context).saveMeasure(argThat(hasLevel(measureCoverage, Metric.Level.WARN)));
- verify(context).saveMeasure(argThat(hasLevel(measureComplexity, Metric.Level.WARN)));
- }
-
- @Test
- public void shouldBeOkIfVariationIsNull() {
- measureClasses.setVariation1(null);
-
- ArrayList<ResolvedCondition> conditions = Lists.newArrayList(
- mockCondition(CoreMetrics.CLASSES, QualityGateConditionDto.OPERATOR_GREATER_THAN, null, "10", 1));
- when(qualityGate.conditions()).thenReturn(conditions);
-
- verifier.decorate(project, context);
-
- verify(context).saveMeasure(argThat(matchesMetric(CoreMetrics.ALERT_STATUS, Metric.Level.OK, null)));
- verify(context).saveMeasure(argThat(hasLevel(measureClasses, Metric.Level.OK)));
- }
-
- @Test
- public void shouldVariationPeriodValueCouldBeUsedForRatingMetric() {
- Metric ratingMetric = new Metric.Builder("key_rating_metric", "Rating metric", Metric.ValueType.RATING).create();
- Measure measureRatingMetric = new Measure(ratingMetric, 150d);
- measureRatingMetric.setVariation1(50d);
- when(context.getMeasure(ratingMetric)).thenReturn(measureRatingMetric);
-
- ArrayList<ResolvedCondition> conditions = Lists.newArrayList(
- mockCondition(ratingMetric, QualityGateConditionDto.OPERATOR_GREATER_THAN, null, "100", 1)
- );
- when(qualityGate.conditions()).thenReturn(conditions);
-
- verifier.decorate(project, context);
-
- verify(context).saveMeasure(argThat(matchesMetric(CoreMetrics.ALERT_STATUS, Metric.Level.OK, null)));
- verify(context).saveMeasure(argThat(hasLevel(measureRatingMetric, Metric.Level.OK)));
- }
-
- @Test
- public void shouldAllowVariationPeriodOnAllPeriods() {
- measureClasses.setVariation4(40d);
-
- ArrayList<ResolvedCondition> conditions = Lists.newArrayList(
- mockCondition(CoreMetrics.CLASSES, QualityGateConditionDto.OPERATOR_GREATER_THAN, null, "30", 4)
- );
- when(qualityGate.conditions()).thenReturn(conditions);
-
- verifier.decorate(project, context);
-
- verify(context).saveMeasure(argThat(matchesMetric(CoreMetrics.ALERT_STATUS, Metric.Level.WARN, null)));
- verify(context).saveMeasure(argThat(hasLevel(measureClasses, Metric.Level.WARN)));
- }
-
- @Test(expected = NotImplementedException.class)
- public void shouldNotAllowPeriodVariationAlertOnStringMetric() {
- Measure measure = new Measure(CoreMetrics.NCLOC_LANGUAGE_DISTRIBUTION, 100d);
- measure.setVariation1(50d);
- when(context.getMeasure(CoreMetrics.NCLOC_LANGUAGE_DISTRIBUTION)).thenReturn(measure);
-
- ArrayList<ResolvedCondition> conditions = Lists.newArrayList(
- mockCondition(CoreMetrics.NCLOC_LANGUAGE_DISTRIBUTION, QualityGateConditionDto.OPERATOR_GREATER_THAN, null, "30", 1)
- );
- when(qualityGate.conditions()).thenReturn(conditions);
-
- verifier.decorate(project, context);
- }
-
- @Test
- @Ignore("Disabled because snapshot is no more created by the batch")
- public void shouldLabelAlertContainsPeriod() {
- measureClasses.setVariation1(40d);
-
- when(i18n.message(any(Locale.class), eq("metric.classes.name"), anyString())).thenReturn("Classes");
- // when(periods.label(snapshot, 1)).thenReturn("since someday");
-
- ArrayList<ResolvedCondition> conditions = Lists.newArrayList(
- mockCondition(CoreMetrics.CLASSES, QualityGateConditionDto.OPERATOR_GREATER_THAN, null, "30", 1) // generates warning because classes
- // increases of 40,
- // which is greater than 30
- );
- when(qualityGate.conditions()).thenReturn(conditions);
-
- verifier.decorate(project, context);
-
- verify(context).saveMeasure(argThat(matchesMetric(CoreMetrics.ALERT_STATUS, Metric.Level.WARN, "Classes variation > 30 since someday")));
- }
-
- @Test
- @Ignore("Disabled because snapshot is no more created by the batch")
- public void shouldLabelAlertForNewMetricDoNotContainsVariationWord() {
- Metric newMetric = new Metric.Builder("new_metric_key", "New Metric", Metric.ValueType.INT).create();
- Measure measure = new Measure(newMetric, 15d);
- measure.setVariation1(50d);
- when(context.getMeasure(newMetric)).thenReturn(measure);
- measureClasses.setVariation1(40d);
-
- when(i18n.message(any(Locale.class), eq("metric.new_metric_key.name"), anyString())).thenReturn("New Measure");
- // when(periods.label(snapshot, 1)).thenReturn("since someday");
-
- ArrayList<ResolvedCondition> conditions = Lists.newArrayList(
- mockCondition(newMetric, QualityGateConditionDto.OPERATOR_GREATER_THAN, null, "30", 1) // generates warning because classes increases
- // of 40, which is
- // greater than 30
- );
- when(qualityGate.conditions()).thenReturn(conditions);
-
- verifier.decorate(project, context);
-
- verify(context).saveMeasure(argThat(matchesMetric(CoreMetrics.ALERT_STATUS, Metric.Level.WARN, "New Measure > 30 since someday")));
- }
-
- @Test
- public void alert_on_work_duration() {
- Metric metric = new Metric.Builder("tech_debt", "Debt", Metric.ValueType.WORK_DUR).create();
-
- // metric name is declared in l10n bundle
- when(i18n.message(any(Locale.class), eq("metric.tech_debt.name"), anyString())).thenReturn("The Debt");
- when(durations.format(any(Locale.class), eq(Duration.create(3600L)), eq(Durations.DurationFormat.SHORT))).thenReturn("1h");
-
- when(context.getMeasure(metric)).thenReturn(new Measure(metric, 7200d));
- ArrayList<ResolvedCondition> conditions = Lists.newArrayList(mockCondition(metric, QualityGateConditionDto.OPERATOR_GREATER_THAN, "3600", null));
- when(qualityGate.conditions()).thenReturn(conditions);
- verifier.decorate(project, context);
-
- // First call to saveMeasure is for the update of debt
- verify(context).saveMeasure(argThat(matchesMetric(metric, Level.ERROR, "The Debt > 1h")));
- verify(context).saveMeasure(argThat(matchesMetric(CoreMetrics.ALERT_STATUS, Metric.Level.ERROR, "The Debt > 1h")));
- verify(context).saveMeasure(argThat(new IsMeasure(CoreMetrics.QUALITY_GATE_DETAILS, "{\"level\":\"ERROR\","
- + "\"conditions\":"
- + "["
- + "{\"metric\":\"tech_debt\",\"op\":\"GT\",\"error\":\"3600\",\"actual\":\"7200.0\",\"level\":\"ERROR\"}"
- + "]"
- + "}")));
- }
-
- private ArgumentMatcher<Measure> matchesMetric(final Metric metric, final Metric.Level alertStatus, final String alertText) {
- return new ArgumentMatcher<Measure>() {
- @Override
- public boolean matches(Object arg) {
- boolean result = ((Measure) arg).getMetric().equals(metric) && ((Measure) arg).getAlertStatus() == alertStatus;
- if (result && alertText != null) {
- result = alertText.equals(((Measure) arg).getAlertText());
- }
- return result;
- }
- };
- }
-
- private ArgumentMatcher<Measure> hasLevel(final Measure measure, final Metric.Level alertStatus) {
- return new ArgumentMatcher<Measure>() {
- @Override
- public boolean matches(Object arg) {
- return arg == measure && ((Measure) arg).getAlertStatus().equals(alertStatus);
- }
- };
- }
-
- private ResolvedCondition mockCondition(Metric metric, String operator, String error, String warning) {
- return mockCondition(metric, operator, error, warning, null);
- }
-
- private ResolvedCondition mockCondition(Metric metric, String operator, String error, String warning, Integer period) {
- ResolvedCondition cond = mock(ResolvedCondition.class);
- when(cond.metric()).thenReturn(metric);
- when(cond.metricKey()).thenReturn(metric.getKey());
- when(cond.operator()).thenReturn(operator);
- when(cond.warningThreshold()).thenReturn(warning);
- when(cond.errorThreshold()).thenReturn(error);
- when(cond.period()).thenReturn(period);
- return cond;
- }
-
-}