@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)); assertThat(underTest).isNotEqualTo(new Condition("other_metric_key", OPERATOR, ERROR_THRESHOLD)); Arrays.stream(Condition.Operator.values()) .filter(s -> !OPERATOR.equals(s)) .forEach(otherOperator -> assertThat(underTest) .isNotEqualTo(new Condition(METRIC_KEY, otherOperator, ERROR_THRESHOLD))); assertThat(underTest).isNotEqualTo(new Condition(METRIC_KEY, OPERATOR, "other_error_threshold")); }
private static JsonObject toJson(EvaluatedCondition evaluatedCondition) { Condition condition = evaluatedCondition.getCondition(); JsonObject result = new JsonObject(); result.addProperty("metric", condition.getMetricKey()); result.addProperty("op", condition.getOperator().getDbValue()); if (condition.isOnLeakPeriod()) { result.addProperty("period", 1); } result.addProperty("error", condition.getErrorThreshold()); evaluatedCondition.getValue().ifPresent(v -> result.addProperty("actual", v)); result.addProperty(FIELD_LEVEL, evaluatedCondition.getStatus().name()); return result; } }
@Override public String toString() { return "Condition{" + "metricKey='" + metricKey + '\'' + ", operator=" + operator + ", errorThreshold=" + toString(errorThreshold) + '}'; }
private static Comparable getThreshold(Condition condition, ValueType valueType) { String valString = condition.getErrorThreshold(); try { switch (valueType) { case INT: case RATING: return parseInteger(valString); case MILLISEC: case WORK_DUR: return Long.parseLong(valString); case FLOAT: case PERCENT: return Double.parseDouble(valString); case LEVEL: return valueType; default: throw new IllegalArgumentException(format("Unsupported value type %s. Cannot convert condition value", valueType)); } } catch (NumberFormatException badValueFormat) { throw new IllegalArgumentException(format( "Quality Gate: unable to parse threshold '%s' to compare against %s", valString, condition.getMetricKey())); } }
@Test public void verify_getters() { assertThat(underTest.getMetricKey()).isEqualTo(METRIC_KEY); assertThat(underTest.getOperator()).isEqualTo(OPERATOR); assertThat(underTest.getErrorThreshold()).contains(ERROR_THRESHOLD); }
@Test public void getMetricsRelatedTo() { Condition condition = new Condition("metric1", Condition.Operator.GREATER_THAN, "10"); QualityGate gate = new QualityGate("1", "foo", ImmutableSet.of(condition)); Set<String> result = underTest.getMetricsRelatedTo(gate); assertThat(result).containsExactlyInAnyOrder( // the metrics needed to compute the status of gate condition.getMetricKey(), // generated metrics CoreMetrics.ALERT_STATUS_KEY, CoreMetrics.QUALITY_GATE_DETAILS_KEY); }
@Override public Set<String> getMetricKeys(QualityGate gate) { Set<String> metricKeys = new HashSet<>(); metricKeys.add(CoreMetrics.NEW_LINES_KEY); for (Condition condition : gate.getConditions()) { metricKeys.add(condition.getMetricKey()); } return metricKeys; }
private static Optional<Comparable> getThreshold(Condition condition, ValueType valueType, boolean error) { Optional<String> valString = error ? condition.getErrorThreshold() : condition.getWarningThreshold(); return valString.map(s -> { try { switch (valueType) { case BOOL: return parseInteger(s) == 1; case INT: case RATING: return parseInteger(s); case MILLISEC: case WORK_DUR: return Long.parseLong(s); case FLOAT: case PERCENT: return Double.parseDouble(s); case STRING: case LEVEL: return s; default: throw new IllegalArgumentException(String.format("Unsupported value type %s. Cannot convert condition value", valueType)); } } catch (NumberFormatException badValueFormat) { throw new IllegalArgumentException(String.format( "Quality Gate: unable to parse threshold '%s' to compare against %s", s, condition.getMetricKey())); } }); }
@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).hashCode()); assertThat(underTest.hashCode()).isNotEqualTo(new Condition("other_metric_key", OPERATOR, ERROR_THRESHOLD).hashCode()); Arrays.stream(Condition.Operator.values()) .filter(s -> !OPERATOR.equals(s)) .forEach(otherOperator -> assertThat(underTest.hashCode()) .isNotEqualTo(new Condition(METRIC_KEY, otherOperator, ERROR_THRESHOLD).hashCode())); assertThat(underTest.hashCode()).isNotEqualTo(new Condition(METRIC_KEY, OPERATOR, "other_error_threshold").hashCode()); } }
private static boolean reachThreshold(Comparable measureValue, Comparable threshold, Condition condition) { int comparison = measureValue.compareTo(threshold); switch (condition.getOperator()) { case GREATER_THAN: return comparison > 0; case LESS_THAN: return comparison < 0; default: throw new IllegalArgumentException(format("Unsupported operator '%s'", condition.getOperator())); } } }
private static Optional<Comparable> getMeasureValue(Condition condition, QualityGateEvaluator.Measure measure) { if (condition.isOnLeakPeriod()) { return Optional.ofNullable(getLeakValue(measure)); } return Optional.ofNullable(getValue(measure)); }
private static void writeQualityGate(JsonWriter writer, EvaluatedQualityGate gate) { writer .name("qualityGate") .beginObject() .prop("name", gate.getQualityGate().getName()) .prop(PROPERTY_STATUS, gate.getStatus().toString()) .name("conditions") .beginArray(); for (EvaluatedCondition evaluatedCondition : gate.getEvaluatedConditions()) { Condition condition = evaluatedCondition.getCondition(); writer .beginObject() .prop("metric", condition.getMetricKey()) .prop("operator", condition.getOperator().name()); evaluatedCondition.getValue().ifPresent(t -> writer.prop("value", t)); writer .prop(PROPERTY_STATUS, evaluatedCondition.getStatus().name()) .prop("errorThreshold", condition.getErrorThreshold()) .endObject(); } writer .endArray() .endObject(); }
/** * Evaluates the condition for the specified measure */ static EvaluatedCondition evaluate(Condition condition, QualityGateEvaluator.Measures measures) { Optional<QualityGateEvaluator.Measure> measure = measures.get(condition.getMetricKey()); if (!measure.isPresent()) { return new EvaluatedCondition(condition, EvaluationStatus.OK, null); } Optional<Comparable> value = getMeasureValue(condition, measure.get()); if (!value.isPresent()) { return new EvaluatedCondition(condition, EvaluationStatus.OK, null); } ValueType type = measure.get().getType(); return evaluateCondition(condition, type, value.get()) .orElseGet(() -> new EvaluatedCondition(condition, EvaluationStatus.OK, value.get().toString())); }
private static boolean reachThreshold(Comparable measureValue, Comparable threshold, Condition condition) { int comparison = measureValue.compareTo(threshold); switch (condition.getOperator()) { case EQUALS: return comparison == 0; case NOT_EQUALS: return comparison != 0; case GREATER_THAN: return comparison > 0; case LESS_THAN: return comparison < 0; default: throw new IllegalArgumentException(String.format("Unsupported operator '%s'", condition.getOperator())); } } }
private static Optional<Comparable> getMeasureValue(Condition condition, QualityGateEvaluator.Measure measure) { if (condition.isOnLeakPeriod()) { return Optional.ofNullable(getLeakValue(measure)); } return Optional.ofNullable(getValue(measure)); }
private static JsonObject toJson(EvaluatedCondition evaluatedCondition) { Condition condition = evaluatedCondition.getCondition(); JsonObject result = new JsonObject(); result.addProperty("metric", condition.getMetricKey()); result.addProperty("op", condition.getOperator().getDbValue()); if (condition.isOnLeakPeriod()) { result.addProperty("period", 1); } condition.getWarningThreshold().ifPresent(t -> result.addProperty("warning", t)); condition.getErrorThreshold().ifPresent(t -> result.addProperty("error", t)); evaluatedCondition.getValue().ifPresent(v -> result.addProperty("actual", v)); result.addProperty(FIELD_LEVEL, evaluatedCondition.getStatus().name()); return result; } }
@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.GREATER_THAN, "10")), Stream.of((Condition) null), IntStream.range(0, random.nextInt(5)) .mapToObj(i -> new Condition("m_after_" + i, Condition.Operator.GREATER_THAN, "10"))) .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 getMetricKeys_includes_metrics_from_qgate() { Set<String> metricKeys = ImmutableSet.of("foo", "bar", "baz"); Set<Condition> conditions = metricKeys.stream().map(key -> { Condition condition = mock(Condition.class); when(condition.getMetricKey()).thenReturn(key); return condition; }).collect(Collectors.toSet()); QualityGate gate = mock(QualityGate.class); when(gate.getConditions()).thenReturn(conditions); assertThat(underTest.getMetricKeys(gate)).containsAll(metricKeys); }
@Test public void toString_is_override() { assertThat(underTest.toString()) .isEqualTo("Condition{metricKey='metric_key', operator=GREATER_THAN, errorThreshold='2'}"); }
private static EvaluatedCondition evaluateConditionsOnMetric(Collection<Condition> conditionsOnSameMetric, Measures measures) { EvaluatedCondition leakEvaluation = null; EvaluatedCondition absoluteEvaluation = null; for (Condition condition : conditionsOnSameMetric) { if (condition.isOnLeakPeriod()) { leakEvaluation = ConditionEvaluator.evaluate(condition, measures); } else { absoluteEvaluation = ConditionEvaluator.evaluate(condition, measures); } } if (leakEvaluation == null) { return requireNonNull(absoluteEvaluation, "Evaluation of absolute value can't be null on conditions " + conditionsOnSameMetric); } if (absoluteEvaluation == null) { return requireNonNull(leakEvaluation, "Evaluation of leak value can't be null on conditions " + conditionsOnSameMetric); } // both conditions are present. Take the worse one. In case of equality, take // the one on the leak period if (absoluteEvaluation.getStatus().compareTo(leakEvaluation.getStatus()) > 0) { return absoluteEvaluation; } return leakEvaluation; }