3 * Copyright (C) 2009-2019 SonarSource SA
4 * mailto:info AT sonarsource DOT com
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 3 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 package org.sonar.server.qualitygate;
22 import com.tngtech.java.junit.dataprovider.DataProvider;
23 import com.tngtech.java.junit.dataprovider.DataProviderRunner;
24 import com.tngtech.java.junit.dataprovider.UseDataProvider;
25 import javax.annotation.Nullable;
26 import org.junit.Rule;
27 import org.junit.Test;
28 import org.junit.rules.ExpectedException;
29 import org.junit.runner.RunWith;
30 import org.sonar.api.measures.Metric;
31 import org.sonar.api.utils.System2;
32 import org.sonar.db.DbTester;
33 import org.sonar.db.metric.MetricDto;
34 import org.sonar.db.qualitygate.QualityGateConditionDto;
35 import org.sonar.db.qualitygate.QualityGateDto;
36 import org.sonar.server.exceptions.BadRequestException;
37 import org.sonar.server.exceptions.NotFoundException;
39 import static java.lang.String.format;
40 import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
41 import static org.sonar.api.measures.CoreMetrics.ALERT_STATUS_KEY;
42 import static org.sonar.api.measures.CoreMetrics.SQALE_RATING_KEY;
43 import static org.sonar.api.measures.Metric.ValueType.BOOL;
44 import static org.sonar.api.measures.Metric.ValueType.DATA;
45 import static org.sonar.api.measures.Metric.ValueType.FLOAT;
46 import static org.sonar.api.measures.Metric.ValueType.INT;
47 import static org.sonar.api.measures.Metric.ValueType.MILLISEC;
48 import static org.sonar.api.measures.Metric.ValueType.PERCENT;
49 import static org.sonar.api.measures.Metric.ValueType.RATING;
50 import static org.sonar.api.measures.Metric.ValueType.WORK_DUR;
52 @RunWith(DataProviderRunner.class)
53 public class QualityGateConditionsUpdaterTest {
56 public ExpectedException expectedException = ExpectedException.none();
59 public DbTester db = DbTester.create(System2.INSTANCE);
61 private QualityGateConditionsUpdater underTest = new QualityGateConditionsUpdater(db.getDbClient());
64 public void create_error_condition() {
65 MetricDto metric = db.measures().insertMetric(m -> m.setKey("new_coverage").setValueType(INT.name()).setHidden(false));
66 QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
68 QualityGateConditionDto result = underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "LT", null, "80");
70 verifyCondition(result, qualityGate, metric, "LT", null, "80");
74 public void fail_to_create_condition_when_condition_on_same_metric_already_exist() {
75 MetricDto metric = db.measures().insertMetric(m -> m.setValueType(PERCENT.name()).setHidden(false));
76 QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
77 db.qualityGates().addCondition(qualityGate, metric);
79 expectedException.expect(BadRequestException.class);
80 expectedException.expectMessage(format("Condition on metric '%s' already exists.", metric.getShortName()));
82 underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "LT", "90", null);
86 public void fail_to_create_condition_on_missing_metric() {
87 QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
89 expectedException.expect(NotFoundException.class);
90 expectedException.expectMessage("There is no metric with key=new_coverage");
92 underTest.createCondition(db.getSession(), qualityGate, "new_coverage", "LT", null, "80");
96 @UseDataProvider("invalid_metrics")
97 public void fail_to_create_condition_on_invalid_metric(String metricKey, Metric.ValueType valueType, boolean hidden) {
98 MetricDto metric = db.measures().insertMetric(m -> m.setKey(metricKey).setValueType(valueType.name()).setHidden(hidden));
99 QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
101 expectedException.expect(BadRequestException.class);
102 expectedException.expectMessage(format("Metric '%s' cannot be used to define a condition.", metric.getKey()));
104 underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "EQ", null, "80");
108 public void fail_to_create_condition_on_not_allowed_operator() {
109 MetricDto metric = db.measures().insertMetric(m -> m.setValueType(PERCENT.name()).setHidden(false));
110 QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
112 expectedException.expect(BadRequestException.class);
113 expectedException.expectMessage("Operator UNKNOWN is not allowed for metric type PERCENT.");
115 underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "UNKNOWN", null, "80");
119 public void create_condition_on_rating_metric() {
120 MetricDto metric = db.measures().insertMetric(m -> m.setKey(SQALE_RATING_KEY).setValueType(RATING.name()).setHidden(false));
121 QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
123 QualityGateConditionDto result = underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "GT", null, "3");
125 verifyCondition(result, qualityGate, metric, "GT", null, "3");
129 public void fail_to_create_warning_condition_on_invalid_rating_metric() {
130 MetricDto metric = db.measures().insertMetric(m -> m.setKey(SQALE_RATING_KEY).setValueType(RATING.name()).setHidden(false));
131 QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
133 expectedException.expect(BadRequestException.class);
134 expectedException.expectMessage("'6' is not a valid rating");
136 underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "GT", "6", null);
140 public void fail_to_create_error_condition_on_invalid_rating_metric() {
141 MetricDto metric = db.measures().insertMetric(m -> m.setKey(SQALE_RATING_KEY).setValueType(RATING.name()).setHidden(false));
142 QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
144 expectedException.expect(BadRequestException.class);
145 expectedException.expectMessage("'80' is not a valid rating");
147 underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "GT", null, "80");
151 public void fail_to_create_condition_on_greater_than_E() {
152 MetricDto metric = db.measures().insertMetric(m -> m.setKey(SQALE_RATING_KEY).setValueType(RATING.name()).setHidden(false));
153 QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
155 expectedException.expect(BadRequestException.class);
156 expectedException.expectMessage("There's no worse rating than E (5)");
158 underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "GT", "5", null);
162 @UseDataProvider("valid_values")
163 public void create_warning_condition(Metric.ValueType valueType, String value) {
164 MetricDto metric = db.measures().insertMetric(m -> m.setValueType(valueType.name()).setHidden(false));
165 QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
167 QualityGateConditionDto result = underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "EQ", value, null);
169 verifyCondition(result, qualityGate, metric, "EQ", value, null);
173 @UseDataProvider("valid_values")
174 public void create_error_condition(Metric.ValueType valueType, String value) {
175 MetricDto metric = db.measures().insertMetric(m -> m.setValueType(valueType.name()).setHidden(false));
176 QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
178 QualityGateConditionDto result = underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "EQ", null, value);
180 verifyCondition(result, qualityGate, metric, "EQ", null, value);
184 @UseDataProvider("invalid_values")
185 public void fail_to_create_warning_INT_condition_when_value_is_not_an_integer(Metric.ValueType valueType, String value) {
186 MetricDto metric = db.measures().insertMetric(m -> m.setValueType(valueType.name()).setHidden(false));
187 QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
189 expectedException.expect(BadRequestException.class);
190 expectedException.expectMessage(format("Invalid value '%s' for metric '%s'", value, metric.getShortName()));
192 underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "EQ", value, null);
196 @UseDataProvider("invalid_values")
197 public void fail_to_create_error_INT_condition_when_value_is_not_an_integer(Metric.ValueType valueType, String value) {
198 MetricDto metric = db.measures().insertMetric(m -> m.setValueType(valueType.name()).setHidden(false));
199 QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
201 expectedException.expect(BadRequestException.class);
202 expectedException.expectMessage(format("Invalid value '%s' for metric '%s'", value, metric.getShortName()));
204 underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "EQ", null, value);
208 public void update_condition() {
209 MetricDto metric = db.measures().insertMetric(m -> m.setValueType(PERCENT.name()).setHidden(false));
210 QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
211 QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric,
212 c -> c.setOperator("LT").setWarningThreshold(null).setErrorThreshold("80"));
214 QualityGateConditionDto result = underTest.updateCondition(db.getSession(), condition, metric.getKey(), "GT", "60", null);
216 verifyCondition(result, qualityGate, metric, "GT", "60", null);
220 public void update_condition_on_rating_metric() {
221 MetricDto metric = db.measures().insertMetric(m -> m.setKey(SQALE_RATING_KEY).setValueType(RATING.name()).setHidden(false));
222 QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
223 QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric,
224 c -> c.setOperator("LT").setWarningThreshold("80").setErrorThreshold(null));
226 QualityGateConditionDto result = underTest.updateCondition(db.getSession(), condition, metric.getKey(), "GT", "4", null);
228 verifyCondition(result, qualityGate, metric, "GT", "4", null);
232 public void fail_to_update_condition_on_rating_metric_on_not_core_rating_metric() {
233 MetricDto metric = db.measures().insertMetric(m -> m.setKey("not_core_rating_metric").setValueType(RATING.name()).setHidden(false));
234 QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
235 QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric,
236 c -> c.setOperator("LT").setWarningThreshold(null).setErrorThreshold("3"));
238 expectedException.expect(BadRequestException.class);
239 expectedException.expectMessage(format("The metric '%s' cannot be used", metric.getShortName()));
241 underTest.updateCondition(db.getSession(), condition, metric.getKey(), "GT", "4", null);
245 @UseDataProvider("invalid_metrics")
246 public void fail_to_update_condition_on_invalid_metric(String metricKey, Metric.ValueType valueType, boolean hidden) {
247 MetricDto metric = db.measures().insertMetric(m -> m.setKey(metricKey).setValueType(valueType.name()).setHidden(hidden));
248 QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
249 QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric,
250 c -> c.setOperator("LT").setWarningThreshold(null).setErrorThreshold("80"));
252 expectedException.expect(BadRequestException.class);
253 expectedException.expectMessage(format("Metric '%s' cannot be used to define a condition.", metric.getKey()));
255 underTest.updateCondition(db.getSession(), condition, metric.getKey(), "GT", "60", null);
259 @UseDataProvider("valid_values")
260 public void update_warning_condition(Metric.ValueType valueType, String value) {
261 MetricDto metric = db.measures().insertMetric(m -> m.setValueType(valueType.name()).setHidden(false));
262 QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
263 QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric,
264 c -> c.setOperator("LT").setWarningThreshold(null).setErrorThreshold("80"));
266 QualityGateConditionDto result = underTest.updateCondition(db.getSession(), condition, metric.getKey(), "EQ", value, null);
268 verifyCondition(result, qualityGate, metric, "EQ", value, null);
272 @UseDataProvider("valid_values")
273 public void update_error_condition(Metric.ValueType valueType, String value) {
274 MetricDto metric = db.measures().insertMetric(m -> m.setValueType(valueType.name()).setHidden(false));
275 QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
276 QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric,
277 c -> c.setOperator("LT").setWarningThreshold(null).setErrorThreshold("80"));
279 QualityGateConditionDto result = underTest.updateCondition(db.getSession(), condition, metric.getKey(), "EQ", null, value);
281 verifyCondition(result, qualityGate, metric, "EQ", null, value);
285 @UseDataProvider("invalid_values")
286 public void fail_to_update_warning_INT_condition_when_value_is_not_an_integer(Metric.ValueType valueType, String value) {
287 MetricDto metric = db.measures().insertMetric(m -> m.setValueType(valueType.name()).setHidden(false));
288 QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
289 QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric,
290 c -> c.setOperator("LT").setWarningThreshold(null).setErrorThreshold("80"));
292 expectedException.expect(BadRequestException.class);
293 expectedException.expectMessage(format("Invalid value '%s' for metric '%s'", value, metric.getShortName()));
295 underTest.updateCondition(db.getSession(), condition, metric.getKey(), "EQ", value, null);
299 @UseDataProvider("invalid_values")
300 public void fail_to_update_error_INT_condition_when_value_is_not_an_integer(Metric.ValueType valueType, String value) {
301 MetricDto metric = db.measures().insertMetric(m -> m.setValueType(valueType.name()).setHidden(false));
302 QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
303 QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric,
304 c -> c.setOperator("LT").setWarningThreshold(null).setErrorThreshold("80"));
306 expectedException.expect(BadRequestException.class);
307 expectedException.expectMessage(format("Invalid value '%s' for metric '%s'", value, metric.getShortName()));
309 underTest.updateCondition(db.getSession(), condition, metric.getKey(), "EQ", null, value);
313 public static Object[][] invalid_metrics() {
314 return new Object[][] {
315 {ALERT_STATUS_KEY, INT, false},
316 {"data_metric", DATA, false},
317 {"hidden", INT, true}
322 public static Object[][] valid_values() {
323 return new Object[][] {
334 public static Object[][] invalid_values() {
335 return new Object[][] {
345 private void verifyCondition(QualityGateConditionDto dto, QualityGateDto qualityGate, MetricDto metric, String operator, @Nullable String warning, @Nullable String error) {
346 QualityGateConditionDto reloaded = db.getDbClient().gateConditionDao().selectById(dto.getId(), db.getSession());
347 assertThat(reloaded.getQualityGateId()).isEqualTo(qualityGate.getId());
348 assertThat(reloaded.getMetricId()).isEqualTo(metric.getId().longValue());
349 assertThat(reloaded.getOperator()).isEqualTo(operator);
350 assertThat(reloaded.getWarningThreshold()).isEqualTo(warning);
351 assertThat(reloaded.getErrorThreshold()).isEqualTo(error);
353 assertThat(dto.getQualityGateId()).isEqualTo(qualityGate.getId());
354 assertThat(dto.getMetricId()).isEqualTo(metric.getId().longValue());
355 assertThat(dto.getOperator()).isEqualTo(operator);
356 assertThat(dto.getWarningThreshold()).isEqualTo(warning);
357 assertThat(dto.getErrorThreshold()).isEqualTo(error);