]> source.dussan.org Git - sonarqube.git/blob
acbc60c89b50ea0bffae26af3998ada1b0f06ab4
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2024 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.ws;
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 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;
46
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;
57
58 @RunWith(DataProviderRunner.class)
59 public class CreateConditionActionIT {
60
61
62   @Rule
63   public UserSessionRule userSession = UserSessionRule.standalone();
64
65   @Rule
66   public DbTester db = DbTester.create();
67
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)));
72
73   private final WsActionTester ws = new WsActionTester(underTest);
74
75   @Test
76   public void create_error_condition() {
77     logInAsQualityGateAdmin();
78     QualityGateDto qualityGate = db.qualityGates().insertQualityGate();
79     MetricDto metric = insertMetric();
80
81     ws.newRequest()
82       .setParam(PARAM_GATE_NAME, qualityGate.getName())
83       .setParam(PARAM_METRIC, metric.getKey())
84       .setParam(PARAM_OPERATOR, "LT")
85       .setParam(PARAM_ERROR, "90")
86       .execute();
87
88     assertCondition(qualityGate, metric, "LT", "90");
89   }
90
91   @Test
92   public void create_condition_over_new_code_period() {
93     logInAsQualityGateAdmin();
94     QualityGateDto qualityGate = db.qualityGates().insertQualityGate();
95     MetricDto metric = insertMetric();
96
97     ws.newRequest()
98       .setParam(PARAM_GATE_NAME, qualityGate.getName())
99       .setParam(PARAM_METRIC, metric.getKey())
100       .setParam(PARAM_OPERATOR, "LT")
101       .setParam(PARAM_ERROR, "90")
102       .execute();
103
104     assertCondition(qualityGate, metric, "LT", "90");
105   }
106
107   @Test
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();
112
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")
118       .execute())
119       .isInstanceOf(IllegalArgumentException.class)
120       .hasMessageContaining(format("Operation forbidden for built-in Quality Gate '%s'", qualityGate.getName()));
121   }
122
123   @Test
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));
128
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")
134       .execute())
135       .isInstanceOf(IllegalArgumentException.class)
136       .hasMessageContaining("Value of parameter 'op' (ABC) must be one of: [LT, GT]");
137   }
138
139   @Test
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));
145
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")
151       .execute())
152       .isInstanceOf(BadRequestException.class)
153       .hasMessageContaining(format("Operator %s is not allowed for this metric.", operator));
154   }
155
156   @Test
157   public void test_response() {
158     logInAsQualityGateAdmin();
159     QualityGateDto qualityGate = db.qualityGates().insertQualityGate();
160     MetricDto metric = insertMetric();
161
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);
168
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");
174   }
175
176   @Test
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);
183
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")
189       .execute();
190
191     assertThat(response.getStatus()).isEqualTo(200);
192   }
193
194   @Test
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);
202
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")
208       .execute();
209
210     assertThat(response.getStatus()).isEqualTo(200);
211   }
212
213   @Test
214   public void throw_ForbiddenException_if_not_gate_administrator() {
215     QualityGateDto qualityGate = db.qualityGates().insertQualityGate();
216     MetricDto metric = insertMetric();
217     userSession.logIn();
218
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")
224       .execute())
225       .isInstanceOf(ForbiddenException.class)
226       .hasMessageContaining("Insufficient privileges");
227   }
228
229   @Test
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),
242         tuple("op", false));
243   }
244
245   @DataProvider
246   public static Object[][] invalid_operators_for_direction() {
247     return new Object[][] {
248       {"LT", -1},
249       {"GT", 1},
250     };
251   }
252
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));
258   }
259
260   private void logInAsQualityGateAdmin() {
261     userSession.logIn().addPermission(ADMINISTER_QUALITY_GATES);
262   }
263
264   private MetricDto insertMetric() {
265     return db.measures().insertMetric(m -> m
266       .setValueType(INT.name())
267       .setHidden(false)
268       .setDirection(0));
269   }
270 }