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", "80");
70 verifyCondition(result, qualityGate, metric, "LT", "80");
74 public void create_condition_throws_NPE_if_errorThreshold_is_null() {
75 MetricDto metric = db.measures().insertMetric(m -> m.setKey(SQALE_RATING_KEY).setValueType(RATING.name()).setHidden(false));
76 QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
78 expectedException.expect(NullPointerException.class);
79 expectedException.expectMessage("errorThreshold can not be null");
81 underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "GT", null);
85 public void fail_to_create_condition_when_condition_on_same_metric_already_exist() {
86 MetricDto metric = db.measures().insertMetric(m -> m.setValueType(PERCENT.name()).setHidden(false));
87 QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
88 db.qualityGates().addCondition(qualityGate, metric);
90 expectedException.expect(BadRequestException.class);
91 expectedException.expectMessage(format("Condition on metric '%s' already exists.", metric.getShortName()));
93 underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "LT", "90");
97 public void fail_to_create_condition_on_missing_metric() {
98 QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
100 expectedException.expect(NotFoundException.class);
101 expectedException.expectMessage("There is no metric with key=new_coverage");
103 underTest.createCondition(db.getSession(), qualityGate, "new_coverage", "LT", "80");
107 @UseDataProvider("invalid_metrics")
108 public void fail_to_create_condition_on_invalid_metric(String metricKey, Metric.ValueType valueType, boolean hidden) {
109 MetricDto metric = db.measures().insertMetric(m -> m.setKey(metricKey).setValueType(valueType.name()).setHidden(hidden));
110 QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
112 expectedException.expect(BadRequestException.class);
113 expectedException.expectMessage(format("Metric '%s' cannot be used to define a condition.", metric.getKey()));
115 underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "EQ", "80");
119 public void fail_to_create_condition_on_not_allowed_operator() {
120 MetricDto metric = db.measures().insertMetric(m -> m.setValueType(PERCENT.name()).setHidden(false));
121 QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
123 expectedException.expect(BadRequestException.class);
124 expectedException.expectMessage("Operator UNKNOWN is not allowed for metric type PERCENT.");
126 underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "UNKNOWN", "90");
130 public void create_condition_on_rating_metric() {
131 MetricDto metric = db.measures().insertMetric(m -> m.setKey(SQALE_RATING_KEY).setValueType(RATING.name()).setHidden(false));
132 QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
134 QualityGateConditionDto result = underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "GT", "3");
136 verifyCondition(result, qualityGate, metric, "GT", "3");
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", "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");
162 @UseDataProvider("valid_values")
163 public void create_error_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);
169 verifyCondition(result, qualityGate, metric, "EQ", value);
173 @UseDataProvider("invalid_values")
174 public void fail_to_create_error_INT_condition_when_value_is_not_an_integer(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 expectedException.expect(BadRequestException.class);
179 expectedException.expectMessage(format("Invalid value '%s' for metric '%s'", value, metric.getShortName()));
181 underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "EQ", value);
185 public void update_condition() {
186 MetricDto metric = db.measures().insertMetric(m -> m.setValueType(PERCENT.name()).setHidden(false));
187 QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
188 QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric,
189 c -> c.setOperator("LT").setErrorThreshold("80"));
191 QualityGateConditionDto result = underTest.updateCondition(db.getSession(), condition, metric.getKey(), "LT", "80");
193 verifyCondition(result, qualityGate, metric, "LT", "80");
197 public void update_condition_throws_NPE_if_errorThreshold_is_null() {
198 MetricDto metric = db.measures().insertMetric(m -> m.setValueType(PERCENT.name()).setHidden(false));
199 QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
200 QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric,
201 c -> c.setOperator("LT").setErrorThreshold("80"));
203 expectedException.expect(NullPointerException.class);
204 expectedException.expectMessage("errorThreshold can not be null");
206 underTest.updateCondition(db.getSession(), condition, metric.getKey(), "GT", null);
210 public void update_condition_on_rating_metric() {
211 MetricDto metric = db.measures().insertMetric(m -> m.setKey(SQALE_RATING_KEY).setValueType(RATING.name()).setHidden(false));
212 QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
213 QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric,
214 c -> c.setOperator("LT").setErrorThreshold("80"));
216 QualityGateConditionDto result = underTest.updateCondition(db.getSession(), condition, metric.getKey(), "GT", "4");
218 verifyCondition(result, qualityGate, metric, "GT", "4");
222 public void fail_to_update_condition_on_rating_metric_on_not_core_rating_metric() {
223 MetricDto metric = db.measures().insertMetric(m -> m.setKey("not_core_rating_metric").setValueType(RATING.name()).setHidden(false));
224 QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
225 QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric,
226 c -> c.setOperator("LT").setErrorThreshold("3"));
228 expectedException.expect(BadRequestException.class);
229 expectedException.expectMessage(format("The metric '%s' cannot be used", metric.getShortName()));
231 underTest.updateCondition(db.getSession(), condition, metric.getKey(), "GT", "4");
235 @UseDataProvider("invalid_metrics")
236 public void fail_to_update_condition_on_invalid_metric(String metricKey, Metric.ValueType valueType, boolean hidden) {
237 MetricDto metric = db.measures().insertMetric(m -> m.setKey(metricKey).setValueType(valueType.name()).setHidden(hidden));
238 QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
239 QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric,
240 c -> c.setOperator("LT").setErrorThreshold("80"));
242 expectedException.expect(BadRequestException.class);
243 expectedException.expectMessage(format("Metric '%s' cannot be used to define a condition.", metric.getKey()));
245 underTest.updateCondition(db.getSession(), condition, metric.getKey(), "GT", "60");
249 @UseDataProvider("valid_values")
250 public void update_error_condition(Metric.ValueType valueType, String value) {
251 MetricDto metric = db.measures().insertMetric(m -> m.setValueType(valueType.name()).setHidden(false));
252 QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
253 QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric,
254 c -> c.setOperator("LT").setErrorThreshold("80"));
256 QualityGateConditionDto result = underTest.updateCondition(db.getSession(), condition, metric.getKey(), "EQ", value);
258 verifyCondition(result, qualityGate, metric, "EQ", value);
262 @UseDataProvider("invalid_values")
263 public void fail_to_update_error_INT_condition_when_value_is_not_an_integer(Metric.ValueType valueType, String value) {
264 MetricDto metric = db.measures().insertMetric(m -> m.setValueType(valueType.name()).setHidden(false));
265 QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
266 QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric,
267 c -> c.setOperator("LT").setErrorThreshold("80"));
269 expectedException.expect(BadRequestException.class);
270 expectedException.expectMessage(format("Invalid value '%s' for metric '%s'", value, metric.getShortName()));
272 underTest.updateCondition(db.getSession(), condition, metric.getKey(), "EQ", value);
276 public static Object[][] invalid_metrics() {
277 return new Object[][] {
278 {ALERT_STATUS_KEY, INT, false},
279 {"data_metric", DATA, false},
280 {"hidden", INT, true}
285 public static Object[][] valid_values() {
286 return new Object[][] {
297 public static Object[][] invalid_values() {
298 return new Object[][] {
308 private void verifyCondition(QualityGateConditionDto dto, QualityGateDto qualityGate, MetricDto metric, String operator, String error) {
309 QualityGateConditionDto reloaded = db.getDbClient().gateConditionDao().selectById(dto.getId(), db.getSession());
310 assertThat(reloaded.getQualityGateId()).isEqualTo(qualityGate.getId());
311 assertThat(reloaded.getMetricId()).isEqualTo(metric.getId().longValue());
312 assertThat(reloaded.getOperator()).isEqualTo(operator);
313 assertThat(reloaded.getErrorThreshold()).isEqualTo(error);
315 assertThat(dto.getQualityGateId()).isEqualTo(qualityGate.getId());
316 assertThat(dto.getMetricId()).isEqualTo(metric.getId().longValue());
317 assertThat(dto.getOperator()).isEqualTo(operator);
318 assertThat(dto.getErrorThreshold()).isEqualTo(error);