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.ws;
22 import java.io.IOException;
23 import java.nio.charset.StandardCharsets;
24 import org.apache.commons.io.IOUtils;
25 import org.junit.Rule;
26 import org.junit.Test;
27 import org.sonar.api.measures.CoreMetrics;
28 import org.sonar.api.server.ws.WebService;
29 import org.sonar.api.utils.System2;
30 import org.sonar.api.web.UserRole;
31 import org.sonar.db.DbClient;
32 import org.sonar.db.DbSession;
33 import org.sonar.db.DbTester;
34 import org.sonar.db.component.BranchType;
35 import org.sonar.db.component.ComponentDto;
36 import org.sonar.db.component.SnapshotDto;
37 import org.sonar.db.metric.MetricDto;
38 import org.sonar.db.permission.GlobalPermission;
39 import org.sonar.server.component.TestComponentFinder;
40 import org.sonar.server.exceptions.BadRequestException;
41 import org.sonar.server.exceptions.ForbiddenException;
42 import org.sonar.server.exceptions.NotFoundException;
43 import org.sonar.server.tester.UserSessionRule;
44 import org.sonar.server.ws.WsActionTester;
45 import org.sonarqube.ws.Qualitygates.ProjectStatusResponse;
46 import org.sonarqube.ws.Qualitygates.ProjectStatusResponse.Status;
48 import static java.lang.String.format;
49 import static org.assertj.core.api.Assertions.assertThat;
50 import static org.assertj.core.api.Assertions.assertThatThrownBy;
51 import static org.assertj.core.api.Assertions.tuple;
52 import static org.sonar.db.component.SnapshotTesting.newAnalysis;
53 import static org.sonar.db.measure.MeasureTesting.newLiveMeasure;
54 import static org.sonar.db.measure.MeasureTesting.newMeasureDto;
55 import static org.sonar.db.metric.MetricTesting.newMetricDto;
56 import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_ANALYSIS_ID;
57 import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_BRANCH;
58 import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_PROJECT_ID;
59 import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_PROJECT_KEY;
60 import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_PULL_REQUEST;
61 import static org.sonar.test.JsonAssert.assertJson;
63 public class ProjectStatusActionTest {
64 private static final String ANALYSIS_ID = "task-uuid";
67 public UserSessionRule userSession = UserSessionRule.standalone();
69 public DbTester db = DbTester.create(System2.INSTANCE);
71 private final DbClient dbClient = db.getDbClient();
72 private final DbSession dbSession = db.getSession();
74 private final WsActionTester ws = new WsActionTester(new ProjectStatusAction(dbClient, TestComponentFinder.from(db), userSession));
77 public void test_definition() {
78 WebService.Action action = ws.getDef();
79 assertThat(action.params())
80 .extracting(WebService.Param::key, WebService.Param::isRequired)
81 .containsExactlyInAnyOrder(
82 tuple("analysisId", false),
83 tuple("projectKey", false),
84 tuple("projectId", false),
85 tuple("branch", false),
86 tuple("pullRequest", false));
90 public void test_json_example() throws IOException {
91 ComponentDto project = db.components().insertPrivateProject();
92 userSession.addProjectPermission(UserRole.USER, project);
93 MetricDto gateDetailsMetric = insertGateDetailMetric();
95 SnapshotDto snapshot = dbClient.snapshotDao().insert(dbSession, newAnalysis(project)
96 .setPeriodMode("last_version")
97 .setPeriodParam("2015-12-07")
98 .setPeriodDate(956789123987L));
99 dbClient.measureDao().insert(dbSession,
100 newMeasureDto(gateDetailsMetric, project, snapshot)
101 .setData(IOUtils.toString(getClass().getResource("ProjectStatusActionTest/measure_data.json"), StandardCharsets.UTF_8)));
104 String response = ws.newRequest()
105 .setParam("analysisId", snapshot.getUuid())
106 .execute().getInput();
108 assertJson(response).isSimilarTo(getClass().getResource("project_status-example.json"));
112 public void return_past_status_when_project_is_referenced_by_past_analysis_id() throws IOException {
113 ComponentDto project = db.components().insertPrivateProject();
114 SnapshotDto pastAnalysis = dbClient.snapshotDao().insert(dbSession, newAnalysis(project)
116 .setPeriodMode("last_version")
117 .setPeriodParam("2015-12-07")
118 .setPeriodDate(956789123987L));
119 SnapshotDto lastAnalysis = dbClient.snapshotDao().insert(dbSession, newAnalysis(project)
121 .setPeriodMode("last_version")
122 .setPeriodParam("2016-12-07")
123 .setPeriodDate(1_500L));
124 MetricDto gateDetailsMetric = insertGateDetailMetric();
125 dbClient.measureDao().insert(dbSession,
126 newMeasureDto(gateDetailsMetric, project, pastAnalysis)
127 .setData(IOUtils.toString(getClass().getResource("ProjectStatusActionTest/measure_data.json"))));
128 dbClient.measureDao().insert(dbSession,
129 newMeasureDto(gateDetailsMetric, project, lastAnalysis)
130 .setData("not_used"));
132 userSession.addProjectPermission(UserRole.USER, project);
134 String response = ws.newRequest()
135 .setParam(PARAM_ANALYSIS_ID, pastAnalysis.getUuid())
136 .execute().getInput();
138 assertJson(response).isSimilarTo(getClass().getResource("project_status-example.json"));
142 public void return_live_status_when_project_is_referenced_by_its_id() throws IOException {
143 ComponentDto project = db.components().insertPrivateProject();
144 dbClient.snapshotDao().insert(dbSession, newAnalysis(project)
145 .setPeriodMode("last_version")
146 .setPeriodParam("2015-12-07")
147 .setPeriodDate(956789123987L));
148 MetricDto gateDetailsMetric = insertGateDetailMetric();
149 dbClient.liveMeasureDao().insert(dbSession,
150 newLiveMeasure(project, gateDetailsMetric)
151 .setData(IOUtils.toString(getClass().getResource("ProjectStatusActionTest/measure_data.json"))));
153 userSession.addProjectPermission(UserRole.USER, project);
155 String response = ws.newRequest()
156 .setParam(PARAM_PROJECT_ID, project.uuid())
157 .execute().getInput();
159 assertJson(response).isSimilarTo(getClass().getResource("project_status-example.json"));
163 public void return_past_status_when_branch_is_referenced_by_past_analysis_id() throws IOException {
164 ComponentDto project = db.components().insertPrivateProject();
165 ComponentDto branch = db.components().insertProjectBranch(project);
166 SnapshotDto pastAnalysis = dbClient.snapshotDao().insert(dbSession, newAnalysis(branch)
168 .setPeriodMode("last_version")
169 .setPeriodParam("2015-12-07")
170 .setPeriodDate(956789123987L));
171 SnapshotDto lastAnalysis = dbClient.snapshotDao().insert(dbSession, newAnalysis(branch)
173 .setPeriodMode("last_version")
174 .setPeriodParam("2016-12-07")
175 .setPeriodDate(1_500L));
176 MetricDto gateDetailsMetric = insertGateDetailMetric();
177 dbClient.measureDao().insert(dbSession,
178 newMeasureDto(gateDetailsMetric, branch, pastAnalysis)
179 .setData(IOUtils.toString(getClass().getResource("ProjectStatusActionTest/measure_data.json"))));
180 dbClient.measureDao().insert(dbSession,
181 newMeasureDto(gateDetailsMetric, branch, lastAnalysis)
182 .setData("not_used"));
184 userSession.addProjectPermission(UserRole.USER, project);
186 String response = ws.newRequest()
187 .setParam(PARAM_ANALYSIS_ID, pastAnalysis.getUuid())
188 .execute().getInput();
190 assertJson(response).isSimilarTo(getClass().getResource("project_status-example.json"));
194 public void return_live_status_when_project_is_referenced_by_its_key() throws IOException {
195 ComponentDto project = db.components().insertPrivateProject();
196 dbClient.snapshotDao().insert(dbSession, newAnalysis(project)
197 .setPeriodMode("last_version")
198 .setPeriodParam("2015-12-07")
199 .setPeriodDate(956789123987L));
200 MetricDto gateDetailsMetric = insertGateDetailMetric();
201 dbClient.liveMeasureDao().insert(dbSession,
202 newLiveMeasure(project, gateDetailsMetric)
203 .setData(IOUtils.toString(getClass().getResource("ProjectStatusActionTest/measure_data.json"))));
205 userSession.addProjectPermission(UserRole.USER, project);
207 String response = ws.newRequest()
208 .setParam(PARAM_PROJECT_KEY, project.getKey())
209 .execute().getInput();
211 assertJson(response).isSimilarTo(getClass().getResource("project_status-example.json"));
215 public void return_live_status_when_branch_is_referenced_by_its_key() throws IOException {
216 ComponentDto project = db.components().insertPrivateProject();
217 ComponentDto branch = db.components().insertProjectBranch(project);
219 dbClient.snapshotDao().insert(dbSession, newAnalysis(branch)
220 .setPeriodMode("last_version")
221 .setPeriodParam("2015-12-07")
222 .setPeriodDate(956789123987L));
223 MetricDto gateDetailsMetric = insertGateDetailMetric();
224 dbClient.liveMeasureDao().insert(dbSession,
225 newLiveMeasure(branch, gateDetailsMetric)
226 .setData(IOUtils.toString(getClass().getResource("ProjectStatusActionTest/measure_data.json"))));
228 userSession.addProjectPermission(UserRole.USER, project);
230 String response = ws.newRequest()
231 .setParam(PARAM_PROJECT_KEY, project.getKey())
232 .setParam(PARAM_BRANCH, branch.getBranch())
233 .execute().getInput();
235 assertJson(response).isSimilarTo(getClass().getResource("project_status-example.json"));
239 public void return_live_status_when_pull_request_is_referenced_by_its_key() throws IOException {
240 ComponentDto project = db.components().insertPrivateProject();
241 ComponentDto pr = db.components().insertProjectBranch(project, branch -> branch.setBranchType(BranchType.PULL_REQUEST));
243 dbClient.snapshotDao().insert(dbSession, newAnalysis(pr)
244 .setPeriodMode("last_version")
245 .setPeriodParam("2015-12-07")
246 .setPeriodDate(956789123987L));
247 MetricDto gateDetailsMetric = insertGateDetailMetric();
248 dbClient.liveMeasureDao().insert(dbSession,
249 newLiveMeasure(pr, gateDetailsMetric)
250 .setData(IOUtils.toString(getClass().getResource("ProjectStatusActionTest/measure_data.json"))));
252 userSession.addProjectPermission(UserRole.USER, project);
254 String response = ws.newRequest()
255 .setParam(PARAM_PROJECT_KEY, project.getKey())
256 .setParam(PARAM_PULL_REQUEST, pr.getPullRequest())
257 .execute().getInput();
259 assertJson(response).isSimilarTo(getClass().getResource("project_status-example.json"));
263 public void return_undefined_status_if_specified_analysis_is_not_found() {
264 ComponentDto project = db.components().insertPrivateProject();
265 SnapshotDto snapshot = dbClient.snapshotDao().insert(dbSession, newAnalysis(project));
267 userSession.addProjectPermission(UserRole.USER, project);
269 ProjectStatusResponse result = ws.newRequest()
270 .setParam(PARAM_ANALYSIS_ID, snapshot.getUuid())
271 .executeProtobuf(ProjectStatusResponse.class);
273 assertThat(result.getProjectStatus().getStatus()).isEqualTo(Status.NONE);
274 assertThat(result.getProjectStatus().getConditionsCount()).isZero();
278 public void return_undefined_status_if_project_is_not_analyzed() {
279 ComponentDto project = db.components().insertPrivateProject();
280 userSession.addProjectPermission(UserRole.USER, project);
282 ProjectStatusResponse result = ws.newRequest()
283 .setParam(PARAM_PROJECT_ID, project.uuid())
284 .executeProtobuf(ProjectStatusResponse.class);
286 assertThat(result.getProjectStatus().getStatus()).isEqualTo(Status.NONE);
287 assertThat(result.getProjectStatus().getConditionsCount()).isZero();
291 public void project_administrator_is_allowed_to_get_project_status() {
292 ComponentDto project = db.components().insertPrivateProject();
293 SnapshotDto snapshot = dbClient.snapshotDao().insert(dbSession, newAnalysis(project));
295 userSession.addProjectPermission(UserRole.ADMIN, project);
298 .setParam(PARAM_ANALYSIS_ID, snapshot.getUuid())
299 .executeProtobuf(ProjectStatusResponse.class);
303 public void project_user_is_allowed_to_get_project_status() {
304 ComponentDto project = db.components().insertPrivateProject();
305 SnapshotDto snapshot = dbClient.snapshotDao().insert(dbSession, newAnalysis(project));
307 userSession.addProjectPermission(UserRole.USER, project);
310 .setParam(PARAM_ANALYSIS_ID, snapshot.getUuid())
311 .executeProtobuf(ProjectStatusResponse.class);
315 public void user_with_project_scan_permission_is_allowed_to_get_project_status() {
316 ComponentDto project = db.components().insertPrivateProject();
317 SnapshotDto snapshot = dbClient.snapshotDao().insert(dbSession, newAnalysis(project));
319 userSession.addProjectPermission(UserRole.SCAN, project);
321 var response = ws.newRequest()
322 .setParam(PARAM_ANALYSIS_ID, snapshot.getUuid()).execute();
324 assertThat(response.getStatus()).isEqualTo(200);
328 public void user_with_global_scan_permission_is_allowed_to_get_project_status() {
329 ComponentDto project = db.components().insertPrivateProject();
330 SnapshotDto snapshot = dbClient.snapshotDao().insert(dbSession, newAnalysis(project));
332 userSession.addPermission(GlobalPermission.SCAN);
334 var response = ws.newRequest()
335 .setParam(PARAM_ANALYSIS_ID, snapshot.getUuid()).execute();
337 assertThat(response.getStatus()).isEqualTo(200);
341 public void fail_if_no_snapshot_id_found() {
342 logInAsSystemAdministrator();
344 assertThatThrownBy(() -> ws.newRequest()
345 .setParam(PARAM_ANALYSIS_ID, ANALYSIS_ID)
346 .executeProtobuf(ProjectStatusResponse.class))
347 .isInstanceOf(NotFoundException.class)
348 .hasMessageContaining("Analysis with id 'task-uuid' is not found");
352 public void fail_if_insufficient_privileges() {
353 ComponentDto project = db.components().insertPrivateProject();
354 SnapshotDto snapshot = dbClient.snapshotDao().insert(dbSession, newAnalysis(project));
358 assertThatThrownBy(() -> ws.newRequest()
359 .setParam(PARAM_ANALYSIS_ID, snapshot.getUuid())
360 .executeProtobuf(ProjectStatusResponse.class))
361 .isInstanceOf(ForbiddenException.class);
365 public void fail_if_project_id_and_ce_task_id_provided() {
366 ComponentDto project = db.components().insertPrivateProject();
367 logInAsSystemAdministrator();
369 assertThatThrownBy(() -> ws.newRequest()
370 .setParam(PARAM_ANALYSIS_ID, "analysis-id")
371 .setParam(PARAM_PROJECT_ID, "project-uuid")
372 .execute().getInput())
373 .isInstanceOf(BadRequestException.class)
374 .hasMessageContaining("Either 'analysisId', 'projectId' or 'projectKey' must be provided");
378 public void fail_if_branch_key_and_pull_request_id_provided() {
379 ComponentDto project = db.components().insertPrivateProject();
380 logInAsSystemAdministrator();
382 assertThatThrownBy(() -> ws.newRequest()
383 .setParam(PARAM_PROJECT_KEY, "key")
384 .setParam(PARAM_BRANCH, "branch")
385 .setParam(PARAM_PULL_REQUEST, "pr")
386 .execute().getInput())
387 .isInstanceOf(BadRequestException.class)
388 .hasMessageContaining("Either 'branch' or 'pullRequest' can be provided, not both");
392 public void fail_if_no_parameter_provided() {
393 logInAsSystemAdministrator();
395 assertThatThrownBy(() -> ws.newRequest()
396 .execute().getInput())
397 .isInstanceOf(BadRequestException.class)
398 .hasMessageContaining("Either 'analysisId', 'projectId' or 'projectKey' must be provided");
402 public void fail_when_using_branch_db_key() {
403 ComponentDto project = db.components().insertPublicProject();
404 userSession.logIn().addProjectPermission(UserRole.ADMIN, project);
405 ComponentDto branch = db.components().insertProjectBranch(project);
406 SnapshotDto snapshot = db.components().insertSnapshot(branch);
408 assertThatThrownBy(() -> ws.newRequest()
409 .setParam(PARAM_PROJECT_KEY, branch.getKey())
411 .isInstanceOf(NotFoundException.class)
412 .hasMessageContaining(format("Project '%s' not found", branch.getKey()));
416 public void fail_when_using_branch_uuid() {
417 ComponentDto project = db.components().insertPublicProject();
418 userSession.logIn().addProjectPermission(UserRole.ADMIN, project);
419 ComponentDto branch = db.components().insertProjectBranch(project);
420 SnapshotDto snapshot = db.components().insertSnapshot(branch);
422 assertThatThrownBy(() -> ws.newRequest()
423 .setParam("projectId", branch.uuid())
425 .isInstanceOf(NotFoundException.class)
426 .hasMessageContaining(format("Project '%s' not found", branch.uuid()));
429 private void logInAsSystemAdministrator() {
430 userSession.logIn().setSystemAdministrator();
433 private MetricDto insertGateDetailMetric() {
434 return dbClient.metricDao().insert(dbSession, newMetricDto()
436 .setKey(CoreMetrics.QUALITY_GATE_DETAILS_KEY));