3 * Copyright (C) 2009-2016 SonarSource SA
4 * mailto:contact 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.
21 package org.sonar.server.qualitygate;
23 import com.tngtech.java.junit.dataprovider.DataProvider;
24 import com.tngtech.java.junit.dataprovider.DataProviderRunner;
25 import com.tngtech.java.junit.dataprovider.UseDataProvider;
26 import javax.annotation.Nullable;
27 import org.junit.Before;
28 import org.junit.Rule;
29 import org.junit.Test;
30 import org.junit.rules.ExpectedException;
31 import org.junit.runner.RunWith;
32 import org.sonar.api.measures.Metric;
33 import org.sonar.api.utils.System2;
34 import org.sonar.db.DbClient;
35 import org.sonar.db.DbSession;
36 import org.sonar.db.DbTester;
37 import org.sonar.db.metric.MetricDto;
38 import org.sonar.db.qualitygate.QualityGateConditionDto;
39 import org.sonar.db.qualitygate.QualityGateDbTester;
40 import org.sonar.db.qualitygate.QualityGateDto;
41 import org.sonar.server.exceptions.BadRequestException;
42 import org.sonar.server.exceptions.NotFoundException;
44 import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
45 import static org.sonar.api.measures.CoreMetrics.ALERT_STATUS_KEY;
46 import static org.sonar.api.measures.Metric.ValueType.DATA;
47 import static org.sonar.api.measures.Metric.ValueType.INT;
48 import static org.sonar.api.measures.Metric.ValueType.RATING;
49 import static org.sonar.db.metric.MetricTesting.newMetricDto;
50 import static org.sonar.server.computation.task.projectanalysis.metric.Metric.MetricType.PERCENT;
52 @RunWith(DataProviderRunner.class)
53 public class QualityGateConditionsUpdaterTest {
56 public ExpectedException expectedException = ExpectedException.none();
59 public DbTester db = DbTester.create(System2.INSTANCE);
61 DbClient dbClient = db.getDbClient();
62 DbSession dbSession = db.getSession();
63 QualityGateDbTester qualityGateDbTester = new QualityGateDbTester(db);
65 QualityGateDto qualityGateDto;
66 MetricDto coverageMetricDto = newMetricDto()
68 .setShortName("Coverage")
69 .setValueType(PERCENT.name())
72 MetricDto ratingMetricDto = newMetricDto()
73 .setKey("rating_metric")
74 .setShortName("Rating")
75 .setValueType(RATING.name())
78 QualityGateConditionsUpdater underTest = new QualityGateConditionsUpdater(dbClient);
81 public void setUp() throws Exception {
82 qualityGateDto = qualityGateDbTester.insertQualityGate();
83 dbClient.metricDao().insert(dbSession, coverageMetricDto, ratingMetricDto);
88 public void create_warning_condition_without_period() {
89 QualityGateConditionDto result = underTest.createCondition(dbSession, qualityGateDto.getId(), "coverage", "LT", "90", null, null);
91 verifyCondition(result, coverageMetricDto.getId(), "LT", "90", null, null);
95 public void create_error_condition_with_period() {
96 MetricDto metricDto = dbClient.metricDao().insert(dbSession, newMetricDto()
97 .setKey("new_coverage")
98 .setValueType(INT.name())
102 QualityGateConditionDto result = underTest.createCondition(dbSession, qualityGateDto.getId(), "new_coverage", "LT", null, "80", 1);
104 verifyCondition(result, metricDto.getId(), "LT", null, "80", 1);
108 public void fail_to_create_condition_when_condition_on_same_metric_already_exist() throws Exception {
109 dbClient.gateConditionDao().insert(new QualityGateConditionDto()
110 .setQualityGateId(qualityGateDto.getId())
111 .setMetricId(coverageMetricDto.getId())
115 expectedException.expect(BadRequestException.class);
116 expectedException.expectMessage("Condition on metric 'Coverage' already exists.");
117 underTest.createCondition(dbSession, qualityGateDto.getId(), coverageMetricDto.getKey(), "LT", "90", null, null);
121 public void fail_to_create_condition_when_condition_on_same_metric_and_on_leak_period_already_exist() throws Exception {
122 dbClient.gateConditionDao().insert(new QualityGateConditionDto()
123 .setQualityGateId(qualityGateDto.getId())
124 .setMetricId(coverageMetricDto.getId())
128 expectedException.expect(BadRequestException.class);
129 expectedException.expectMessage("Condition on metric 'Coverage' over leak period already exists.");
130 underTest.createCondition(dbSession, qualityGateDto.getId(), coverageMetricDto.getKey(), "LT", "90", null, 1);
134 public void fail_to_create_condition_on_missing_metric() {
135 expectedException.expect(NotFoundException.class);
136 expectedException.expectMessage("There is no metric with key=new_coverage");
137 underTest.createCondition(dbSession, qualityGateDto.getId(), "new_coverage", "LT", null, "80", 2);
141 @UseDataProvider("invalid_metrics")
142 public void fail_to_create_condition_on_invalid_metric(String metricKey, Metric.ValueType valueType, boolean hidden) {
143 dbClient.metricDao().insert(dbSession, newMetricDto()
145 .setValueType(valueType.name())
149 expectedException.expect(BadRequestException.class);
150 expectedException.expectMessage("Metric '" + metricKey + "' cannot be used to define a condition.");
151 underTest.createCondition(dbSession, qualityGateDto.getId(), metricKey, "EQ", null, "80", null);
155 public void fail_to_create_condition_on_not_allowed_operator() {
156 expectedException.expect(BadRequestException.class);
157 expectedException.expectMessage("Operator UNKNOWN is not allowed for metric type PERCENT.");
158 underTest.createCondition(dbSession, qualityGateDto.getId(), "coverage", "UNKNOWN", null, "80", 2);
162 public void fail_to_create_condition_on_missing_period() {
163 dbClient.metricDao().insert(dbSession, newMetricDto()
164 .setKey("new_coverage")
165 .setValueType(INT.name())
169 expectedException.expect(BadRequestException.class);
170 expectedException.expectMessage("A period must be selected for differential metrics.");
171 underTest.createCondition(dbSession, qualityGateDto.getId(), "new_coverage", "EQ", null, "90", null);
175 public void fail_to_create_condition_on_invalid_period() {
176 expectedException.expect(BadRequestException.class);
177 expectedException.expectMessage("The only valid quality gate period is 1, the leak period.");
178 underTest.createCondition(dbSession, qualityGateDto.getId(), "coverage", "EQ", null, "90", 6);
182 public void create_condition_on_rating_metric() {
183 QualityGateConditionDto result = underTest.createCondition(dbSession, qualityGateDto.getId(), "rating_metric", "GT", null, "3", null);
185 verifyCondition(result, ratingMetricDto.getId(), "GT", null, "3", null);
189 public void fail_to_create_condition_on_rating_metric_on_leak_period() {
190 expectedException.expect(BadRequestException.class);
191 expectedException.expectMessage("The metric 'Rating' cannot be used on the leak period");
192 underTest.createCondition(dbSession, qualityGateDto.getId(), "rating_metric", "GT", null, "3", 1);
196 public void fail_to_create_warning_condition_on_invalid_rating_metric() {
197 expectedException.expect(BadRequestException.class);
198 expectedException.expectMessage("'6' is not a valid rating");
199 underTest.createCondition(dbSession, qualityGateDto.getId(), ratingMetricDto.getKey(), "GT", "6", null, null);
203 public void fail_to_create_error_condition_on_invalid_rating_metric() {
204 expectedException.expect(BadRequestException.class);
205 expectedException.expectMessage("'80' is not a valid rating");
206 underTest.createCondition(dbSession, qualityGateDto.getId(), ratingMetricDto.getKey(), "GT", null, "80", null);
210 public void fail_to_create_condition_on_greater_than_E() {
211 expectedException.expect(BadRequestException.class);
212 expectedException.expectMessage("There's no worse rating than E (5)");
213 underTest.createCondition(dbSession, qualityGateDto.getId(), ratingMetricDto.getKey(), "GT", "5", null, null);
217 public void update_condition() {
218 QualityGateConditionDto condition = insertCondition(coverageMetricDto.getId(), "LT", null, "80", null);
220 QualityGateConditionDto result = underTest.updateCondition(dbSession, condition.getId(), "coverage", "GT", "60", null, 1);
222 verifyCondition(result, coverageMetricDto.getId(), "GT", "60", null, 1);
226 public void update_condition_over_leak_period() {
227 QualityGateConditionDto condition = insertCondition(coverageMetricDto.getId(), "GT", "80", null, 1);
229 QualityGateConditionDto result = underTest.updateCondition(dbSession, condition.getId(), "coverage", "LT", null, "80", null);
231 verifyCondition(result, coverageMetricDto.getId(), "LT", null, "80", null);
235 public void update_condition_on_rating_metric() {
236 QualityGateConditionDto condition = insertCondition(ratingMetricDto.getId(), "LT", null, "3", null);
238 QualityGateConditionDto result = underTest.updateCondition(dbSession, condition.getId(), "rating_metric", "GT", "4", null, null);
240 verifyCondition(result, ratingMetricDto.getId(), "GT", "4", null, null);
244 public void fail_to_update_condition_on_rating_metric_on_leak_period() {
245 QualityGateConditionDto condition = insertCondition(ratingMetricDto.getId(), "LT", null, "3", null);
247 expectedException.expect(BadRequestException.class);
248 expectedException.expectMessage("The metric 'Rating' cannot be used on the leak period");
249 underTest.updateCondition(dbSession, condition.getId(), "rating_metric", "GT", "4", null, 1);
253 @UseDataProvider("invalid_metrics")
254 public void fail_to_update_condition_on_invalid_metric(String metricKey, Metric.ValueType valueType, boolean hidden) {
255 MetricDto metricDto = dbClient.metricDao().insert(dbSession, newMetricDto()
257 .setValueType(valueType.name())
259 QualityGateConditionDto condition = insertCondition(metricDto.getId(), "LT", null, "80", null);
262 expectedException.expect(BadRequestException.class);
263 expectedException.expectMessage("Metric '" + metricKey + "' cannot be used to define a condition.");
264 underTest.updateCondition(dbSession, condition.getId(), metricDto.getKey(), "GT", "60", null, 1);
268 public void fail_to_update_condition_when_condition_on_same_metric_already_exist() throws Exception {
269 QualityGateConditionDto conditionNotOnLeakPeriod = insertCondition(coverageMetricDto.getId(), "GT", "80", null, null);
270 QualityGateConditionDto conditionOnLeakPeriod = insertCondition(coverageMetricDto.getId(), "GT", "80", null, 1);
272 expectedException.expect(BadRequestException.class);
273 expectedException.expectMessage("Condition on metric 'Coverage' over leak period already exists.");
274 // Update condition not on leak period to be on leak period => will fail as this condition already exist
275 underTest.updateCondition(dbSession, conditionNotOnLeakPeriod.getId(), coverageMetricDto.getKey(), "GT", "80", null, 1);
279 public static Object[][] invalid_metrics() {
280 return new Object[][] {
281 {ALERT_STATUS_KEY, INT, false},
282 {"data_metric", DATA, false},
283 {"hidden", INT, true}
287 private QualityGateConditionDto insertCondition(long metricId, String operator, @Nullable String warning, @Nullable String error,
288 @Nullable Integer period) {
289 QualityGateConditionDto qualityGateConditionDto = new QualityGateConditionDto().setQualityGateId(qualityGateDto.getId())
290 .setMetricId(metricId)
291 .setOperator(operator)
292 .setWarningThreshold(warning)
293 .setErrorThreshold(error)
295 dbClient.gateConditionDao().insert(qualityGateConditionDto, dbSession);
297 return qualityGateConditionDto;
300 private void verifyCondition(QualityGateConditionDto dto, int metricId, String operator, @Nullable String warning, @Nullable String error, @Nullable Integer period) {
301 QualityGateConditionDto reloaded = dbClient.gateConditionDao().selectById(dto.getId(), dbSession);
302 assertThat(reloaded.getQualityGateId()).isEqualTo(qualityGateDto.getId());
303 assertThat(reloaded.getMetricId()).isEqualTo(metricId);
304 assertThat(reloaded.getOperator()).isEqualTo(operator);
305 assertThat(reloaded.getWarningThreshold()).isEqualTo(warning);
306 assertThat(reloaded.getErrorThreshold()).isEqualTo(error);
307 assertThat(reloaded.getPeriod()).isEqualTo(period);
309 assertThat(dto.getQualityGateId()).isEqualTo(qualityGateDto.getId());
310 assertThat(dto.getMetricId()).isEqualTo(metricId);
311 assertThat(dto.getOperator()).isEqualTo(operator);
312 assertThat(dto.getWarningThreshold()).isEqualTo(warning);
313 assertThat(dto.getErrorThreshold()).isEqualTo(error);
314 assertThat(dto.getPeriod()).isEqualTo(period);