123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454 |
- /*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
- package org.sonar.server.qualitygate.ws;
-
- import java.io.IOException;
- import java.nio.charset.StandardCharsets;
- import org.apache.commons.io.IOUtils;
- import org.apache.commons.lang.RandomStringUtils;
- import org.junit.Rule;
- import org.junit.Test;
- import org.sonar.api.measures.CoreMetrics;
- import org.sonar.api.server.ws.WebService;
- import org.sonar.api.utils.System2;
- import org.sonar.api.web.UserRole;
- import org.sonar.db.DbClient;
- import org.sonar.db.DbSession;
- import org.sonar.db.DbTester;
- import org.sonar.db.component.BranchType;
- import org.sonar.db.component.ComponentDto;
- import org.sonar.db.component.SnapshotDto;
- import org.sonar.db.metric.MetricDto;
- import org.sonar.db.permission.GlobalPermission;
- import org.sonar.db.qualitygate.QualityGateDto;
- import org.sonar.server.component.TestComponentFinder;
- import org.sonar.server.exceptions.BadRequestException;
- import org.sonar.server.exceptions.ForbiddenException;
- import org.sonar.server.exceptions.NotFoundException;
- import org.sonar.server.qualitygate.QualityGateCaycChecker;
- import org.sonar.server.tester.UserSessionRule;
- import org.sonar.server.ws.WsActionTester;
- import org.sonarqube.ws.Qualitygates.ProjectStatusResponse;
- import org.sonarqube.ws.Qualitygates.ProjectStatusResponse.Status;
-
- import static java.lang.String.format;
- import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
- import static org.assertj.core.api.Assertions.assertThat;
- import static org.assertj.core.api.Assertions.assertThatThrownBy;
- import static org.assertj.core.api.Assertions.tuple;
- import static org.mockito.ArgumentMatchers.any;
- import static org.mockito.ArgumentMatchers.eq;
- import static org.mockito.Mockito.mock;
- import static org.mockito.Mockito.when;
- import static org.sonar.db.component.SnapshotTesting.newAnalysis;
- import static org.sonar.db.measure.MeasureTesting.newLiveMeasure;
- import static org.sonar.db.measure.MeasureTesting.newMeasureDto;
- import static org.sonar.db.metric.MetricTesting.newMetricDto;
- import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_ANALYSIS_ID;
- import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_BRANCH;
- import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_PROJECT_ID;
- import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_PROJECT_KEY;
- import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_PULL_REQUEST;
- import static org.sonar.test.JsonAssert.assertJson;
-
- public class ProjectStatusActionTest {
- private static final String ANALYSIS_ID = "task-uuid";
-
- @Rule
- public UserSessionRule userSession = UserSessionRule.standalone();
- @Rule
- public DbTester db = DbTester.create(System2.INSTANCE);
-
- private final DbClient dbClient = db.getDbClient();
- private final DbSession dbSession = db.getSession();
- private final QualityGateCaycChecker qualityGateCaycChecker = mock(QualityGateCaycChecker.class);
-
- private final WsActionTester ws = new WsActionTester(new ProjectStatusAction(dbClient, TestComponentFinder.from(db), userSession, qualityGateCaycChecker));
-
- @Test
- public void test_definition() {
- WebService.Action action = ws.getDef();
- assertThat(action.params())
- .extracting(WebService.Param::key, WebService.Param::isRequired)
- .containsExactlyInAnyOrder(
- tuple("analysisId", false),
- tuple("projectKey", false),
- tuple("projectId", false),
- tuple("branch", false),
- tuple("pullRequest", false));
- }
-
- @Test
- public void test_json_example() throws IOException {
- ComponentDto project = db.components().insertPrivateProject();
- userSession.addProjectPermission(UserRole.USER, project);
- MetricDto gateDetailsMetric = insertGateDetailMetric();
-
- SnapshotDto snapshot = dbClient.snapshotDao().insert(dbSession, newAnalysis(project)
- .setPeriodMode("last_version")
- .setPeriodParam("2015-12-07")
- .setPeriodDate(956789123987L));
- dbClient.measureDao().insert(dbSession,
- newMeasureDto(gateDetailsMetric, project, snapshot)
- .setData(IOUtils.toString(getClass().getResource("ProjectStatusActionTest/measure_data.json"), StandardCharsets.UTF_8)));
- dbSession.commit();
-
- String response = ws.newRequest()
- .setParam("analysisId", snapshot.getUuid())
- .execute().getInput();
-
- assertJson(response).isSimilarTo(getClass().getResource("project_status-example.json"));
- }
-
- @Test
- public void return_past_status_when_project_is_referenced_by_past_analysis_id() throws IOException {
- ComponentDto project = db.components().insertPrivateProject();
- SnapshotDto pastAnalysis = dbClient.snapshotDao().insert(dbSession, newAnalysis(project)
- .setLast(false)
- .setPeriodMode("last_version")
- .setPeriodParam("2015-12-07")
- .setPeriodDate(956789123987L));
- SnapshotDto lastAnalysis = dbClient.snapshotDao().insert(dbSession, newAnalysis(project)
- .setLast(true)
- .setPeriodMode("last_version")
- .setPeriodParam("2016-12-07")
- .setPeriodDate(1_500L));
- MetricDto gateDetailsMetric = insertGateDetailMetric();
- dbClient.measureDao().insert(dbSession,
- newMeasureDto(gateDetailsMetric, project, pastAnalysis)
- .setData(IOUtils.toString(getClass().getResource("ProjectStatusActionTest/measure_data.json"))));
- dbClient.measureDao().insert(dbSession,
- newMeasureDto(gateDetailsMetric, project, lastAnalysis)
- .setData("not_used"));
- dbSession.commit();
- userSession.addProjectPermission(UserRole.USER, project);
-
- String response = ws.newRequest()
- .setParam(PARAM_ANALYSIS_ID, pastAnalysis.getUuid())
- .execute().getInput();
-
- assertJson(response).isSimilarTo(getClass().getResource("project_status-example.json"));
- }
-
- @Test
- public void return_live_status_when_project_is_referenced_by_its_id() throws IOException {
- ComponentDto project = db.components().insertPrivateProject();
- dbClient.snapshotDao().insert(dbSession, newAnalysis(project)
- .setPeriodMode("last_version")
- .setPeriodParam("2015-12-07")
- .setPeriodDate(956789123987L));
- MetricDto gateDetailsMetric = insertGateDetailMetric();
- dbClient.liveMeasureDao().insert(dbSession,
- newLiveMeasure(project, gateDetailsMetric)
- .setData(IOUtils.toString(getClass().getResource("ProjectStatusActionTest/measure_data.json"))));
- dbSession.commit();
- userSession.addProjectPermission(UserRole.USER, project);
-
- String response = ws.newRequest()
- .setParam(PARAM_PROJECT_ID, project.uuid())
- .execute().getInput();
-
- assertJson(response).isSimilarTo(getClass().getResource("project_status-example.json"));
- }
-
- @Test
- public void return_past_status_when_branch_is_referenced_by_past_analysis_id() throws IOException {
- ComponentDto project = db.components().insertPrivateProject();
- ComponentDto branch = db.components().insertProjectBranch(project);
- SnapshotDto pastAnalysis = dbClient.snapshotDao().insert(dbSession, newAnalysis(branch)
- .setLast(false)
- .setPeriodMode("last_version")
- .setPeriodParam("2015-12-07")
- .setPeriodDate(956789123987L));
- SnapshotDto lastAnalysis = dbClient.snapshotDao().insert(dbSession, newAnalysis(branch)
- .setLast(true)
- .setPeriodMode("last_version")
- .setPeriodParam("2016-12-07")
- .setPeriodDate(1_500L));
- MetricDto gateDetailsMetric = insertGateDetailMetric();
- dbClient.measureDao().insert(dbSession,
- newMeasureDto(gateDetailsMetric, branch, pastAnalysis)
- .setData(IOUtils.toString(getClass().getResource("ProjectStatusActionTest/measure_data.json"))));
- dbClient.measureDao().insert(dbSession,
- newMeasureDto(gateDetailsMetric, branch, lastAnalysis)
- .setData("not_used"));
- dbSession.commit();
- userSession.addProjectPermission(UserRole.USER, project);
-
- String response = ws.newRequest()
- .setParam(PARAM_ANALYSIS_ID, pastAnalysis.getUuid())
- .execute().getInput();
-
- assertJson(response).isSimilarTo(getClass().getResource("project_status-example.json"));
- }
-
- @Test
- public void return_live_status_when_project_is_referenced_by_its_key() throws IOException {
- ComponentDto project = db.components().insertPrivateProject();
- dbClient.snapshotDao().insert(dbSession, newAnalysis(project)
- .setPeriodMode("last_version")
- .setPeriodParam("2015-12-07")
- .setPeriodDate(956789123987L));
- MetricDto gateDetailsMetric = insertGateDetailMetric();
- dbClient.liveMeasureDao().insert(dbSession,
- newLiveMeasure(project, gateDetailsMetric)
- .setData(IOUtils.toString(getClass().getResource("ProjectStatusActionTest/measure_data.json"))));
- dbSession.commit();
- userSession.addProjectPermission(UserRole.USER, project);
-
- String response = ws.newRequest()
- .setParam(PARAM_PROJECT_KEY, project.getKey())
- .execute().getInput();
-
- assertJson(response).isSimilarTo(getClass().getResource("project_status-example.json"));
- }
-
- @Test
- public void return_live_status_when_branch_is_referenced_by_its_key() throws IOException {
- ComponentDto project = db.components().insertPrivateProject();
- String branchName = randomAlphanumeric(248);
- ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey(branchName));
-
- dbClient.snapshotDao().insert(dbSession, newAnalysis(branch)
- .setPeriodMode("last_version")
- .setPeriodParam("2015-12-07")
- .setPeriodDate(956789123987L));
- MetricDto gateDetailsMetric = insertGateDetailMetric();
- dbClient.liveMeasureDao().insert(dbSession,
- newLiveMeasure(branch, gateDetailsMetric)
- .setData(IOUtils.toString(getClass().getResource("ProjectStatusActionTest/measure_data.json"))));
- dbSession.commit();
- userSession.addProjectPermission(UserRole.USER, project);
-
- String response = ws.newRequest()
- .setParam(PARAM_PROJECT_KEY, project.getKey())
- .setParam(PARAM_BRANCH, branchName)
- .execute().getInput();
-
- assertJson(response).isSimilarTo(getClass().getResource("project_status-example.json"));
- }
-
- @Test
- public void return_live_status_when_pull_request_is_referenced_by_its_key() throws IOException {
- ComponentDto project = db.components().insertPrivateProject();
- String pullRequestKey = RandomStringUtils.randomAlphanumeric(100);
- ComponentDto pr = db.components().insertProjectBranch(project, branch -> branch.setBranchType(BranchType.PULL_REQUEST)
- .setKey(pullRequestKey));
-
- dbClient.snapshotDao().insert(dbSession, newAnalysis(pr)
- .setPeriodMode("last_version")
- .setPeriodParam("2015-12-07")
- .setPeriodDate(956789123987L));
- MetricDto gateDetailsMetric = insertGateDetailMetric();
- dbClient.liveMeasureDao().insert(dbSession,
- newLiveMeasure(pr, gateDetailsMetric)
- .setData(IOUtils.toString(getClass().getResource("ProjectStatusActionTest/measure_data.json"))));
- dbSession.commit();
- userSession.addProjectPermission(UserRole.USER, project);
-
- String response = ws.newRequest()
- .setParam(PARAM_PROJECT_KEY, project.getKey())
- .setParam(PARAM_PULL_REQUEST, pullRequestKey)
- .execute().getInput();
-
- assertJson(response).isSimilarTo(getClass().getResource("project_status-example.json"));
- }
-
- @Test
- public void return_undefined_status_if_specified_analysis_is_not_found() {
- ComponentDto project = db.components().insertPrivateProject();
- SnapshotDto snapshot = dbClient.snapshotDao().insert(dbSession, newAnalysis(project));
- dbSession.commit();
- userSession.addProjectPermission(UserRole.USER, project);
-
- ProjectStatusResponse result = ws.newRequest()
- .setParam(PARAM_ANALYSIS_ID, snapshot.getUuid())
- .executeProtobuf(ProjectStatusResponse.class);
-
- assertThat(result.getProjectStatus().getStatus()).isEqualTo(Status.NONE);
- assertThat(result.getProjectStatus().getConditionsCount()).isZero();
- }
-
- @Test
- public void return_undefined_status_if_project_is_not_analyzed() {
- ComponentDto project = db.components().insertPrivateProject();
- userSession.addProjectPermission(UserRole.USER, project);
-
- ProjectStatusResponse result = ws.newRequest()
- .setParam(PARAM_PROJECT_ID, project.uuid())
- .executeProtobuf(ProjectStatusResponse.class);
-
- assertThat(result.getProjectStatus().getStatus()).isEqualTo(Status.NONE);
- assertThat(result.getProjectStatus().getConditionsCount()).isZero();
- }
-
- @Test
- public void project_administrator_is_allowed_to_get_project_status() {
- ComponentDto project = db.components().insertPrivateProject();
- SnapshotDto snapshot = dbClient.snapshotDao().insert(dbSession, newAnalysis(project));
- dbSession.commit();
- userSession.addProjectPermission(UserRole.ADMIN, project);
-
- ws.newRequest()
- .setParam(PARAM_ANALYSIS_ID, snapshot.getUuid())
- .executeProtobuf(ProjectStatusResponse.class);
- }
-
- @Test
- public void project_user_is_allowed_to_get_project_status() {
- ComponentDto project = db.components().insertPrivateProject();
- SnapshotDto snapshot = dbClient.snapshotDao().insert(dbSession, newAnalysis(project));
- dbSession.commit();
- userSession.addProjectPermission(UserRole.USER, project);
-
- ws.newRequest()
- .setParam(PARAM_ANALYSIS_ID, snapshot.getUuid())
- .executeProtobuf(ProjectStatusResponse.class);
- }
-
- @Test
- public void check_cayc_compliant_flag() {
- ComponentDto project = db.components().insertPrivateProject();
- var qg = db.qualityGates().insertBuiltInQualityGate();
- db.qualityGates().setDefaultQualityGate(qg);
- when(qualityGateCaycChecker.checkCaycCompliantFromProject(any(DbSession.class), eq(project.uuid()))).thenReturn(true);
- SnapshotDto snapshot = dbClient.snapshotDao().insert(dbSession, newAnalysis(project));
- dbSession.commit();
- userSession.addProjectPermission(UserRole.USER, project);
-
- ProjectStatusResponse result = ws.newRequest()
- .setParam(PARAM_ANALYSIS_ID, snapshot.getUuid())
- .executeProtobuf(ProjectStatusResponse.class);
-
- assertThat(result.getProjectStatus().getIsCaycCompliant()).isTrue();
- }
-
- @Test
- public void user_with_project_scan_permission_is_allowed_to_get_project_status() {
- ComponentDto project = db.components().insertPrivateProject();
- SnapshotDto snapshot = dbClient.snapshotDao().insert(dbSession, newAnalysis(project));
- dbSession.commit();
- userSession.addProjectPermission(UserRole.SCAN, project);
-
- var response = ws.newRequest()
- .setParam(PARAM_ANALYSIS_ID, snapshot.getUuid()).execute();
-
- assertThat(response.getStatus()).isEqualTo(200);
- }
-
- @Test
- public void user_with_global_scan_permission_is_allowed_to_get_project_status() {
- ComponentDto project = db.components().insertPrivateProject();
- SnapshotDto snapshot = dbClient.snapshotDao().insert(dbSession, newAnalysis(project));
- dbSession.commit();
- userSession.addPermission(GlobalPermission.SCAN);
-
- var response = ws.newRequest()
- .setParam(PARAM_ANALYSIS_ID, snapshot.getUuid()).execute();
-
- assertThat(response.getStatus()).isEqualTo(200);
- }
-
- @Test
- public void fail_if_no_snapshot_id_found() {
- logInAsSystemAdministrator();
-
- assertThatThrownBy(() -> ws.newRequest()
- .setParam(PARAM_ANALYSIS_ID, ANALYSIS_ID)
- .executeProtobuf(ProjectStatusResponse.class))
- .isInstanceOf(NotFoundException.class)
- .hasMessageContaining("Analysis with id 'task-uuid' is not found");
- }
-
- @Test
- public void fail_if_insufficient_privileges() {
- ComponentDto project = db.components().insertPrivateProject();
- SnapshotDto snapshot = dbClient.snapshotDao().insert(dbSession, newAnalysis(project));
- dbSession.commit();
- userSession.logIn();
-
- assertThatThrownBy(() -> ws.newRequest()
- .setParam(PARAM_ANALYSIS_ID, snapshot.getUuid())
- .executeProtobuf(ProjectStatusResponse.class))
- .isInstanceOf(ForbiddenException.class);
- }
-
- @Test
- public void fail_if_project_id_and_ce_task_id_provided() {
- ComponentDto project = db.components().insertPrivateProject();
- logInAsSystemAdministrator();
-
- assertThatThrownBy(() -> ws.newRequest()
- .setParam(PARAM_ANALYSIS_ID, "analysis-id")
- .setParam(PARAM_PROJECT_ID, "project-uuid")
- .execute().getInput())
- .isInstanceOf(BadRequestException.class)
- .hasMessageContaining("Either 'analysisId', 'projectId' or 'projectKey' must be provided");
- }
-
- @Test
- public void fail_if_branch_key_and_pull_request_id_provided() {
- ComponentDto project = db.components().insertPrivateProject();
- logInAsSystemAdministrator();
-
- assertThatThrownBy(() -> ws.newRequest()
- .setParam(PARAM_PROJECT_KEY, "key")
- .setParam(PARAM_BRANCH, "branch")
- .setParam(PARAM_PULL_REQUEST, "pr")
- .execute().getInput())
- .isInstanceOf(BadRequestException.class)
- .hasMessageContaining("Either 'branch' or 'pullRequest' can be provided, not both");
- }
-
- @Test
- public void fail_if_no_parameter_provided() {
- logInAsSystemAdministrator();
-
- assertThatThrownBy(() -> ws.newRequest()
- .execute().getInput())
- .isInstanceOf(BadRequestException.class)
- .hasMessageContaining("Either 'analysisId', 'projectId' or 'projectKey' must be provided");
- }
-
- @Test
- public void fail_when_using_branch_uuid() {
- ComponentDto project = db.components().insertPublicProject();
- userSession.logIn().addProjectPermission(UserRole.ADMIN, project);
- ComponentDto branch = db.components().insertProjectBranch(project);
- SnapshotDto snapshot = db.components().insertSnapshot(branch);
-
- assertThatThrownBy(() -> ws.newRequest()
- .setParam("projectId", branch.uuid())
- .execute())
- .isInstanceOf(NotFoundException.class)
- .hasMessageContaining(format("Project '%s' not found", branch.uuid()));
- }
-
- private void logInAsSystemAdministrator() {
- userSession.logIn().setSystemAdministrator();
- }
-
- private MetricDto insertGateDetailMetric() {
- return dbClient.metricDao().insert(dbSession, newMetricDto()
- .setEnabled(true)
- .setKey(CoreMetrics.QUALITY_GATE_DETAILS_KEY));
- }
-
- }
|