3 * Copyright (C) 2009-2024 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.ws;
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 java.util.ArrayList;
26 import org.junit.Rule;
27 import org.junit.Test;
28 import org.junit.runner.RunWith;
29 import org.sonar.api.server.ws.WebService;
30 import org.sonar.db.DbClient;
31 import org.sonar.db.DbSession;
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.db.user.GroupDto;
37 import org.sonar.db.user.UserDto;
38 import org.sonar.server.component.TestComponentFinder;
39 import org.sonar.server.exceptions.BadRequestException;
40 import org.sonar.server.exceptions.ForbiddenException;
41 import org.sonar.server.qualitygate.QualityGateConditionsUpdater;
42 import org.sonar.server.tester.UserSessionRule;
43 import org.sonar.server.ws.TestResponse;
44 import org.sonar.server.ws.WsActionTester;
45 import org.sonarqube.ws.Qualitygates.CreateConditionResponse;
47 import static java.lang.String.format;
48 import static org.assertj.core.api.Assertions.assertThat;
49 import static org.assertj.core.api.Assertions.assertThatThrownBy;
50 import static org.assertj.core.api.Assertions.tuple;
51 import static org.sonar.api.measures.Metric.ValueType.INT;
52 import static org.sonar.db.permission.GlobalPermission.ADMINISTER_QUALITY_GATES;
53 import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_ERROR;
54 import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_GATE_NAME;
55 import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_METRIC;
56 import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_OPERATOR;
58 @RunWith(DataProviderRunner.class)
59 public class CreateConditionActionIT {
63 public UserSessionRule userSession = UserSessionRule.standalone();
66 public DbTester db = DbTester.create();
68 private final DbClient dbClient = db.getDbClient();
69 private final DbSession dbSession = db.getSession();
70 private final CreateConditionAction underTest = new CreateConditionAction(dbClient, new QualityGateConditionsUpdater(dbClient),
71 new QualityGatesWsSupport(dbClient, userSession, TestComponentFinder.from(db)));
73 private final WsActionTester ws = new WsActionTester(underTest);
76 public void create_error_condition() {
77 logInAsQualityGateAdmin();
78 QualityGateDto qualityGate = db.qualityGates().insertQualityGate();
79 MetricDto metric = insertMetric();
82 .setParam(PARAM_GATE_NAME, qualityGate.getName())
83 .setParam(PARAM_METRIC, metric.getKey())
84 .setParam(PARAM_OPERATOR, "LT")
85 .setParam(PARAM_ERROR, "90")
88 assertCondition(qualityGate, metric, "LT", "90");
92 public void create_condition_over_new_code_period() {
93 logInAsQualityGateAdmin();
94 QualityGateDto qualityGate = db.qualityGates().insertQualityGate();
95 MetricDto metric = insertMetric();
98 .setParam(PARAM_GATE_NAME, qualityGate.getName())
99 .setParam(PARAM_METRIC, metric.getKey())
100 .setParam(PARAM_OPERATOR, "LT")
101 .setParam(PARAM_ERROR, "90")
104 assertCondition(qualityGate, metric, "LT", "90");
108 public void fail_to_update_built_in_quality_gate() {
109 logInAsQualityGateAdmin();
110 QualityGateDto qualityGate = db.qualityGates().insertQualityGate(qg -> qg.setBuiltIn(true));
111 MetricDto metric = insertMetric();
113 assertThatThrownBy(() -> ws.newRequest()
114 .setParam(PARAM_GATE_NAME, qualityGate.getName())
115 .setParam(PARAM_METRIC, metric.getKey())
116 .setParam(PARAM_OPERATOR, "LT")
117 .setParam(PARAM_ERROR, "90")
119 .isInstanceOf(IllegalArgumentException.class)
120 .hasMessageContaining(format("Operation forbidden for built-in Quality Gate '%s'", qualityGate.getName()));
124 public void fail_with_unknown_operator() {
125 logInAsQualityGateAdmin();
126 QualityGateDto qualityGate = db.qualityGates().insertQualityGate();
127 MetricDto metric = db.measures().insertMetric(m -> m.setValueType(INT.name()).setHidden(false).setDirection(0));
129 assertThatThrownBy(() -> ws.newRequest()
130 .setParam(PARAM_GATE_NAME, qualityGate.getName())
131 .setParam(PARAM_METRIC, metric.getKey())
132 .setParam(PARAM_OPERATOR, "ABC")
133 .setParam(PARAM_ERROR, "90")
135 .isInstanceOf(IllegalArgumentException.class)
136 .hasMessageContaining("Value of parameter 'op' (ABC) must be one of: [LT, GT]");
140 @UseDataProvider("invalid_operators_for_direction")
141 public void fail_with_invalid_operators_for_direction(String operator, int direction) {
142 logInAsQualityGateAdmin();
143 QualityGateDto qualityGate = db.qualityGates().insertQualityGate();
144 MetricDto metric = db.measures().insertMetric(m -> m.setValueType(INT.name()).setHidden(false).setDirection(direction));
146 assertThatThrownBy(() -> ws.newRequest()
147 .setParam(PARAM_GATE_NAME, qualityGate.getName())
148 .setParam(PARAM_METRIC, metric.getKey())
149 .setParam(PARAM_OPERATOR, operator)
150 .setParam(PARAM_ERROR, "90")
152 .isInstanceOf(BadRequestException.class)
153 .hasMessageContaining(format("Operator %s is not allowed for this metric.", operator));
157 public void test_response() {
158 logInAsQualityGateAdmin();
159 QualityGateDto qualityGate = db.qualityGates().insertQualityGate();
160 MetricDto metric = insertMetric();
162 CreateConditionResponse response = ws.newRequest()
163 .setParam(PARAM_GATE_NAME, qualityGate.getName())
164 .setParam(PARAM_METRIC, metric.getKey())
165 .setParam(PARAM_OPERATOR, "LT")
166 .setParam(PARAM_ERROR, "45")
167 .executeProtobuf(CreateConditionResponse.class);
169 QualityGateConditionDto condition = new ArrayList<>(dbClient.gateConditionDao().selectForQualityGate(dbSession, qualityGate.getUuid())).get(0);
170 assertThat(response.getId()).isEqualTo(condition.getUuid());
171 assertThat(response.getMetric()).isEqualTo(metric.getKey());
172 assertThat(response.getOp()).isEqualTo("LT");
173 assertThat(response.getError()).isEqualTo("45");
177 public void user_with_permission_can_call_endpoint() {
178 QualityGateDto qualityGate = db.qualityGates().insertQualityGate();
179 MetricDto metric = insertMetric();
180 UserDto user = db.users().insertUser();
181 db.qualityGates().addUserPermission(qualityGate, user);
182 userSession.logIn(user);
184 TestResponse response = ws.newRequest()
185 .setParam(PARAM_GATE_NAME, qualityGate.getName())
186 .setParam(PARAM_METRIC, metric.getKey())
187 .setParam(PARAM_OPERATOR, "LT")
188 .setParam(PARAM_ERROR, "90")
191 assertThat(response.getStatus()).isEqualTo(200);
195 public void user_with_group_permission_can_call_endpoint() {
196 QualityGateDto qualityGate = db.qualityGates().insertQualityGate();
197 MetricDto metric = insertMetric();
198 UserDto user = db.users().insertUser();
199 GroupDto group = db.users().insertGroup();
200 db.qualityGates().addGroupPermission(qualityGate, group);
201 userSession.logIn(user).setGroups(group);
203 TestResponse response = ws.newRequest()
204 .setParam(PARAM_GATE_NAME, qualityGate.getName())
205 .setParam(PARAM_METRIC, metric.getKey())
206 .setParam(PARAM_OPERATOR, "LT")
207 .setParam(PARAM_ERROR, "90")
210 assertThat(response.getStatus()).isEqualTo(200);
214 public void throw_ForbiddenException_if_not_gate_administrator() {
215 QualityGateDto qualityGate = db.qualityGates().insertQualityGate();
216 MetricDto metric = insertMetric();
219 assertThatThrownBy(() -> ws.newRequest()
220 .setParam(PARAM_GATE_NAME, qualityGate.getName())
221 .setParam(PARAM_METRIC, metric.getKey())
222 .setParam(PARAM_OPERATOR, "LT")
223 .setParam(PARAM_ERROR, "90")
225 .isInstanceOf(ForbiddenException.class)
226 .hasMessageContaining("Insufficient privileges");
230 public void test_ws_definition() {
231 WebService.Action action = ws.getDef();
232 assertThat(action).isNotNull();
233 assertThat(action.isInternal()).isFalse();
234 assertThat(action.isPost()).isTrue();
235 assertThat(action.responseExampleAsString()).isNotEmpty();
236 assertThat(action.params())
237 .extracting(WebService.Param::key, WebService.Param::isRequired)
238 .containsExactlyInAnyOrder(
239 tuple("gateName", true),
240 tuple("metric", true),
241 tuple("error", true),
246 public static Object[][] invalid_operators_for_direction() {
247 return new Object[][] {
253 private void assertCondition(QualityGateDto qualityGate, MetricDto metric, String operator, String error) {
254 assertThat(dbClient.gateConditionDao().selectForQualityGate(dbSession, qualityGate.getUuid()))
255 .extracting(QualityGateConditionDto::getQualityGateUuid, QualityGateConditionDto::getMetricUuid, QualityGateConditionDto::getOperator,
256 QualityGateConditionDto::getErrorThreshold)
257 .containsExactlyInAnyOrder(tuple(qualityGate.getUuid(), metric.getUuid(), operator, error));
260 private void logInAsQualityGateAdmin() {
261 userSession.logIn().addPermission(ADMINISTER_QUALITY_GATES);
264 private MetricDto insertMetric() {
265 return db.measures().insertMetric(m -> m
266 .setValueType(INT.name())