3 * Copyright (C) 2009-2022 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 java.util.ArrayList;
23 import java.util.Date;
24 import java.util.List;
25 import java.util.Random;
26 import org.junit.Rule;
27 import org.junit.Test;
28 import org.sonar.api.utils.System2;
29 import org.sonar.api.utils.log.LogTester;
30 import org.sonar.api.utils.log.LoggerLevel;
31 import org.sonar.core.util.UuidFactoryFast;
32 import org.sonar.core.util.Uuids;
33 import org.sonar.db.DbClient;
34 import org.sonar.db.DbSession;
35 import org.sonar.db.DbTester;
36 import org.sonar.db.metric.MetricDao;
37 import org.sonar.db.metric.MetricDto;
38 import org.sonar.db.qualitygate.QualityGateConditionDao;
39 import org.sonar.db.qualitygate.QualityGateConditionDto;
40 import org.sonar.db.qualitygate.QualityGateDao;
41 import org.sonar.db.qualitygate.QualityGateDto;
43 import static org.assertj.core.api.Assertions.assertThat;
44 import static org.assertj.core.api.Assertions.tuple;
45 import static org.sonar.api.measures.CoreMetrics.NEW_COVERAGE_KEY;
46 import static org.sonar.api.measures.CoreMetrics.NEW_DUPLICATED_LINES_DENSITY_KEY;
47 import static org.sonar.api.measures.CoreMetrics.NEW_MAINTAINABILITY_RATING_KEY;
48 import static org.sonar.api.measures.CoreMetrics.NEW_RELIABILITY_RATING_KEY;
49 import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED_KEY;
50 import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_RATING_KEY;
51 import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_REMEDIATION_EFFORT_KEY;
52 import static org.sonar.api.measures.Metric.ValueType.INT;
53 import static org.sonar.api.measures.Metric.ValueType.PERCENT;
54 import static org.sonar.db.metric.MetricTesting.newMetricDto;
55 import static org.sonar.db.qualitygate.QualityGateConditionDto.OPERATOR_GREATER_THAN;
56 import static org.sonar.db.qualitygate.QualityGateConditionDto.OPERATOR_LESS_THAN;
58 public class RegisterQualityGatesTest {
61 public DbTester db = DbTester.create(System2.INSTANCE);
63 public LogTester logTester = new LogTester();
65 private static final String BUILT_IN_NAME = "Sonar way";
67 private final DbClient dbClient = db.getDbClient();
68 private final DbSession dbSession = db.getSession();
70 private final QualityGateDao qualityGateDao = dbClient.qualityGateDao();
71 private final QualityGateConditionDao gateConditionDao = dbClient.gateConditionDao();
72 private final MetricDao metricDao = dbClient.metricDao();
73 private final QualityGateConditionsUpdater qualityGateConditionsUpdater = new QualityGateConditionsUpdater(dbClient);
74 private final QualityGateFinder qualityGateFinder = new QualityGateFinder(dbClient);
76 private final RegisterQualityGates underTest = new RegisterQualityGates(dbClient, qualityGateConditionsUpdater,
77 UuidFactoryFast.getInstance(), System2.INSTANCE);
80 public void register_default_gate() {
85 verifyCorrectBuiltInQualityGate();
87 logTester.logs(LoggerLevel.INFO).contains("Built-in quality gate [Sonar way] has been created")).isTrue();
89 logTester.logs(LoggerLevel.INFO).contains("Built-in quality gate's conditions of [Sonar way] has been updated")).isTrue();
93 public void upgrade_empty_quality_gate() {
98 assertThat(db.countRowsOfTable("quality_gates")).isOne();
99 verifyCorrectBuiltInQualityGate();
101 logTester.logs(LoggerLevel.INFO).contains("Built-in quality gate's conditions of [Sonar way] has been updated")).isTrue();
105 public void upgrade_should_remove_deleted_condition() {
107 QualityGateDto builtInQualityGate = db.qualityGates().insertBuiltInQualityGate();
108 createBuiltInConditions(builtInQualityGate);
109 // Add another condition
110 qualityGateConditionsUpdater.createCondition(dbSession, builtInQualityGate,
111 NEW_SECURITY_REMEDIATION_EFFORT_KEY, OPERATOR_GREATER_THAN, "5");
116 assertThat(db.countRowsOfTable("quality_gates")).isOne();
117 verifyCorrectBuiltInQualityGate();
119 logTester.logs(LoggerLevel.INFO).contains("Built-in quality gate's conditions of [Sonar way] has been updated")).isTrue();
123 public void upgrade_should_add_missing_condition() {
125 QualityGateDto builtInQualityGate = db.qualityGates().insertBuiltInQualityGate();
126 List<QualityGateConditionDto> builtInConditions = createBuiltInConditions(builtInQualityGate);
127 // Remove a condition
128 QualityGateConditionDto conditionToBeDeleted = builtInConditions.get(new Random().nextInt(builtInConditions.size()));
129 gateConditionDao.delete(conditionToBeDeleted, dbSession);
134 assertThat(db.countRowsOfTable("quality_gates")).isOne();
135 verifyCorrectBuiltInQualityGate();
137 logTester.logs(LoggerLevel.INFO).contains("Built-in quality gate's conditions of [Sonar way] has been updated")).isTrue();
141 public void should_set_SonarWay_as_builtin_when_not_set() {
143 QualityGateDto qualityGate = dbClient.qualityGateDao().insert(dbSession, new QualityGateDto()
144 .setName("Sonar way")
145 .setUuid(Uuids.createFast())
147 .setCreatedAt(new Date()));
149 createBuiltInConditions(qualityGate);
154 assertThat(db.countRowsOfTable("quality_gates")).isOne();
155 verifyCorrectBuiltInQualityGate();
157 logTester.logs(LoggerLevel.INFO).contains("Quality gate [Sonar way] has been set as built-in")).isTrue();
161 public void should_not_update_builtin_quality_gate_if_already_uptodate() {
163 QualityGateDto builtInQualityGate = db.qualityGates().insertBuiltInQualityGate();
164 createBuiltInConditions(builtInQualityGate);
169 assertThat(db.countRowsOfTable("quality_gates")).isOne();
170 verifyCorrectBuiltInQualityGate();
171 // Log must not be present
173 logTester.logs(LoggerLevel.INFO).contains("Quality gate [Sonar way] has been set as built-in")).isFalse();
175 logTester.logs(LoggerLevel.INFO).contains("Built-in quality gate [Sonar way] has been created")).isFalse();
177 logTester.logs(LoggerLevel.INFO).contains("Built-in quality gate's conditions of [Sonar way] has been updated")).isFalse();
181 public void ensure_only_one_built_in_quality_gate() {
183 String qualityGateName = "IncorrectQualityGate";
184 QualityGateDto builtin = new QualityGateDto().setName(qualityGateName).setBuiltIn(true).setUuid(Uuids.createFast());
185 qualityGateDao.insert(dbSession, builtin);
190 QualityGateDto oldQualityGate = qualityGateDao.selectByName(dbSession, qualityGateName);
191 assertThat(oldQualityGate).isNotNull();
192 assertThat(oldQualityGate.isBuiltIn()).isFalse();
193 assertThat(db.select("select name as \"name\" from quality_gates where is_built_in is true"))
194 .extracting(column -> column.get("name"))
195 .containsExactly(BUILT_IN_NAME);
197 logTester.logs(LoggerLevel.INFO).contains("Built-in quality gate [Sonar way] has been created")).isTrue();
199 logTester.logs(LoggerLevel.INFO).contains("Built-in quality gate's conditions of [Sonar way] has been updated")).isTrue();
203 public void ensure_only_that_builtin_is_set_as_default_when_no_default_quality_gate() {
205 QualityGateDto builtInQualityGate = db.qualityGates().insertBuiltInQualityGate();
209 assertThat(qualityGateFinder.getBuiltInQualityGate(dbSession)).isNotNull();
210 assertThat(qualityGateFinder.getBuiltInQualityGate(dbSession).getUuid()).isEqualTo(builtInQualityGate.getUuid());
214 public void builtin_quality_gate_with_incorrect_metricuuid_should_not_throw_an_exception() {
216 QualityGateConditionDto conditionDto = new QualityGateConditionDto()
217 .setUuid(Uuids.createFast())
218 .setQualityGateUuid("qgate_uuid")
219 .setMetricUuid("unknown") // This uuid does not exist
220 .setOperator(OPERATOR_GREATER_THAN)
221 .setErrorThreshold("1");
222 gateConditionDao.insert(conditionDto, dbSession);
227 // No exception thrown
228 verifyCorrectBuiltInQualityGate();
230 logTester.logs(LoggerLevel.INFO).contains("Built-in quality gate's conditions of [Sonar way] has been updated")).isTrue();
233 private void insertMetrics() {
234 dbClient.metricDao().insert(dbSession, newMetricDto().setKey(NEW_RELIABILITY_RATING_KEY).setValueType(INT.name()).setHidden(false).setDirection(0));
235 dbClient.metricDao().insert(dbSession, newMetricDto().setKey(NEW_SECURITY_RATING_KEY).setValueType(INT.name()).setHidden(false).setDirection(0));
236 dbClient.metricDao().insert(dbSession, newMetricDto().setKey(NEW_SECURITY_REMEDIATION_EFFORT_KEY).setValueType(INT.name()).setHidden(false).setDirection(0));
237 dbClient.metricDao().insert(dbSession, newMetricDto().setKey(NEW_MAINTAINABILITY_RATING_KEY).setValueType(PERCENT.name()).setHidden(false).setDirection(0));
238 dbClient.metricDao().insert(dbSession, newMetricDto().setKey(NEW_COVERAGE_KEY).setValueType(PERCENT.name()).setHidden(false).setDirection(0));
239 dbClient.metricDao().insert(dbSession, newMetricDto().setKey(NEW_DUPLICATED_LINES_DENSITY_KEY).setValueType(PERCENT.name()).setHidden(false).setDirection(0));
240 dbClient.metricDao().insert(dbSession, newMetricDto().setKey(NEW_SECURITY_HOTSPOTS_REVIEWED_KEY).setValueType(PERCENT.name()).setHidden(false).setDirection(0));
244 private void verifyCorrectBuiltInQualityGate() {
245 MetricDto newReliability = metricDao.selectByKey(dbSession, NEW_RELIABILITY_RATING_KEY);
246 MetricDto newSecurity = metricDao.selectByKey(dbSession, NEW_SECURITY_RATING_KEY);
247 MetricDto newMaintainability = metricDao.selectByKey(dbSession, NEW_MAINTAINABILITY_RATING_KEY);
248 MetricDto newCoverage = metricDao.selectByKey(dbSession, NEW_COVERAGE_KEY);
249 MetricDto newDuplication = metricDao.selectByKey(dbSession, NEW_DUPLICATED_LINES_DENSITY_KEY);
250 MetricDto newSecurityHotspots = metricDao.selectByKey(dbSession, NEW_SECURITY_HOTSPOTS_REVIEWED_KEY);
252 QualityGateDto qualityGateDto = qualityGateDao.selectByName(dbSession, BUILT_IN_NAME);
253 assertThat(qualityGateDto).isNotNull();
254 assertThat(qualityGateDto.getCreatedAt()).isNotNull();
255 assertThat(qualityGateDto.isBuiltIn()).isTrue();
256 assertThat(gateConditionDao.selectForQualityGate(dbSession, qualityGateDto.getUuid()))
257 .extracting(QualityGateConditionDto::getMetricUuid, QualityGateConditionDto::getOperator,
258 QualityGateConditionDto::getErrorThreshold)
259 .containsExactlyInAnyOrder(
260 tuple(newReliability.getUuid(), OPERATOR_GREATER_THAN, "1"),
261 tuple(newSecurity.getUuid(), OPERATOR_GREATER_THAN, "1"),
262 tuple(newMaintainability.getUuid(), OPERATOR_GREATER_THAN, "1"),
263 tuple(newCoverage.getUuid(), OPERATOR_LESS_THAN, "80"),
264 tuple(newDuplication.getUuid(), OPERATOR_GREATER_THAN, "3"),
265 tuple(newSecurityHotspots.getUuid(), OPERATOR_LESS_THAN, "100"));
268 private List<QualityGateConditionDto> createBuiltInConditions(QualityGateDto qg) {
269 List<QualityGateConditionDto> conditions = new ArrayList<>();
271 conditions.add(qualityGateConditionsUpdater.createCondition(dbSession, qg,
272 NEW_SECURITY_RATING_KEY, OPERATOR_GREATER_THAN, "1"));
273 conditions.add(qualityGateConditionsUpdater.createCondition(dbSession, qg,
274 NEW_RELIABILITY_RATING_KEY, OPERATOR_GREATER_THAN, "1"));
275 conditions.add(qualityGateConditionsUpdater.createCondition(dbSession, qg,
276 NEW_MAINTAINABILITY_RATING_KEY, OPERATOR_GREATER_THAN, "1"));
277 conditions.add(qualityGateConditionsUpdater.createCondition(dbSession, qg,
278 NEW_COVERAGE_KEY, OPERATOR_LESS_THAN, "80"));
279 conditions.add(qualityGateConditionsUpdater.createCondition(dbSession, qg,
280 NEW_DUPLICATED_LINES_DENSITY_KEY, OPERATOR_GREATER_THAN, "3"));
281 conditions.add(qualityGateConditionsUpdater.createCondition(dbSession, qg,
282 NEW_SECURITY_HOTSPOTS_REVIEWED_KEY, OPERATOR_LESS_THAN, "100"));