Browse Source

SONAR-10085 add QualityGate model to be shared accross server

tags/7.0-RC1
Sébastien Lesaint 6 years ago
parent
commit
ef1259e286

+ 123
- 0
server/sonar-server/src/main/java/org/sonar/server/qualitygate/Condition.java View File

@@ -0,0 +1,123 @@
/*
* 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;
}
}
}

+ 103
- 0
server/sonar-server/src/main/java/org/sonar/server/qualitygate/EvaluatedCondition.java View File

@@ -0,0 +1,103 @@
/*
* 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
}
}

+ 159
- 0
server/sonar-server/src/main/java/org/sonar/server/qualitygate/EvaluatedQualityGate.java View File

@@ -0,0 +1,159 @@
/*
* 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
}
}

+ 83
- 0
server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGate.java View File

@@ -0,0 +1,83 @@
/*
* 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 +
'}';
}
}

+ 128
- 0
server/sonar-server/src/test/java/org/sonar/server/qualitygate/ConditionTest.java View File

@@ -0,0 +1,128 @@
/*
* 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());
}
}

+ 110
- 0
server/sonar-server/src/test/java/org/sonar/server/qualitygate/EvaluatedConditionTest.java View File

@@ -0,0 +1,110 @@
/*
* 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());
}
}

+ 225
- 0
server/sonar-server/src/test/java/org/sonar/server/qualitygate/EvaluatedQualityGateTest.java View File

@@ -0,0 +1,225 @@
/*
* 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());
}
}

+ 135
- 0
server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateTest.java View File

@@ -0,0 +1,135 @@
/*
* 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());
}
}

Loading…
Cancel
Save