]> source.dussan.org Git - sonarqube.git/blob
d9c67647ab1f02d7036b79ccad2606e0b4f70000
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2019 SonarSource SA
4  * mailto:info AT sonarsource DOT com
5  *
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.
10  *
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.
15  *
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.
19  */
20 package org.sonar.server.qualitygate;
21
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 org.junit.Rule;
26 import org.junit.Test;
27 import org.junit.rules.ExpectedException;
28 import org.junit.runner.RunWith;
29 import org.sonar.api.measures.Metric;
30 import org.sonar.api.utils.System2;
31 import org.sonar.db.DbTester;
32 import org.sonar.db.metric.MetricDto;
33 import org.sonar.db.qualitygate.QualityGateConditionDto;
34 import org.sonar.db.qualitygate.QualityGateDto;
35 import org.sonar.server.exceptions.BadRequestException;
36 import org.sonar.server.exceptions.NotFoundException;
37
38 import static java.lang.String.format;
39 import static java.lang.String.valueOf;
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.DISTRIB;
46 import static org.sonar.api.measures.Metric.ValueType.FLOAT;
47 import static org.sonar.api.measures.Metric.ValueType.INT;
48 import static org.sonar.api.measures.Metric.ValueType.MILLISEC;
49 import static org.sonar.api.measures.Metric.ValueType.PERCENT;
50 import static org.sonar.api.measures.Metric.ValueType.RATING;
51 import static org.sonar.api.measures.Metric.ValueType.STRING;
52 import static org.sonar.api.measures.Metric.ValueType.WORK_DUR;
53
54 @RunWith(DataProviderRunner.class)
55 public class QualityGateConditionsUpdaterTest {
56
57   @Rule
58   public ExpectedException expectedException = ExpectedException.none();
59
60   @Rule
61   public DbTester db = DbTester.create(System2.INSTANCE);
62
63   private QualityGateConditionsUpdater underTest = new QualityGateConditionsUpdater(db.getDbClient());
64
65   @Test
66   public void create_error_condition() {
67     MetricDto metric = insertMetric(INT, "new_coverage");
68     QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
69
70     QualityGateConditionDto result = underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "LT", "80");
71
72     verifyCondition(result, qualityGate, metric, "LT", "80");
73   }
74
75   @Test
76   @UseDataProvider("valid_operators_and_direction")
77   public void create_condition_with_valid_operators_and_direction(String operator, int direction) {
78     MetricDto metric = db.measures().insertMetric(m -> m.setKey("key").setValueType(INT.name()).setHidden(false).setDirection(direction));
79     QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
80
81     QualityGateConditionDto result = underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), operator, "80");
82
83     verifyCondition(result, qualityGate, metric, operator, "80");
84   }
85
86   @Test
87   public void create_condition_throws_NPE_if_errorThreshold_is_null() {
88     MetricDto metric = insertMetric(RATING, SQALE_RATING_KEY);
89     QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
90
91     expectedException.expect(NullPointerException.class);
92     expectedException.expectMessage("errorThreshold can not be null");
93
94     underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "GT", null);
95   }
96
97   @Test
98   public void fail_to_create_condition_when_condition_on_same_metric_already_exist() {
99     MetricDto metric = insertMetric(PERCENT);
100     QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
101     db.qualityGates().addCondition(qualityGate, metric);
102
103     expectedException.expect(BadRequestException.class);
104     expectedException.expectMessage(format("Condition on metric '%s' already exists.", metric.getShortName()));
105
106     underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "LT", "80");
107   }
108
109   @Test
110   public void fail_to_create_condition_on_missing_metric() {
111     QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
112
113     expectedException.expect(NotFoundException.class);
114     expectedException.expectMessage("There is no metric with key=new_coverage");
115
116     underTest.createCondition(db.getSession(), qualityGate, "new_coverage", "LT", "80");
117   }
118
119   @Test
120   @UseDataProvider("invalid_metrics")
121   public void fail_to_create_condition_on_invalid_metric(String metricKey, Metric.ValueType valueType, boolean hidden) {
122     MetricDto metric = db.measures().insertMetric(m -> m.setKey(metricKey).setValueType(valueType.name()).setHidden(hidden).setDirection(0));
123     QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
124
125     expectedException.expect(BadRequestException.class);
126     expectedException.expectMessage(format("Metric '%s' cannot be used to define a condition", metric.getKey()));
127
128     underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "LT", "80");
129   }
130
131   @Test
132   @UseDataProvider("invalid_operators_and_direction")
133   public void fail_to_create_condition_on_not_allowed_operator_for_metric_direction(String operator, int direction) {
134     MetricDto metric = db.measures().insertMetric(m -> m.setKey("key").setValueType(INT.name()).setHidden(false).setDirection(direction));
135     QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
136
137     expectedException.expect(BadRequestException.class);
138     expectedException.expectMessage(format("Operator %s is not allowed for this metric.", operator));
139
140     underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), operator, "90");
141   }
142
143   @Test
144   public void create_condition_on_rating_metric() {
145     MetricDto metric = insertMetric(RATING, SQALE_RATING_KEY);
146     QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
147
148     QualityGateConditionDto result = underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "GT", "3");
149
150     verifyCondition(result, qualityGate, metric, "GT", "3");
151   }
152
153   @Test
154   public void fail_to_create_error_condition_on_invalid_rating_metric() {
155     MetricDto metric = insertMetric(RATING, SQALE_RATING_KEY);
156     QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
157
158     expectedException.expect(BadRequestException.class);
159     expectedException.expectMessage("'80' is not a valid rating");
160
161     underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "GT", "80");
162   }
163
164   @Test
165   public void fail_to_create_condition_on_greater_than_E() {
166     MetricDto metric = insertMetric(RATING, SQALE_RATING_KEY);
167     QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
168
169     expectedException.expect(BadRequestException.class);
170     expectedException.expectMessage("There's no worse rating than E (5)");
171
172     underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "GT", "5");
173   }
174
175   @Test
176   @UseDataProvider("valid_values")
177   public void create_error_condition(Metric.ValueType valueType, String value) {
178     MetricDto metric = db.measures().insertMetric(m -> m.setValueType(valueType.name()).setHidden(false).setDirection(0));
179     QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
180
181     QualityGateConditionDto result = underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "LT", value);
182
183     verifyCondition(result, qualityGate, metric, "LT", value);
184   }
185
186   @Test
187   @UseDataProvider("invalid_values")
188   public void fail_to_create_error_INT_condition_when_value_is_not_an_integer(Metric.ValueType valueType, String value) {
189     MetricDto metric = db.measures().insertMetric(m -> m.setValueType(valueType.name()).setHidden(false).setDirection(0));
190     QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
191
192     expectedException.expect(BadRequestException.class);
193     expectedException.expectMessage(format("Invalid value '%s' for metric '%s'", value, metric.getShortName()));
194
195     underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "LT", value);
196   }
197
198   @Test
199   public void update_condition() {
200     MetricDto metric = insertMetric(PERCENT);
201     QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
202     QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric,
203       c -> c.setOperator("LT").setErrorThreshold("80"));
204
205     QualityGateConditionDto result = underTest.updateCondition(db.getSession(), condition, metric.getKey(), "LT", "80");
206
207     verifyCondition(result, qualityGate, metric, "LT", "80");
208   }
209
210   @Test
211   public void update_condition_throws_NPE_if_errorThreshold_is_null() {
212     MetricDto metric = insertMetric(PERCENT);
213     QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
214     QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric,
215       c -> c.setOperator("LT").setErrorThreshold("80"));
216
217     expectedException.expect(NullPointerException.class);
218     expectedException.expectMessage("errorThreshold can not be null");
219
220     underTest.updateCondition(db.getSession(), condition, metric.getKey(), "GT", null);
221   }
222
223   @Test
224   public void update_condition_on_rating_metric() {
225     MetricDto metric = insertMetric(RATING, SQALE_RATING_KEY);
226     QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
227     QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric,
228       c -> c.setOperator("LT").setErrorThreshold("80"));
229
230     QualityGateConditionDto result = underTest.updateCondition(db.getSession(), condition, metric.getKey(), "GT", "4");
231
232     verifyCondition(result, qualityGate, metric, "GT", "4");
233   }
234
235   @Test
236   @UseDataProvider("update_invalid_operators_and_direction")
237   public void fail_to_update_condition_on_not_allowed_operator_for_metric_direction(String validOperator, String updatedOperator, int direction) {
238     MetricDto metric = db.measures().insertMetric(m -> m.setValueType(PERCENT.name()).setHidden(false).setDirection(direction));
239     QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
240     QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric,
241       c -> c.setOperator(validOperator).setErrorThreshold("80"));
242
243     expectedException.expect(BadRequestException.class);
244     expectedException.expectMessage(format("Operator %s is not allowed for this metric", updatedOperator));
245
246     underTest.updateCondition(db.getSession(), condition, metric.getKey(), updatedOperator, "70");
247   }
248
249   @Test
250   public void fail_to_update_condition_on_rating_metric_on_leak_period() {
251     MetricDto metric = insertMetric(RATING, SQALE_RATING_KEY);
252     QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
253     QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric,
254       c -> c.setOperator("LT").setErrorThreshold("3"));
255
256     QualityGateConditionDto result = underTest.updateCondition(db.getSession(), condition, metric.getKey(), "GT", "4");
257
258     verifyCondition(result, qualityGate, metric, "GT", "4");
259   }
260
261   @Test
262   public void fail_to_update_condition_on_rating_metric_on_not_core_rating_metric() {
263     MetricDto metric = insertMetric(RATING, "not_core_rating_metric");
264     QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
265     QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric,
266       c -> c.setOperator("LT").setErrorThreshold("3"));
267
268     expectedException.expect(BadRequestException.class);
269     expectedException.expectMessage(format("The metric '%s' cannot be used", metric.getShortName()));
270
271     underTest.updateCondition(db.getSession(), condition, metric.getKey(), "GT", "4");
272   }
273
274   @Test
275   @UseDataProvider("invalid_metrics")
276   public void fail_to_update_condition_on_invalid_metric(String metricKey, Metric.ValueType valueType, boolean hidden) {
277     MetricDto metric = db.measures().insertMetric(m -> m.setKey(metricKey).setValueType(valueType.name()).setHidden(hidden));
278     QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
279     QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric,
280       c -> c.setOperator("LT").setErrorThreshold("80"));
281
282     expectedException.expect(BadRequestException.class);
283     expectedException.expectMessage(format("Metric '%s' cannot be used to define a condition", metric.getKey()));
284
285     underTest.updateCondition(db.getSession(), condition, metric.getKey(), "GT", "60");
286   }
287
288   @Test
289   @UseDataProvider("valid_values")
290   public void update_error_condition(Metric.ValueType valueType, String value) {
291     MetricDto metric = db.measures().insertMetric(m -> m.setValueType(valueType.name()).setHidden(false).setDirection(0));
292     QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
293     QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric,
294       c -> c.setOperator("LT").setErrorThreshold("80"));
295
296     QualityGateConditionDto result = underTest.updateCondition(db.getSession(), condition, metric.getKey(), "LT", value);
297
298     verifyCondition(result, qualityGate, metric, "LT", value);
299   }
300
301   @Test
302   @UseDataProvider("invalid_values")
303   public void fail_to_update_error_INT_condition_when_value_is_not_an_integer(Metric.ValueType valueType, String value) {
304     MetricDto metric = db.measures().insertMetric(m -> m.setValueType(valueType.name()).setHidden(false).setDirection(0));
305     QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
306     QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric,
307       c -> c.setOperator("LT").setErrorThreshold("80"));
308
309     expectedException.expect(BadRequestException.class);
310     expectedException.expectMessage(format("Invalid value '%s' for metric '%s'", value, metric.getShortName()));
311
312     underTest.updateCondition(db.getSession(), condition, metric.getKey(), "LT", value);
313   }
314
315   @DataProvider
316   public static Object[][] invalid_metrics() {
317     return new Object[][] {
318       {ALERT_STATUS_KEY, INT, false},
319       {"boolean", BOOL, false},
320       {"string", STRING, false},
321       {"data_metric", DATA, false},
322       {"distrib", DISTRIB, false},
323       {"hidden", INT, true}
324     };
325   }
326
327   @DataProvider
328   public static Object[][] valid_values() {
329     return new Object[][] {
330       {INT, "10"},
331       {MILLISEC, "1000"},
332       {WORK_DUR, "1000"},
333       {FLOAT, "5.12"},
334       {PERCENT, "10.30"},
335     };
336   }
337
338   @DataProvider
339   public static Object[][] invalid_values() {
340     return new Object[][] {
341       {INT, "ABCD"},
342       {MILLISEC, "ABCD"},
343       {WORK_DUR, "ABCD"},
344       {FLOAT, "ABCD"},
345       {PERCENT, "ABCD"},
346     };
347   }
348
349   @DataProvider
350   public static Object[][] invalid_operators_and_direction() {
351     return new Object[][] {
352       {"EQ", 0},
353       {"NE", 0},
354       {"LT", -1},
355       {"GT", 1},
356     };
357   }
358
359   @DataProvider
360   public static Object[][] update_invalid_operators_and_direction() {
361     return new Object[][] {
362       {"LT", "EQ", 0},
363       {"LT", "NE", 0},
364       {"GT", "LT", -1},
365       {"LT", "GT", 1},
366     };
367   }
368
369   @DataProvider
370   public static Object[][] valid_operators_and_direction() {
371     return new Object[][] {
372       {"LT", 0},
373       {"GT", 0},
374       {"GT", -1},
375       {"LT", 1},
376     };
377   }
378
379   private MetricDto insertMetric(Metric.ValueType type) {
380     return insertMetric(type, "key");
381   }
382
383   private MetricDto insertMetric(Metric.ValueType type, String key) {
384     return db.measures().insertMetric(m -> m
385       .setKey(key)
386       .setValueType(type.name())
387       .setHidden(false)
388       .setDirection(0)
389     );
390   }
391
392   private void verifyCondition(QualityGateConditionDto dto, QualityGateDto qualityGate, MetricDto metric, String operator, String error) {
393     QualityGateConditionDto reloaded = db.getDbClient().gateConditionDao().selectById(dto.getId(), db.getSession());
394     assertThat(reloaded.getQualityGateId()).isEqualTo(qualityGate.getId());
395     assertThat(reloaded.getMetricId()).isEqualTo(metric.getId().longValue());
396     assertThat(reloaded.getOperator()).isEqualTo(operator);
397     assertThat(reloaded.getErrorThreshold()).isEqualTo(error);
398
399     assertThat(dto.getQualityGateId()).isEqualTo(qualityGate.getId());
400     assertThat(dto.getMetricId()).isEqualTo(metric.getId().longValue());
401     assertThat(dto.getOperator()).isEqualTo(operator);
402     assertThat(dto.getErrorThreshold()).isEqualTo(error);
403   }
404
405 }