]> source.dussan.org Git - sonarqube.git/blob
f3132c3aa397ffa3fe4bcb9a1ce1ce4469a30c1a
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2022 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 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;
47
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;
62
63 public class ProjectStatusActionTest {
64   private static final String ANALYSIS_ID = "task-uuid";
65
66   @Rule
67   public UserSessionRule userSession = UserSessionRule.standalone();
68   @Rule
69   public DbTester db = DbTester.create(System2.INSTANCE);
70
71   private final DbClient dbClient = db.getDbClient();
72   private final DbSession dbSession = db.getSession();
73
74   private final WsActionTester ws = new WsActionTester(new ProjectStatusAction(dbClient, TestComponentFinder.from(db), userSession));
75
76   @Test
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));
87   }
88
89   @Test
90   public void test_json_example() throws IOException {
91     ComponentDto project = db.components().insertPrivateProject();
92     userSession.addProjectPermission(UserRole.USER, project);
93     MetricDto gateDetailsMetric = insertGateDetailMetric();
94
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)));
102     dbSession.commit();
103
104     String response = ws.newRequest()
105       .setParam("analysisId", snapshot.getUuid())
106       .execute().getInput();
107
108     assertJson(response).isSimilarTo(getClass().getResource("project_status-example.json"));
109   }
110
111   @Test
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)
115       .setLast(false)
116       .setPeriodMode("last_version")
117       .setPeriodParam("2015-12-07")
118       .setPeriodDate(956789123987L));
119     SnapshotDto lastAnalysis = dbClient.snapshotDao().insert(dbSession, newAnalysis(project)
120       .setLast(true)
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"));
131     dbSession.commit();
132     userSession.addProjectPermission(UserRole.USER, project);
133
134     String response = ws.newRequest()
135       .setParam(PARAM_ANALYSIS_ID, pastAnalysis.getUuid())
136       .execute().getInput();
137
138     assertJson(response).isSimilarTo(getClass().getResource("project_status-example.json"));
139   }
140
141   @Test
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"))));
152     dbSession.commit();
153     userSession.addProjectPermission(UserRole.USER, project);
154
155     String response = ws.newRequest()
156       .setParam(PARAM_PROJECT_ID, project.uuid())
157       .execute().getInput();
158
159     assertJson(response).isSimilarTo(getClass().getResource("project_status-example.json"));
160   }
161
162   @Test
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)
167       .setLast(false)
168       .setPeriodMode("last_version")
169       .setPeriodParam("2015-12-07")
170       .setPeriodDate(956789123987L));
171     SnapshotDto lastAnalysis = dbClient.snapshotDao().insert(dbSession, newAnalysis(branch)
172       .setLast(true)
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"));
183     dbSession.commit();
184     userSession.addProjectPermission(UserRole.USER, project);
185
186     String response = ws.newRequest()
187       .setParam(PARAM_ANALYSIS_ID, pastAnalysis.getUuid())
188       .execute().getInput();
189
190     assertJson(response).isSimilarTo(getClass().getResource("project_status-example.json"));
191   }
192
193   @Test
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"))));
204     dbSession.commit();
205     userSession.addProjectPermission(UserRole.USER, project);
206
207     String response = ws.newRequest()
208       .setParam(PARAM_PROJECT_KEY, project.getKey())
209       .execute().getInput();
210
211     assertJson(response).isSimilarTo(getClass().getResource("project_status-example.json"));
212   }
213
214   @Test
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);
218
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"))));
227     dbSession.commit();
228     userSession.addProjectPermission(UserRole.USER, project);
229
230     String response = ws.newRequest()
231       .setParam(PARAM_PROJECT_KEY, project.getKey())
232       .setParam(PARAM_BRANCH, branch.getBranch())
233       .execute().getInput();
234
235     assertJson(response).isSimilarTo(getClass().getResource("project_status-example.json"));
236   }
237
238   @Test
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));
242
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"))));
251     dbSession.commit();
252     userSession.addProjectPermission(UserRole.USER, project);
253
254     String response = ws.newRequest()
255       .setParam(PARAM_PROJECT_KEY, project.getKey())
256       .setParam(PARAM_PULL_REQUEST, pr.getPullRequest())
257       .execute().getInput();
258
259     assertJson(response).isSimilarTo(getClass().getResource("project_status-example.json"));
260   }
261
262   @Test
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));
266     dbSession.commit();
267     userSession.addProjectPermission(UserRole.USER, project);
268
269     ProjectStatusResponse result = ws.newRequest()
270       .setParam(PARAM_ANALYSIS_ID, snapshot.getUuid())
271       .executeProtobuf(ProjectStatusResponse.class);
272
273     assertThat(result.getProjectStatus().getStatus()).isEqualTo(Status.NONE);
274     assertThat(result.getProjectStatus().getConditionsCount()).isZero();
275   }
276
277   @Test
278   public void return_undefined_status_if_project_is_not_analyzed() {
279     ComponentDto project = db.components().insertPrivateProject();
280     userSession.addProjectPermission(UserRole.USER, project);
281
282     ProjectStatusResponse result = ws.newRequest()
283       .setParam(PARAM_PROJECT_ID, project.uuid())
284       .executeProtobuf(ProjectStatusResponse.class);
285
286     assertThat(result.getProjectStatus().getStatus()).isEqualTo(Status.NONE);
287     assertThat(result.getProjectStatus().getConditionsCount()).isZero();
288   }
289
290   @Test
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));
294     dbSession.commit();
295     userSession.addProjectPermission(UserRole.ADMIN, project);
296
297     ws.newRequest()
298       .setParam(PARAM_ANALYSIS_ID, snapshot.getUuid())
299       .executeProtobuf(ProjectStatusResponse.class);
300   }
301
302   @Test
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));
306     dbSession.commit();
307     userSession.addProjectPermission(UserRole.USER, project);
308
309     ws.newRequest()
310       .setParam(PARAM_ANALYSIS_ID, snapshot.getUuid())
311       .executeProtobuf(ProjectStatusResponse.class);
312   }
313
314   @Test
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));
318     dbSession.commit();
319     userSession.addProjectPermission(UserRole.SCAN, project);
320
321     var response = ws.newRequest()
322       .setParam(PARAM_ANALYSIS_ID, snapshot.getUuid()).execute();
323
324     assertThat(response.getStatus()).isEqualTo(200);
325   }
326
327   @Test
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));
331     dbSession.commit();
332     userSession.addPermission(GlobalPermission.SCAN);
333
334     var response = ws.newRequest()
335       .setParam(PARAM_ANALYSIS_ID, snapshot.getUuid()).execute();
336
337     assertThat(response.getStatus()).isEqualTo(200);
338   }
339
340   @Test
341   public void fail_if_no_snapshot_id_found() {
342     logInAsSystemAdministrator();
343
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");
349   }
350
351   @Test
352   public void fail_if_insufficient_privileges() {
353     ComponentDto project = db.components().insertPrivateProject();
354     SnapshotDto snapshot = dbClient.snapshotDao().insert(dbSession, newAnalysis(project));
355     dbSession.commit();
356     userSession.logIn();
357
358     assertThatThrownBy(() -> ws.newRequest()
359       .setParam(PARAM_ANALYSIS_ID, snapshot.getUuid())
360       .executeProtobuf(ProjectStatusResponse.class))
361       .isInstanceOf(ForbiddenException.class);
362   }
363
364   @Test
365   public void fail_if_project_id_and_ce_task_id_provided() {
366     ComponentDto project = db.components().insertPrivateProject();
367     logInAsSystemAdministrator();
368
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");
375   }
376
377   @Test
378   public void fail_if_branch_key_and_pull_request_id_provided() {
379     ComponentDto project = db.components().insertPrivateProject();
380     logInAsSystemAdministrator();
381
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");
389   }
390
391   @Test
392   public void fail_if_no_parameter_provided() {
393     logInAsSystemAdministrator();
394
395     assertThatThrownBy(() -> ws.newRequest()
396       .execute().getInput())
397       .isInstanceOf(BadRequestException.class)
398       .hasMessageContaining("Either 'analysisId', 'projectId' or 'projectKey' must be provided");
399   }
400
401   @Test
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);
407
408     assertThatThrownBy(() -> ws.newRequest()
409       .setParam(PARAM_PROJECT_KEY, branch.getDbKey())
410       .execute())
411       .isInstanceOf(NotFoundException.class)
412       .hasMessageContaining(format("Project '%s' not found", branch.getDbKey()));
413   }
414
415   @Test
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);
421
422     assertThatThrownBy(() -> ws.newRequest()
423       .setParam("projectId", branch.uuid())
424       .execute())
425       .isInstanceOf(NotFoundException.class)
426       .hasMessageContaining(format("Project '%s' not found", branch.uuid()));
427   }
428
429   private void logInAsSystemAdministrator() {
430     userSession.logIn().setSystemAdministrator();
431   }
432
433   private MetricDto insertGateDetailMetric() {
434     return dbClient.metricDao().insert(dbSession, newMetricDto()
435       .setEnabled(true)
436       .setKey(CoreMetrics.QUALITY_GATE_DETAILS_KEY));
437   }
438
439 }