--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.qualitygate;
+
+import java.util.Objects;
+import java.util.Optional;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.Immutable;
+
+import static java.util.Objects.requireNonNull;
+
+@Immutable
+public class Condition {
+
+ private final String metricKey;
+ private final Operator operator;
+ @CheckForNull
+ private final String warningThreshold;
+ @CheckForNull
+ private final String errorThreshold;
+ private final boolean onLeakPeriod;
+
+ public Condition(String metricKey, Operator operator,
+ @Nullable String errorThreshold, @Nullable String warningThreshold,
+ boolean onLeakPeriod) {
+ this.metricKey = requireNonNull(metricKey, "metricKey can't be null");
+ this.operator = requireNonNull(operator, "operator can't be null");
+ this.onLeakPeriod = onLeakPeriod;
+ this.errorThreshold = errorThreshold;
+ this.warningThreshold = warningThreshold;
+ }
+
+ public String getMetricKey() {
+ return metricKey;
+ }
+
+ public boolean isOnLeakPeriod() {
+ return onLeakPeriod;
+ }
+
+ public Operator getOperator() {
+ return operator;
+ }
+
+ public Optional<String> getWarningThreshold() {
+ return Optional.ofNullable(warningThreshold);
+ }
+
+ public Optional<String> getErrorThreshold() {
+ return Optional.ofNullable(errorThreshold);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ Condition condition = (Condition) o;
+ return onLeakPeriod == condition.onLeakPeriod &&
+ Objects.equals(metricKey, condition.metricKey) &&
+ operator == condition.operator &&
+ Objects.equals(warningThreshold, condition.warningThreshold) &&
+ Objects.equals(errorThreshold, condition.errorThreshold);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(metricKey, operator, warningThreshold, errorThreshold, onLeakPeriod);
+ }
+
+ @Override
+ public String toString() {
+ return "Condition{" +
+ "metricKey='" + metricKey + '\'' +
+ ", operator=" + operator +
+ ", warningThreshold=" + toString(warningThreshold) +
+ ", errorThreshold=" + toString(errorThreshold) +
+ ", onLeakPeriod=" + onLeakPeriod +
+ '}';
+ }
+
+ private static String toString(@Nullable String errorThreshold) {
+ if (errorThreshold == null) {
+ return null;
+ }
+ return '\'' + errorThreshold + '\'';
+ }
+
+ public enum Operator {
+ EQUALS("EQ"), NOT_EQUALS("NE"), GREATER_THAN("GT"), LESS_THAN("LT");
+
+ private final String dbValue;
+
+ Operator(String dbValue) {
+ this.dbValue = dbValue;
+ }
+
+ public String getDbValue() {
+ return dbValue;
+ }
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.qualitygate;
+
+import java.util.Objects;
+import java.util.Optional;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.Immutable;
+
+import static java.util.Objects.requireNonNull;
+
+@Immutable
+public class EvaluatedCondition {
+ private final Condition condition;
+ private final EvaluationStatus status;
+ private final String value;
+
+ public EvaluatedCondition(Condition condition, EvaluationStatus status, @Nullable String value) {
+ this.condition = requireNonNull(condition, "condition can't be null");
+ this.status = requireNonNull(status, "status can't be null");
+ this.value = value;
+ }
+
+ public Condition getCondition() {
+ return condition;
+ }
+
+ public EvaluationStatus getStatus() {
+ return status;
+ }
+
+ public Optional<String> getValue() {
+ return Optional.ofNullable(value);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ EvaluatedCondition that = (EvaluatedCondition) o;
+ return Objects.equals(condition, that.condition) &&
+ status == that.status &&
+ Objects.equals(value, that.value);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(condition, status, value);
+ }
+
+ @Override
+ public String toString() {
+ return "EvaluatedCondition{" +
+ "condition=" + condition +
+ ", status=" + status +
+ ", value=" + (value == null ? null : '\'' + value + '\'') +
+ '}';
+ }
+
+ /**
+ * Quality gate condition evaluation status.
+ */
+ public enum EvaluationStatus {
+ /**
+ * No measure found or measure had no value. The condition has not been evaluated and therefor ignored in
+ * the computation of the Quality Gate status.
+ */
+ NO_VALUE,
+ /**
+ * Condition evaluated as OK, neither error nor warning thresholds have been reached.
+ */
+ OK,
+ /**
+ * Condition evaluated as WARN, only warning thresholds has been reached.
+ */
+ WARN,
+ /**
+ * Condition evaluated as ERROR, error thresholds has been reached (and most likely warning thresholds too).
+ */
+ ERROR
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.qualitygate;
+
+import com.google.common.collect.ImmutableSet;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.Immutable;
+import org.sonar.server.qualitygate.EvaluatedCondition.EvaluationStatus;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
+
+@Immutable
+public class EvaluatedQualityGate {
+ private final QualityGate qualityGate;
+ private final Status status;
+ private final Set<EvaluatedCondition> evaluatedConditions;
+
+ private EvaluatedQualityGate(QualityGate qualityGate, Status status, Set<EvaluatedCondition> evaluatedConditions) {
+ this.qualityGate = qualityGate;
+ this.status = status;
+ this.evaluatedConditions = evaluatedConditions;
+ }
+
+ public QualityGate getQualityGate() {
+ return qualityGate;
+ }
+
+ public Status getStatus() {
+ return status;
+ }
+
+ public Set<EvaluatedCondition> getEvaluatedConditions() {
+ return evaluatedConditions;
+ }
+
+ public static Builder newBuilder() {
+ return new Builder();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ EvaluatedQualityGate that = (EvaluatedQualityGate) o;
+ return Objects.equals(qualityGate, that.qualityGate) &&
+ status == that.status &&
+ Objects.equals(evaluatedConditions, that.evaluatedConditions);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(qualityGate, status, evaluatedConditions);
+ }
+
+ @Override
+ public String toString() {
+ return "EvaluatedQualityGate{" +
+ "qualityGate=" + qualityGate +
+ ", status=" + status +
+ ", evaluatedConditions=" + evaluatedConditions +
+ '}';
+ }
+
+ public static final class Builder {
+ private QualityGate qualityGate;
+ private Status status;
+ private final Map<Condition, EvaluatedCondition> evaluatedConditions = new HashMap<>();
+
+ private Builder() {
+ // use static factory method
+ }
+
+ public Builder setQualityGate(QualityGate qualityGate) {
+ this.qualityGate = checkQualityGate(qualityGate);
+ return this;
+ }
+
+ public Builder setStatus(Status status) {
+ this.status = checkStatus(status);
+ return this;
+ }
+
+ public Builder addCondition(Condition condition, EvaluationStatus status, @Nullable String value) {
+ evaluatedConditions.put(condition, new EvaluatedCondition(condition, status, value));
+ return this;
+ }
+
+ public Set<EvaluatedCondition> getEvaluatedConditions() {
+ return ImmutableSet.copyOf(evaluatedConditions.values());
+ }
+
+ public EvaluatedQualityGate build() {
+ checkQualityGate(this.qualityGate);
+ checkStatus(this.status);
+
+ return new EvaluatedQualityGate(
+ this.qualityGate,
+ this.status,
+ checkEvaluatedConditions(qualityGate, evaluatedConditions));
+ }
+
+ private static Set<EvaluatedCondition> checkEvaluatedConditions(QualityGate qualityGate, Map<Condition, EvaluatedCondition> evaluatedConditions) {
+ Set<Condition> conditions = qualityGate.getConditions();
+
+ Set<Condition> conditionsNotEvaluated = conditions.stream()
+ .filter(c -> !evaluatedConditions.containsKey(c))
+ .collect(Collectors.toSet());
+ checkArgument(conditionsNotEvaluated.isEmpty(), "Evaluation missing for the following conditions: %s", conditionsNotEvaluated);
+
+ Set<Condition> unknownConditions = evaluatedConditions.keySet().stream()
+ .filter(c -> !conditions.contains(c))
+ .collect(Collectors.toSet());
+ checkArgument(unknownConditions.isEmpty(), "Evaluation provided for unknown conditions: %s", unknownConditions);
+
+ return ImmutableSet.copyOf(evaluatedConditions.values());
+ }
+
+ private static QualityGate checkQualityGate(@Nullable QualityGate qualityGate) {
+ return requireNonNull(qualityGate, "qualityGate can't be null");
+ }
+
+ private static Status checkStatus(@Nullable Status status) {
+ return requireNonNull(status, "status can't be null");
+ }
+ }
+
+ public enum Status {
+ OK,
+ WARN,
+ ERROR
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.qualitygate;
+
+import java.util.Objects;
+import java.util.Set;
+import javax.annotation.concurrent.Immutable;
+
+import static java.util.Objects.requireNonNull;
+import static org.sonar.core.util.stream.MoreCollectors.toSet;
+
+@Immutable
+public class QualityGate {
+ private final String id;
+ private final String name;
+ private final Set<Condition> conditions;
+
+ public QualityGate(String id, String name, Set<Condition> conditions) {
+ this.id = requireNonNull(id, "id can't be null");
+ this.name = requireNonNull(name, "name can't be null");
+ this.conditions = requireNonNull(conditions, "conditions can't be null")
+ .stream()
+ .map(c -> requireNonNull(c, "condition can't be null"))
+ .collect(toSet(conditions.size()));
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Set<Condition> getConditions() {
+ return conditions;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ QualityGate that = (QualityGate) o;
+ return Objects.equals(id, that.id) &&
+ Objects.equals(name, that.name) &&
+ Objects.equals(conditions, that.conditions);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, name, conditions);
+ }
+
+ @Override
+ public String toString() {
+ return "QualityGate{" +
+ "id=" + id +
+ ", name='" + name + '\'' +
+ ", conditions=" + conditions +
+ '}';
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.qualitygate;
+
+import java.util.Arrays;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class ConditionTest {
+ private static final String METRIC_KEY = "metric_key";
+ private static final Condition.Operator OPERATOR = Condition.Operator.EQUALS;
+ private static final String ERROR_THRESHOLD = "2";
+ private static final String WARN_THRESHOLD = "4";
+ private static final boolean ON_LEAK_PERIOD = true;
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ private Condition underTest = new Condition(METRIC_KEY, OPERATOR, ERROR_THRESHOLD, WARN_THRESHOLD, ON_LEAK_PERIOD);
+
+ @Test
+ public void constructor_throws_NPE_if_metricKey_is_null() {
+ expectedException.expect(NullPointerException.class);
+ expectedException.expectMessage("metricKey can't be null");
+
+ new Condition(null, OPERATOR, ERROR_THRESHOLD, WARN_THRESHOLD, ON_LEAK_PERIOD);
+ }
+
+ @Test
+ public void constructor_throws_NPE_if_operator_is_null() {
+ expectedException.expect(NullPointerException.class);
+ expectedException.expectMessage("operator can't be null");
+
+ new Condition(METRIC_KEY, null, ERROR_THRESHOLD, WARN_THRESHOLD, ON_LEAK_PERIOD);
+ }
+
+ @Test
+ public void errorThreshold_can_be_null() {
+ Condition underTest = new Condition(METRIC_KEY, OPERATOR, null, WARN_THRESHOLD, ON_LEAK_PERIOD);
+
+ assertThat(underTest.getErrorThreshold()).isEmpty();
+ }
+
+ @Test
+ public void warnThreshold_can_be_null() {
+ Condition underTest = new Condition(METRIC_KEY, OPERATOR, ERROR_THRESHOLD, null, ON_LEAK_PERIOD);
+
+ assertThat(underTest.getWarningThreshold()).isEmpty();
+ }
+
+ @Test
+ public void verify_getters() {
+ assertThat(underTest.getMetricKey()).isEqualTo(METRIC_KEY);
+ assertThat(underTest.getOperator()).isEqualTo(OPERATOR);
+ assertThat(underTest.getErrorThreshold()).contains(ERROR_THRESHOLD);
+ assertThat(underTest.getWarningThreshold()).contains(WARN_THRESHOLD);
+ assertThat(underTest.isOnLeakPeriod()).isEqualTo(ON_LEAK_PERIOD);
+ }
+
+ @Test
+ public void toString_is_override() {
+ assertThat(underTest.toString())
+ .isEqualTo("Condition{metricKey='metric_key', operator=EQUALS, warningThreshold='4', errorThreshold='2', onLeakPeriod=true}");
+ }
+
+ @Test
+ public void toString_does_not_quote_nulls() {
+ Condition withNulls = new Condition("metric_key", Condition.Operator.LESS_THAN, null, null, false);
+ assertThat(withNulls.toString())
+ .isEqualTo("Condition{metricKey='metric_key', operator=LESS_THAN, warningThreshold=null, errorThreshold=null, onLeakPeriod=false}");
+ }
+
+ @Test
+ public void equals_is_based_on_all_fields() {
+ assertThat(underTest).isEqualTo(underTest);
+ assertThat(underTest).isNotEqualTo(null);
+ assertThat(underTest).isNotEqualTo(new Object());
+ assertThat(underTest).isEqualTo(new Condition(METRIC_KEY, OPERATOR, ERROR_THRESHOLD, WARN_THRESHOLD, ON_LEAK_PERIOD));
+ assertThat(underTest).isNotEqualTo(new Condition("other_metric_key", OPERATOR, ERROR_THRESHOLD, WARN_THRESHOLD, ON_LEAK_PERIOD));
+ Arrays.stream(Condition.Operator.values())
+ .filter(s -> !OPERATOR.equals(s))
+ .forEach(otherOperator -> assertThat(underTest)
+ .isNotEqualTo(new Condition(METRIC_KEY, otherOperator, ERROR_THRESHOLD, WARN_THRESHOLD, ON_LEAK_PERIOD)));
+ assertThat(underTest).isNotEqualTo(new Condition(METRIC_KEY, OPERATOR, null, WARN_THRESHOLD, ON_LEAK_PERIOD));
+ assertThat(underTest).isNotEqualTo(new Condition(METRIC_KEY, OPERATOR, "other_error_threshold", WARN_THRESHOLD, ON_LEAK_PERIOD));
+ assertThat(underTest).isNotEqualTo(new Condition(METRIC_KEY, OPERATOR, ERROR_THRESHOLD, null, ON_LEAK_PERIOD));
+ assertThat(underTest).isNotEqualTo(new Condition(METRIC_KEY, OPERATOR, ERROR_THRESHOLD, "other_warn_threshold", ON_LEAK_PERIOD));
+ assertThat(underTest).isNotEqualTo(new Condition(METRIC_KEY, OPERATOR, ERROR_THRESHOLD, WARN_THRESHOLD, !ON_LEAK_PERIOD));
+ }
+
+ @Test
+ public void hashcode_is_based_on_all_fields() {
+ assertThat(underTest.hashCode()).isEqualTo(underTest.hashCode());
+ assertThat(underTest.hashCode()).isNotEqualTo(null);
+ assertThat(underTest.hashCode()).isNotEqualTo(new Object().hashCode());
+ assertThat(underTest.hashCode()).isEqualTo(new Condition(METRIC_KEY, OPERATOR, ERROR_THRESHOLD, WARN_THRESHOLD, ON_LEAK_PERIOD).hashCode());
+ assertThat(underTest.hashCode()).isNotEqualTo(new Condition("other_metric_key", OPERATOR, ERROR_THRESHOLD, WARN_THRESHOLD, ON_LEAK_PERIOD).hashCode());
+ Arrays.stream(Condition.Operator.values())
+ .filter(s -> !OPERATOR.equals(s))
+ .forEach(otherOperator -> assertThat(underTest.hashCode())
+ .isNotEqualTo(new Condition(METRIC_KEY, otherOperator, ERROR_THRESHOLD, WARN_THRESHOLD, ON_LEAK_PERIOD).hashCode()));
+ assertThat(underTest.hashCode()).isNotEqualTo(new Condition(METRIC_KEY, OPERATOR, null, WARN_THRESHOLD, ON_LEAK_PERIOD).hashCode());
+ assertThat(underTest.hashCode()).isNotEqualTo(new Condition(METRIC_KEY, OPERATOR, "other_error_threshold", WARN_THRESHOLD, ON_LEAK_PERIOD).hashCode());
+ assertThat(underTest.hashCode()).isNotEqualTo(new Condition(METRIC_KEY, OPERATOR, ERROR_THRESHOLD, null, ON_LEAK_PERIOD).hashCode());
+ assertThat(underTest.hashCode()).isNotEqualTo(new Condition(METRIC_KEY, OPERATOR, ERROR_THRESHOLD, "other_warn_threshold", ON_LEAK_PERIOD).hashCode());
+ assertThat(underTest.hashCode()).isNotEqualTo(new Condition(METRIC_KEY, OPERATOR, ERROR_THRESHOLD, WARN_THRESHOLD, !ON_LEAK_PERIOD).hashCode());
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.qualitygate;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.server.qualitygate.Condition.Operator.EQUALS;
+import static org.sonar.server.qualitygate.EvaluatedCondition.EvaluationStatus.OK;
+import static org.sonar.server.qualitygate.EvaluatedCondition.EvaluationStatus.WARN;
+
+public class EvaluatedConditionTest {
+ private static final Condition CONDITION_1 = new Condition("metricKey", EQUALS, "2", "4", false);
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ private EvaluatedCondition underTest = new EvaluatedCondition(CONDITION_1, WARN, "value");
+
+ @Test
+ public void constructor_throws_NPE_if_condition_is_null() {
+ expectedException.expect(NullPointerException.class);
+ expectedException.expectMessage("condition can't be null");
+
+ new EvaluatedCondition(null, WARN, "value");
+ }
+
+ @Test
+ public void constructor_throws_NPE_if_EvaluationStatus_is_null() {
+ expectedException.expect(NullPointerException.class);
+ expectedException.expectMessage("status can't be null");
+
+ new EvaluatedCondition(CONDITION_1, null, "value");
+ }
+
+ @Test
+ public void constructor_accepts_null_value() {
+ EvaluatedCondition underTest = new EvaluatedCondition(CONDITION_1, WARN, null);
+
+ assertThat(underTest.getValue()).isEmpty();
+ }
+
+ @Test
+ public void verify_getters() {
+ EvaluatedCondition underTest = new EvaluatedCondition(CONDITION_1, WARN, "value");
+
+ assertThat(underTest.getCondition()).isEqualTo(CONDITION_1);
+ assertThat(underTest.getStatus()).isEqualTo(WARN);
+ assertThat(underTest.getValue()).contains("value");
+ }
+
+ @Test
+ public void override_toString() {
+ assertThat(underTest.toString()).isEqualTo("EvaluatedCondition{condition=" +
+ "Condition{metricKey='metricKey', operator=EQUALS, warningThreshold='4', errorThreshold='2', onLeakPeriod=false}, " +
+ "status=WARN, value='value'}");
+ }
+
+ @Test
+ public void toString_does_not_quote_null_value() {
+ EvaluatedCondition underTest = new EvaluatedCondition(CONDITION_1, WARN, null);
+
+ assertThat(underTest.toString()).isEqualTo("EvaluatedCondition{condition=" +
+ "Condition{metricKey='metricKey', operator=EQUALS, warningThreshold='4', errorThreshold='2', onLeakPeriod=false}, " +
+ "status=WARN, value=null}");
+ }
+
+ @Test
+ public void equals_is_based_on_all_fields() {
+ assertThat(underTest).isEqualTo(underTest);
+ assertThat(underTest).isEqualTo(new EvaluatedCondition(CONDITION_1, WARN, "value"));
+ assertThat(underTest).isNotEqualTo(null);
+ assertThat(underTest).isNotEqualTo(new Object());
+ assertThat(underTest).isNotEqualTo(new EvaluatedCondition(new Condition("other_metric", EQUALS, "a", "b", true), WARN, "value"));
+ assertThat(underTest).isNotEqualTo(new EvaluatedCondition(CONDITION_1, OK, "value"));
+ assertThat(underTest).isNotEqualTo(new EvaluatedCondition(CONDITION_1, WARN, null));
+ assertThat(underTest).isNotEqualTo(new EvaluatedCondition(CONDITION_1, WARN, "other_value"));
+ }
+
+ @Test
+ public void hashcode_is_based_on_all_fields() {
+ assertThat(underTest.hashCode()).isEqualTo(underTest.hashCode());
+ assertThat(underTest.hashCode()).isEqualTo(new EvaluatedCondition(CONDITION_1, WARN, "value").hashCode());
+ assertThat(underTest.hashCode()).isNotEqualTo(null);
+ assertThat(underTest.hashCode()).isNotEqualTo(new Object().hashCode());
+ assertThat(underTest.hashCode()).isNotEqualTo(new EvaluatedCondition(new Condition("other_metric", EQUALS, "a", "b", true), WARN, "value").hashCode());
+ assertThat(underTest.hashCode()).isNotEqualTo(new EvaluatedCondition(CONDITION_1, OK, "value").hashCode());
+ assertThat(underTest.hashCode()).isNotEqualTo(new EvaluatedCondition(CONDITION_1, WARN, null).hashCode());
+ assertThat(underTest.hashCode()).isNotEqualTo(new EvaluatedCondition(CONDITION_1, WARN, "other_value").hashCode());
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.qualitygate;
+
+import com.google.common.collect.ImmutableSet;
+import java.util.Random;
+import org.apache.commons.lang.RandomStringUtils;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import static java.util.Collections.emptySet;
+import static java.util.Collections.singleton;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.server.qualitygate.EvaluatedQualityGate.newBuilder;
+import static org.sonar.server.qualitygate.EvaluatedQualityGate.Status.OK;
+import static org.sonar.server.qualitygate.EvaluatedQualityGate.Status.WARN;
+
+public class EvaluatedQualityGateTest {
+ private static final String QUALITY_GATE_ID = "qg_id";
+ private static final String QUALITY_GATE_NAME = "qg_name";
+ private static final QualityGate NO_CONDITION_QUALITY_GATE = new QualityGate(QUALITY_GATE_ID, QUALITY_GATE_NAME, emptySet());
+ private static final Condition CONDITION_1 = new Condition("metric_key", Condition.Operator.LESS_THAN, "2", "4", true);
+ private static final Condition CONDITION_2 = new Condition("metric_key_2", Condition.Operator.GREATER_THAN, "6", "12", false);
+ private static final QualityGate ONE_CONDITION_QUALITY_GATE = new QualityGate(QUALITY_GATE_ID, QUALITY_GATE_NAME, singleton(CONDITION_1));
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ private final Random random = new Random();
+ private final EvaluatedQualityGate.Status randomStatus = EvaluatedQualityGate.Status.values()[random.nextInt(EvaluatedQualityGate.Status.values().length)];
+ private final EvaluatedCondition.EvaluationStatus randomEvaluationStatus = EvaluatedCondition.EvaluationStatus.values()[random
+ .nextInt(EvaluatedCondition.EvaluationStatus.values().length)];
+ private final String randomValue = random.nextBoolean() ? null : RandomStringUtils.randomAlphanumeric(3);
+
+ private EvaluatedQualityGate.Builder builder = newBuilder();
+
+ @Test
+ public void setQualityGate_fails_with_NPE_if_argument_is_null() {
+ expectedException.expect(NullPointerException.class);
+ expectedException.expectMessage("qualityGate can't be null");
+
+ builder.setQualityGate(null);
+ }
+
+ @Test
+ public void setStatus_fails_with_NPE_if_argument_is_null() {
+ expectedException.expect(NullPointerException.class);
+ expectedException.expectMessage("status can't be null");
+
+ builder.setStatus(null);
+ }
+
+ @Test
+ public void build_fails_with_NPE_if_qualityGate_not_set() {
+ expectedException.expect(NullPointerException.class);
+ expectedException.expectMessage("qualityGate can't be null");
+
+ builder.build();
+ }
+
+ @Test
+ public void build_fails_with_NPE_if_status_not_set() {
+ builder.setQualityGate(NO_CONDITION_QUALITY_GATE);
+
+ expectedException.expect(NullPointerException.class);
+ expectedException.expectMessage("status can't be null");
+
+ builder.build();
+ }
+
+ @Test
+ public void addCondition_fails_with_NPE_if_condition_is_null() {
+ expectedException.expect(NullPointerException.class);
+ expectedException.expectMessage("condition can't be null");
+
+ builder.addCondition(null, EvaluatedCondition.EvaluationStatus.WARN, "a_value");
+ }
+
+ @Test
+ public void addCondition_fails_with_NPE_if_status_is_null() {
+ expectedException.expect(NullPointerException.class);
+ expectedException.expectMessage("status can't be null");
+
+ builder.addCondition(new Condition("metric_key", Condition.Operator.LESS_THAN, "2", "4", true), null, "a_value");
+ }
+
+ @Test
+ public void addCondition_accepts_null_value() {
+ builder.addCondition(CONDITION_1, EvaluatedCondition.EvaluationStatus.NO_VALUE, null);
+
+ assertThat(builder.getEvaluatedConditions())
+ .containsOnly(new EvaluatedCondition(CONDITION_1, EvaluatedCondition.EvaluationStatus.NO_VALUE, null));
+ }
+
+ @Test
+ public void getEvaluatedConditions_returns_empty_with_no_condition_added_to_builder() {
+ assertThat(builder.getEvaluatedConditions()).isEmpty();
+ }
+
+ @Test
+ public void build_fails_with_IAE_if_condition_added_and_no_on_QualityGate() {
+ builder.setQualityGate(NO_CONDITION_QUALITY_GATE)
+ .setStatus(randomStatus)
+ .addCondition(CONDITION_1, randomEvaluationStatus, randomValue);
+
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Evaluation provided for unknown conditions: [" + CONDITION_1 + "]");
+
+ builder.build();
+ }
+
+ @Test
+ public void build_fails_with_IAE_if_condition_is_missing_for_one_defined_in_QualityGate() {
+ builder.setQualityGate(ONE_CONDITION_QUALITY_GATE)
+ .setStatus(randomStatus);
+
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Evaluation missing for the following conditions: [" + CONDITION_1 + "]");
+
+ builder.build();
+ }
+
+ @Test
+ public void verify_getters() {
+ EvaluatedQualityGate underTest = builder
+ .setQualityGate(ONE_CONDITION_QUALITY_GATE)
+ .setStatus(randomStatus)
+ .addCondition(CONDITION_1, randomEvaluationStatus, randomValue)
+ .build();
+
+ assertThat(underTest.getQualityGate()).isEqualTo(ONE_CONDITION_QUALITY_GATE);
+ assertThat(underTest.getStatus()).isEqualTo(randomStatus);
+ assertThat(underTest.getEvaluatedConditions())
+ .containsOnly(new EvaluatedCondition(CONDITION_1, randomEvaluationStatus, randomValue));
+ }
+
+ @Test
+ public void verify_getters_when_no_condition() {
+ EvaluatedQualityGate underTest = builder
+ .setQualityGate(NO_CONDITION_QUALITY_GATE)
+ .setStatus(randomStatus)
+ .build();
+
+ assertThat(underTest.getQualityGate()).isEqualTo(NO_CONDITION_QUALITY_GATE);
+ assertThat(underTest.getStatus()).isEqualTo(randomStatus);
+ assertThat(underTest.getEvaluatedConditions()).isEmpty();
+ }
+
+ @Test
+ public void verify_getters_when_multiple_conditions() {
+ QualityGate qualityGate = new QualityGate(QUALITY_GATE_ID, QUALITY_GATE_NAME, ImmutableSet.of(CONDITION_1, CONDITION_2));
+ EvaluatedQualityGate underTest = builder
+ .setQualityGate(qualityGate)
+ .setStatus(randomStatus)
+ .addCondition(CONDITION_1, randomEvaluationStatus, randomValue)
+ .addCondition(CONDITION_2, EvaluatedCondition.EvaluationStatus.WARN, "bad")
+ .build();
+
+ assertThat(underTest.getQualityGate()).isEqualTo(qualityGate);
+ assertThat(underTest.getStatus()).isEqualTo(randomStatus);
+ assertThat(underTest.getEvaluatedConditions()).containsOnly(
+ new EvaluatedCondition(CONDITION_1, randomEvaluationStatus, randomValue),
+ new EvaluatedCondition(CONDITION_2, EvaluatedCondition.EvaluationStatus.WARN, "bad"));
+ }
+
+ @Test
+ public void equals_is_based_on_all_fields() {
+ EvaluatedQualityGate.Builder builder = this.builder
+ .setQualityGate(ONE_CONDITION_QUALITY_GATE)
+ .setStatus(WARN)
+ .addCondition(CONDITION_1, EvaluatedCondition.EvaluationStatus.WARN, "foo");
+
+ EvaluatedQualityGate underTest = builder.build();
+ assertThat(underTest).isEqualTo(builder.build());
+ assertThat(underTest).isNotSameAs(builder.build());
+ assertThat(underTest).isNotEqualTo(null);
+ assertThat(underTest).isNotEqualTo(new Object());
+ assertThat(underTest).isNotEqualTo(builder.setQualityGate(new QualityGate("other_id", QUALITY_GATE_NAME, singleton(CONDITION_1))).build());
+ assertThat(underTest).isNotEqualTo(builder.setQualityGate(ONE_CONDITION_QUALITY_GATE).setStatus(OK).build());
+ assertThat(underTest).isNotEqualTo(newBuilder()
+ .setQualityGate(ONE_CONDITION_QUALITY_GATE)
+ .setStatus(WARN)
+ .addCondition(CONDITION_1, EvaluatedCondition.EvaluationStatus.OK, "foo")
+ .build());
+ }
+
+ @Test
+ public void hashcode_is_based_on_all_fields() {
+ EvaluatedQualityGate.Builder builder = this.builder
+ .setQualityGate(ONE_CONDITION_QUALITY_GATE)
+ .setStatus(WARN)
+ .addCondition(CONDITION_1, EvaluatedCondition.EvaluationStatus.WARN, "foo");
+
+ EvaluatedQualityGate underTest = builder.build();
+ assertThat(underTest.hashCode()).isEqualTo(builder.build().hashCode());
+ assertThat(underTest.hashCode()).isNotSameAs(builder.build().hashCode());
+ assertThat(underTest.hashCode()).isNotEqualTo(null);
+ assertThat(underTest.hashCode()).isNotEqualTo(new Object().hashCode());
+ assertThat(underTest.hashCode()).isNotEqualTo(builder.setQualityGate(new QualityGate("other_id", QUALITY_GATE_NAME, singleton(CONDITION_1))).build().hashCode());
+ assertThat(underTest.hashCode()).isNotEqualTo(builder.setQualityGate(ONE_CONDITION_QUALITY_GATE).setStatus(OK).build().hashCode());
+ assertThat(underTest.hashCode()).isNotEqualTo(newBuilder()
+ .setQualityGate(ONE_CONDITION_QUALITY_GATE)
+ .setStatus(WARN)
+ .addCondition(CONDITION_1, EvaluatedCondition.EvaluationStatus.OK, "foo")
+ .build().hashCode());
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.qualitygate;
+
+import com.google.common.collect.ImmutableSet;
+import java.util.Random;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import static java.util.Collections.emptySet;
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class QualityGateTest {
+ private static final String QUALIGATE_ID = "qg_id";
+ private static final String QUALIGATE_NAME = "qg_name";
+ private static final Condition CONDITION_1 = new Condition("m1", Condition.Operator.EQUALS, "1", "2", false);
+ private static final Condition CONDITION_2 = new Condition("m2", Condition.Operator.LESS_THAN, "2", "4", true);
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ private QualityGate underTest = new QualityGate(QUALIGATE_ID, QUALIGATE_NAME, ImmutableSet.of(CONDITION_1, CONDITION_2));
+
+ @Test
+ public void constructor_fails_with_NPE_if_id_is_null() {
+ expectedException.expect(NullPointerException.class);
+ expectedException.expectMessage("id can't be null");
+
+ new QualityGate(null, "name", emptySet());
+ }
+
+ @Test
+ public void constructor_fails_with_NPE_if_name_is_null() {
+ expectedException.expect(NullPointerException.class);
+ expectedException.expectMessage("name can't be null");
+
+ new QualityGate("id", null, emptySet());
+ }
+
+ @Test
+ public void constructor_fails_with_NPE_if_conditions_is_null() {
+ expectedException.expect(NullPointerException.class);
+ expectedException.expectMessage("conditions can't be null");
+
+ new QualityGate("id", "name", null);
+ }
+
+ @Test
+ public void constructor_fails_with_NPE_if_conditions_contains_null() {
+ expectedException.expect(NullPointerException.class);
+ expectedException.expectMessage("condition can't be null");
+ Random random = new Random();
+ Set<Condition> conditions = Stream.of(
+ IntStream.range(0, random.nextInt(5))
+ .mapToObj(i -> new Condition("m_before_" + i, Condition.Operator.EQUALS, null, null, false)),
+ Stream.of((Condition) null),
+ IntStream.range(0, random.nextInt(5))
+ .mapToObj(i -> new Condition("m_after_" + i, Condition.Operator.EQUALS, null, null, false)))
+ .flatMap(s -> s)
+ .collect(Collectors.toSet());
+
+ expectedException.expect(NullPointerException.class);
+ expectedException.expectMessage("condition can't be null");
+
+ new QualityGate("id", "name", conditions);
+ }
+
+ @Test
+ public void verify_getters() {
+ assertThat(underTest.getId()).isEqualTo(QUALIGATE_ID);
+ assertThat(underTest.getName()).isEqualTo(QUALIGATE_NAME);
+ assertThat(underTest.getConditions()).containsOnly(CONDITION_1, CONDITION_2);
+ }
+
+ @Test
+ public void toString_is_override() {
+ QualityGate underTest = new QualityGate(QUALIGATE_ID, QUALIGATE_NAME, ImmutableSet.of(CONDITION_2));
+
+ assertThat(underTest.toString()).isEqualTo("QualityGate{id=qg_id, name='qg_name', conditions=[" +
+ "Condition{metricKey='m2', operator=LESS_THAN, warningThreshold='4', errorThreshold='2', onLeakPeriod=true}" +
+ "]}");
+ }
+
+ @Test
+ public void equals_is_based_on_all_fields() {
+ assertThat(underTest).isEqualTo(underTest);
+ assertThat(underTest).isEqualTo(new QualityGate(QUALIGATE_ID, QUALIGATE_NAME, ImmutableSet.of(CONDITION_2, CONDITION_1)));
+ assertThat(underTest).isNotEqualTo(null);
+ assertThat(underTest).isNotEqualTo(new Object());
+ assertThat(underTest).isNotEqualTo(new QualityGate("other_id", QUALIGATE_NAME, ImmutableSet.of(CONDITION_2, CONDITION_1)));
+ assertThat(underTest).isNotEqualTo(new QualityGate(QUALIGATE_ID, "other_name", ImmutableSet.of(CONDITION_2, CONDITION_1)));
+ assertThat(underTest).isNotEqualTo(new QualityGate(QUALIGATE_ID, QUALIGATE_NAME, emptySet()));
+ assertThat(underTest).isNotEqualTo(new QualityGate(QUALIGATE_ID, QUALIGATE_NAME, ImmutableSet.of(CONDITION_1)));
+ assertThat(underTest).isNotEqualTo(new QualityGate(QUALIGATE_ID, QUALIGATE_NAME, ImmutableSet.of(CONDITION_2)));
+ assertThat(underTest).isNotEqualTo(
+ new QualityGate(QUALIGATE_ID, QUALIGATE_NAME, ImmutableSet.of(CONDITION_1, CONDITION_2, new Condition("new", Condition.Operator.GREATER_THAN, "a", "b", false))));
+ }
+
+ @Test
+ public void hashcode_is_based_on_all_fields() {
+ assertThat(underTest.hashCode()).isEqualTo(underTest.hashCode());
+ assertThat(underTest.hashCode()).isEqualTo(new QualityGate(QUALIGATE_ID, QUALIGATE_NAME, ImmutableSet.of(CONDITION_2, CONDITION_1)).hashCode());
+ assertThat(underTest.hashCode()).isNotEqualTo(null);
+ assertThat(underTest.hashCode()).isNotEqualTo(new Object().hashCode());
+ assertThat(underTest.hashCode()).isNotEqualTo(new QualityGate("other_id", QUALIGATE_NAME, ImmutableSet.of(CONDITION_2, CONDITION_1)).hashCode());
+ assertThat(underTest.hashCode()).isNotEqualTo(new QualityGate(QUALIGATE_ID, "other_name", ImmutableSet.of(CONDITION_2, CONDITION_1)).hashCode());
+ assertThat(underTest.hashCode()).isNotEqualTo(new QualityGate(QUALIGATE_ID, QUALIGATE_NAME, emptySet()).hashCode());
+ assertThat(underTest.hashCode()).isNotEqualTo(new QualityGate(QUALIGATE_ID, QUALIGATE_NAME, ImmutableSet.of(CONDITION_1)).hashCode());
+ assertThat(underTest.hashCode()).isNotEqualTo(new QualityGate(QUALIGATE_ID, QUALIGATE_NAME, ImmutableSet.of(CONDITION_2)).hashCode());
+ assertThat(underTest.hashCode()).isNotEqualTo(
+ new QualityGate(QUALIGATE_ID, QUALIGATE_NAME, ImmutableSet.of(CONDITION_1, CONDITION_2, new Condition("new", Condition.Operator.GREATER_THAN, "a", "b", false))).hashCode());
+ }
+}