From: Julien Lancelot Date: Thu, 14 Dec 2017 11:04:32 +0000 (+0100) Subject: SONAR-10134 Move QgateProjectFinder code to SearchAction X-Git-Tag: 7.0-RC1~107 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=b286480804ac3785431e3c44f07e25dac5dbaea7;p=sonarqube.git SONAR-10134 Move QgateProjectFinder code to SearchAction --- diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/qualitygate/ProjectQgateAssociationQuery.java b/server/sonar-db-dao/src/main/java/org/sonar/db/qualitygate/ProjectQgateAssociationQuery.java index 0aa8ef35026..3962d8f6ff8 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/qualitygate/ProjectQgateAssociationQuery.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/qualitygate/ProjectQgateAssociationQuery.java @@ -54,7 +54,7 @@ public class ProjectQgateAssociationQuery { private final int pageIndex; private ProjectQgateAssociationQuery(Builder builder) { - this.gateId = builder.gateId; + this.gateId = Long.toString(builder.gateId); this.membership = builder.membership; this.projectSearch = builder.projectSearch; if (this.projectSearch == null) { @@ -97,7 +97,7 @@ public class ProjectQgateAssociationQuery { } public static class Builder { - private String gateId; + private long gateId; private String membership; private String projectSearch; @@ -107,7 +107,7 @@ public class ProjectQgateAssociationQuery { private Builder() { } - public Builder gateId(String gateId) { + public Builder gateId(long gateId) { this.gateId = gateId; return this; } @@ -155,7 +155,6 @@ public class ProjectQgateAssociationQuery { } public ProjectQgateAssociationQuery build() { - Preconditions.checkNotNull(gateId, "Gate ID cannot be null."); initMembership(); initPageIndex(); initPageSize(); diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/qualitygate/ProjectQgateAssociationDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/qualitygate/ProjectQgateAssociationDaoTest.java index df22238b152..f79bd01d847 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/qualitygate/ProjectQgateAssociationDaoTest.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/qualitygate/ProjectQgateAssociationDaoTest.java @@ -19,11 +19,8 @@ */ package org.sonar.db.qualitygate; -import static org.assertj.core.api.Assertions.assertThat; - import java.util.List; import java.util.Optional; - import org.junit.Rule; import org.junit.Test; import org.sonar.api.utils.System2; @@ -33,6 +30,8 @@ import org.sonar.db.DbTester; import org.sonar.db.component.ComponentDto; import org.sonar.db.property.PropertyDto; +import static org.assertj.core.api.Assertions.assertThat; + public class ProjectQgateAssociationDaoTest { @Rule @@ -46,7 +45,7 @@ public class ProjectQgateAssociationDaoTest { public void select_all_projects_by_query() { db.prepareDbUnit(getClass(), "shared.xml"); - ProjectQgateAssociationQuery query = ProjectQgateAssociationQuery.builder().gateId("42").build(); + ProjectQgateAssociationQuery query = ProjectQgateAssociationQuery.builder().gateId(42L).build(); List result = underTest.selectProjects(dbSession, query); assertThat(result).hasSize(5); } @@ -55,22 +54,22 @@ public class ProjectQgateAssociationDaoTest { public void select_projects_by_query() { db.prepareDbUnit(getClass(), "shared.xml"); - assertThat(underTest.selectProjects(dbSession, ProjectQgateAssociationQuery.builder().gateId("42").membership(ProjectQgateAssociationQuery.IN).build())).hasSize(3); - assertThat(underTest.selectProjects(dbSession, ProjectQgateAssociationQuery.builder().gateId("42").membership(ProjectQgateAssociationQuery.OUT).build())).hasSize(2); + assertThat(underTest.selectProjects(dbSession, ProjectQgateAssociationQuery.builder().gateId(42L).membership(ProjectQgateAssociationQuery.IN).build())).hasSize(3); + assertThat(underTest.selectProjects(dbSession, ProjectQgateAssociationQuery.builder().gateId(42L).membership(ProjectQgateAssociationQuery.OUT).build())).hasSize(2); } @Test public void search_by_project_name() { db.prepareDbUnit(getClass(), "shared.xml"); - List result = underTest.selectProjects(dbSession, ProjectQgateAssociationQuery.builder().gateId("42").projectSearch("one").build()); + List result = underTest.selectProjects(dbSession, ProjectQgateAssociationQuery.builder().gateId(42L).projectSearch("one").build()); assertThat(result).hasSize(1); assertThat(result.get(0).getName()).isEqualTo("Project One"); - result = underTest.selectProjects(dbSession, ProjectQgateAssociationQuery.builder().gateId("42").projectSearch("one").build()); + result = underTest.selectProjects(dbSession, ProjectQgateAssociationQuery.builder().gateId(42L).projectSearch("one").build()); assertThat(result).hasSize(1); - result = underTest.selectProjects(dbSession, ProjectQgateAssociationQuery.builder().gateId("42").projectSearch("project").build()); + result = underTest.selectProjects(dbSession, ProjectQgateAssociationQuery.builder().gateId(42L).projectSearch("project").build()); assertThat(result).hasSize(5); } @@ -78,7 +77,7 @@ public class ProjectQgateAssociationDaoTest { public void should_be_sorted_by_project_name() { db.prepareDbUnit(getClass(), "shared.xml"); - List result = underTest.selectProjects(dbSession, ProjectQgateAssociationQuery.builder().gateId("42").build()); + List result = underTest.selectProjects(dbSession, ProjectQgateAssociationQuery.builder().gateId(42L).build()); assertThat(result).hasSize(5); assertThat(result.get(0).getName()).isEqualTo("Project Five"); assertThat(result.get(1).getName()).isEqualTo("Project Four"); diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/qualitygate/ProjectQgateAssociationQueryTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/qualitygate/ProjectQgateAssociationQueryTest.java index 0b6eca27135..2ff682b9b30 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/qualitygate/ProjectQgateAssociationQueryTest.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/qualitygate/ProjectQgateAssociationQueryTest.java @@ -28,24 +28,13 @@ public class ProjectQgateAssociationQueryTest { @Rule public ExpectedException expectedException = ExpectedException.none(); - @Test - public void fail_on_null_login() { - expectedException.expect(NullPointerException.class); - expectedException.expectMessage("Gate ID cannot be null"); - - ProjectQgateAssociationQuery.Builder builder = ProjectQgateAssociationQuery.builder() - .gateId(null); - - builder.build(); - } - @Test public void fail_on_invalid_membership() { expectedException.expect(IllegalArgumentException.class); expectedException.expectMessage("Membership is not valid (got unknown). Available values are [all, selected, deselected]"); ProjectQgateAssociationQuery.Builder builder = ProjectQgateAssociationQuery.builder(); - builder.gateId("nelson"); + builder.gateId(42L); builder.membership("unknown"); builder.build(); diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QgateProjectFinder.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QgateProjectFinder.java deleted file mode 100644 index 4f561bd8d5a..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QgateProjectFinder.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2017 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; - -import java.util.Collection; -import java.util.List; -import org.sonar.api.server.ServerSide; -import org.sonar.api.utils.Paging; -import org.sonar.api.web.UserRole; -import org.sonar.core.util.stream.MoreCollectors; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.organization.OrganizationDto; -import org.sonar.db.qualitygate.ProjectQgateAssociation; -import org.sonar.db.qualitygate.ProjectQgateAssociationDao; -import org.sonar.db.qualitygate.ProjectQgateAssociationDto; -import org.sonar.db.qualitygate.ProjectQgateAssociationQuery; -import org.sonar.db.qualitygate.QualityGateDao; -import org.sonar.server.user.UserSession; - -import static org.sonar.api.utils.Paging.forPageIndex; -import static org.sonar.server.ws.WsUtils.checkFound; - -@ServerSide -public class QgateProjectFinder { - - private final DbClient dbClient; - private final QualityGateDao qualitygateDao; - private final ProjectQgateAssociationDao associationDao; - private final UserSession userSession; - - public QgateProjectFinder(DbClient dbClient, UserSession userSession) { - this.dbClient = dbClient; - this.userSession = userSession; - this.qualitygateDao = dbClient.qualityGateDao(); - this.associationDao = dbClient.projectQgateAssociationDao(); - } - - public Association find(DbSession dbSession, OrganizationDto organization, ProjectQgateAssociationQuery query) { - getQualityGateId(dbSession, organization, query.gateId()); - List projects = associationDao.selectProjects(dbSession, query); - List authorizedProjects = keepAuthorizedProjects(dbSession, projects); - - Paging paging = forPageIndex(query.pageIndex()) - .withPageSize(query.pageSize()) - .andTotal(authorizedProjects.size()); - return new Association(toProjectAssociations(getPaginatedProjects(authorizedProjects, paging)), paging.hasNextPage()); - } - - private Long getQualityGateId(DbSession dbSession, OrganizationDto organization, String gateId) { - return checkFound(qualitygateDao.selectByOrganizationAndId(dbSession, organization, Long.valueOf(gateId)), "Quality gate '" + gateId + "' does not exists.").getId(); - } - - private static List getPaginatedProjects(List projects, Paging paging) { - return projects.stream().skip(paging.offset()).limit(paging.pageSize()).collect(MoreCollectors.toList()); - } - - private static List toProjectAssociations(List dtos) { - return dtos.stream().map(ProjectQgateAssociationDto::toQgateAssociation).collect(MoreCollectors.toList()); - } - - private List keepAuthorizedProjects(DbSession dbSession, List projects) { - if (userSession.isRoot()) { - // the method AuthorizationDao#keepAuthorizedProjectIds() should be replaced by - // a call to UserSession, which would transparently support roots. - // Meanwhile root is explicitly handled. - return projects; - } - List projectIds = projects.stream().map(ProjectQgateAssociationDto::getId).collect(MoreCollectors.toList()); - Collection authorizedProjectIds = dbClient.authorizationDao().keepAuthorizedProjectIds(dbSession, projectIds, userSession.getUserId(), UserRole.USER); - return projects.stream().filter(project -> authorizedProjectIds.contains(project.getId())).collect(MoreCollectors.toList()); - } - - public static class Association { - private List projects; - private boolean hasMoreResults; - - private Association(List projects, boolean hasMoreResults) { - this.projects = projects; - this.hasMoreResults = hasMoreResults; - } - - public List projects() { - return projects; - } - - public boolean hasMoreResults() { - return hasMoreResults; - } - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateModule.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateModule.java index 03d1e9c3492..7eeb365fefd 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateModule.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateModule.java @@ -44,7 +44,6 @@ public class QualityGateModule extends Module { add( QualityGateUpdater.class, QualityGateConditionsUpdater.class, - QgateProjectFinder.class, QualityGateFinder.class, // WS QualityGatesWsSupport.class, diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/SearchAction.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/SearchAction.java index 67d4e1b905c..bca22fd5672 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/SearchAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/SearchAction.java @@ -20,18 +20,26 @@ package org.sonar.server.qualitygate.ws; import com.google.common.io.Resources; +import java.util.Collection; +import java.util.List; import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; +import org.sonar.api.utils.Paging; +import org.sonar.api.web.UserRole; +import org.sonar.core.util.stream.MoreCollectors; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.organization.OrganizationDto; import org.sonar.db.qualitygate.ProjectQgateAssociation; +import org.sonar.db.qualitygate.ProjectQgateAssociationDto; import org.sonar.db.qualitygate.ProjectQgateAssociationQuery; -import org.sonar.server.qualitygate.QgateProjectFinder; +import org.sonar.server.qualitygate.QualityGateFinder; +import org.sonar.server.user.UserSession; import org.sonarqube.ws.Qualitygates; import static org.sonar.api.server.ws.WebService.Param.SELECTED; +import static org.sonar.api.utils.Paging.forPageIndex; import static org.sonar.db.qualitygate.ProjectQgateAssociationQuery.ANY; import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_GATE_ID; import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_PAGE; @@ -42,12 +50,14 @@ import static org.sonar.server.ws.WsUtils.writeProtobuf; public class SearchAction implements QualityGatesWsAction { private final DbClient dbClient; - private final QgateProjectFinder projectFinder; + private final UserSession userSession; + private QualityGateFinder qualityGateFinder; private final QualityGatesWsSupport wsSupport; - public SearchAction(DbClient dbClient, QgateProjectFinder projectFinder, QualityGatesWsSupport wsSupport) { + public SearchAction(DbClient dbClient, UserSession userSession, QualityGateFinder qualityGateFinder, QualityGatesWsSupport wsSupport) { this.dbClient = dbClient; - this.projectFinder = projectFinder; + this.userSession = userSession; + this.qualityGateFinder = qualityGateFinder; this.wsSupport = wsSupport; } @@ -85,14 +95,12 @@ public class SearchAction implements QualityGatesWsAction { @Override public void handle(Request request, Response response) { - try (DbSession dbSession = dbClient.openSession(false)) { OrganizationDto organization = wsSupport.getOrganization(dbSession, request); - - QgateProjectFinder.Association associations = projectFinder.find(dbSession, organization, + Association associations = find(dbSession, organization, ProjectQgateAssociationQuery.builder() - .gateId(request.mandatoryParam(PARAM_GATE_ID)) + .gateId(request.mandatoryParamAsLong(PARAM_GATE_ID)) .membership(request.param(PARAM_QUERY) == null ? request.param(SELECTED) : ANY) .projectSearch(request.param(PARAM_QUERY)) .pageIndex(request.paramAsInt(PARAM_PAGE)) @@ -110,7 +118,55 @@ public class SearchAction implements QualityGatesWsAction { } writeProtobuf(createResponse.build(), request, response); + } + } + + private SearchAction.Association find(DbSession dbSession, OrganizationDto organization, ProjectQgateAssociationQuery query) { + qualityGateFinder.getByOrganizationAndId(dbSession, organization, Long.parseLong(query.gateId())); + List projects = dbClient.projectQgateAssociationDao().selectProjects(dbSession, query); + List authorizedProjects = keepAuthorizedProjects(dbSession, projects); + + Paging paging = forPageIndex(query.pageIndex()) + .withPageSize(query.pageSize()) + .andTotal(authorizedProjects.size()); + return new SearchAction.Association(toProjectAssociations(getPaginatedProjects(authorizedProjects, paging)), paging.hasNextPage()); + } + + private static List getPaginatedProjects(List projects, Paging paging) { + return projects.stream().skip(paging.offset()).limit(paging.pageSize()).collect(MoreCollectors.toList()); + } + + private static List toProjectAssociations(List dtos) { + return dtos.stream().map(ProjectQgateAssociationDto::toQgateAssociation).collect(MoreCollectors.toList()); + } + + private List keepAuthorizedProjects(DbSession dbSession, List projects) { + if (userSession.isRoot()) { + // the method AuthorizationDao#keepAuthorizedProjectIds() should be replaced by + // a call to UserSession, which would transparently support roots. + // Meanwhile root is explicitly handled. + return projects; + } + List projectIds = projects.stream().map(ProjectQgateAssociationDto::getId).collect(MoreCollectors.toList()); + Collection authorizedProjectIds = dbClient.authorizationDao().keepAuthorizedProjectIds(dbSession, projectIds, userSession.getUserId(), UserRole.USER); + return projects.stream().filter(project -> authorizedProjectIds.contains(project.getId())).collect(MoreCollectors.toList()); + } + + private static class Association { + private List projects; + private boolean hasMoreResults; + + private Association(List projects, boolean hasMoreResults) { + this.projects = projects; + this.hasMoreResults = hasMoreResults; + } + + public List projects() { + return projects; + } + public boolean hasMoreResults() { + return hasMoreResults; } } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QgateProjectFinderTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QgateProjectFinderTest.java deleted file mode 100644 index 93f491c659a..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QgateProjectFinderTest.java +++ /dev/null @@ -1,293 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2017 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; - -import com.google.common.base.Function; -import java.util.List; -import java.util.Map; -import javax.annotation.Nonnull; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.api.utils.System2; -import org.sonar.core.util.Uuids; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.DbTester; -import org.sonar.db.component.ComponentDbTester; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.organization.OrganizationDto; -import org.sonar.db.property.PropertyDto; -import org.sonar.db.qualitygate.ProjectQgateAssociation; -import org.sonar.db.qualitygate.ProjectQgateAssociationQuery; -import org.sonar.db.qualitygate.QualityGateDto; -import org.sonar.db.user.UserDto; -import org.sonar.server.exceptions.NotFoundException; -import org.sonar.server.qualitygate.QgateProjectFinder.Association; -import org.sonar.server.tester.UserSessionRule; - -import static com.google.common.collect.FluentIterable.from; -import static org.assertj.core.api.Assertions.assertThat; -import static org.sonar.api.web.UserRole.USER; -import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto; -import static org.sonar.db.component.ComponentTesting.newPublicProjectDto; -import static org.sonar.db.qualitygate.ProjectQgateAssociationQuery.IN; -import static org.sonar.db.qualitygate.ProjectQgateAssociationQuery.OUT; -import static org.sonar.db.qualitygate.ProjectQgateAssociationQuery.builder; -import static org.sonar.server.qualitygate.QualityGateFinder.SONAR_QUALITYGATE_PROPERTY; - -public class QgateProjectFinderTest { - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Rule - public UserSessionRule userSession = UserSessionRule.standalone(); - - @Rule - public DbTester dbTester = DbTester.create(System2.INSTANCE); - - private DbClient dbClient = dbTester.getDbClient(); - private DbSession dbSession = dbTester.getSession(); - private ComponentDbTester componentDbTester = new ComponentDbTester(dbTester); - private QgateProjectFinder underTest = new QgateProjectFinder(dbClient, userSession); - - @Test - public void return_empty_association() { - OrganizationDto organization = dbTester.organizations().insert(); - QualityGateDto qGate = dbTester.qualityGates().insertQualityGate(organization, - qualityGateDto -> qualityGateDto.setName("Default Quality Gate").setUuid(Uuids.createFast())); - dbTester.commit(); - - Association result = underTest.find(dbSession, organization, - builder() - .gateId(Long.toString(qGate.getId())) - .build()); - - assertThat(result.projects()).isEmpty(); - } - - @Test - public void return_all_projects() { - OrganizationDto organization = dbTester.organizations().insert(); - QualityGateDto qGate = dbTester.qualityGates().insertQualityGate(organization, - qualityGateDto -> qualityGateDto.setName("Default Quality Gate").setUuid(Uuids.createFast())); - dbTester.commit(); - ComponentDto unassociatedProject = newPublicProjectDto(organization); - dbTester.components().insertComponent(unassociatedProject); - ComponentDto associatedProject = newPublicProjectDto(organization); - dbTester.components().insertComponent(associatedProject); - associateProjectToQualitGate(associatedProject, qGate); - - Association result = underTest.find(dbSession, organization, - builder() - .gateId(Long.toString(qGate.getId())) - .build()); - - Map projectsById = projectsById(result.projects()); - assertThat(projectsById).hasSize(2); - - verifyProject(projectsById.get(associatedProject.getId()), true, associatedProject.name()); - verifyProject(projectsById.get(unassociatedProject.getId()), false, unassociatedProject.name()); - } - - @Test - public void return_only_associated_project() { - OrganizationDto organization = dbTester.organizations().insert(); - QualityGateDto qGate = dbTester.qualityGates().insertQualityGate(organization, - qualityGateDto -> qualityGateDto.setName("Default Quality Gate").setUuid(Uuids.createFast())); - dbTester.commit(); - ComponentDto project1 = newPublicProjectDto(organization); - dbTester.components().insertComponent(project1); - ComponentDto associatedProject = project1; - ComponentDto project = newPublicProjectDto(organization); - dbTester.components().insertComponent(project); - associateProjectToQualitGate(associatedProject, qGate); - - Association result = underTest.find(dbSession, organization, - builder() - .membership(IN) - .gateId(Long.toString(qGate.getId())) - .build()); - - Map projectsById = projectsById(result.projects()); - assertThat(projectsById).hasSize(1); - verifyProject(projectsById.get(associatedProject.getId()), true, associatedProject.name()); - } - - @Test - public void return_only_unassociated_project() { - OrganizationDto organization = dbTester.organizations().insert(); - QualityGateDto qGate = dbTester.qualityGates().insertQualityGate(organization, - qualityGateDto -> qualityGateDto.setName("Default Quality Gate").setUuid(Uuids.createFast())); - dbTester.commit(); - ComponentDto unAssociatedProject = newPublicProjectDto(organization); - dbTester.components().insertComponent(unAssociatedProject); - ComponentDto associatedProject = newPublicProjectDto(organization); - dbTester.components().insertComponent(associatedProject); - associateProjectToQualitGate(associatedProject, qGate); - - Association result = underTest.find(dbSession, organization, - builder() - .membership(OUT) - .gateId(Long.toString(qGate.getId())) - .build()); - - Map projectsById = projectsById(result.projects()); - assertThat(projectsById).hasSize(1); - verifyProject(projectsById.get(unAssociatedProject.getId()), false, unAssociatedProject.name()); - } - - @Test - public void return_only_authorized_projects() { - OrganizationDto organization = dbTester.organizations().insert(); - QualityGateDto qGate = dbTester.qualityGates().insertQualityGate(organization, - qualityGateDto -> qualityGateDto.setName("Default Quality Gate").setUuid(Uuids.createFast())); - dbTester.commit(); - UserDto user = dbTester.users().insertUser("a_login"); - ComponentDto project = componentDbTester.insertComponent(newPrivateProjectDto(organization)); - componentDbTester.insertComponent(newPrivateProjectDto(organization)); - - // User can only see project 1 - dbTester.users().insertProjectPermissionOnUser(user, USER, project); - - userSession.logIn(user.getLogin()).setUserId(user.getId()); - Association result = underTest.find(dbSession, organization, - builder() - .gateId(Long.toString(qGate.getId())) - .build()); - - verifyProjects(result, project.getId()); - } - - @Test - public void do_not_verify_permissions_if_user_is_root() { - OrganizationDto organization = dbTester.organizations().insert(); - QualityGateDto qGate = dbTester.qualityGates().insertQualityGate(organization, - qualityGateDto -> qualityGateDto.setName("Default Quality Gate").setUuid(Uuids.createFast())); - dbTester.commit(); - ComponentDto project = componentDbTester.insertPrivateProject(organization); - ProjectQgateAssociationQuery query = builder() - .gateId(Long.toString(qGate.getId())) - .build(); - - userSession.logIn().setNonRoot(); - verifyProjects(underTest.find(dbSession, organization, query)); - - userSession.logIn().setRoot(); - verifyProjects(underTest.find(dbSession, organization, query), project.getId()); - } - - @Test - public void test_paging() throws Exception { - OrganizationDto organization = dbTester.organizations().insert(); - QualityGateDto qGate = dbTester.qualityGates().insertQualityGate(organization, - qualityGateDto -> qualityGateDto.setName("Default Quality Gate").setUuid(Uuids.createFast())); - dbTester.commit(); - ComponentDto project1 = newPublicProjectDto(organization).setName("Project 1"); - dbTester.components().insertComponent(project1); - associateProjectToQualitGate(project1, qGate); - ComponentDto project2 = newPublicProjectDto(organization).setName("Project 2"); - dbTester.components().insertComponent(project2); - ComponentDto project3 = newPublicProjectDto(organization).setName("Project 3"); - dbTester.components().insertComponent(project3); - - // Return partial result on first page - verifyPaging(underTest.find(dbSession, organization, - builder().gateId(Long.toString(qGate.getId())) - .pageIndex(1) - .pageSize(1) - .build()), - true, project1.getId()); - - // Return partial result on second page - verifyPaging(underTest.find(dbSession, organization, - builder().gateId(Long.toString(qGate.getId())) - .pageIndex(2) - .pageSize(1) - .build()), - true, project2.getId()); - - // Return partial result on first page - verifyPaging(underTest.find(dbSession, organization, - builder().gateId(Long.toString(qGate.getId())) - .pageIndex(1) - .pageSize(2) - .build()), - true, project1.getId(), project2.getId()); - - // Return all result on first page - verifyPaging(underTest.find(dbSession, organization, - builder().gateId(Long.toString(qGate.getId())) - .pageIndex(1) - .pageSize(3) - .build()), - false, project1.getId(), project2.getId(), project3.getId()); - - // Return no result as page index is off limit - verifyPaging(underTest.find(dbSession, organization, - builder().gateId(Long.toString(qGate.getId())) - .pageIndex(3) - .pageSize(3) - .build()), - false); - } - - @Test - public void fail_on_unknown_quality_gate() { - expectedException.expect(NotFoundException.class); - underTest.find(dbSession, dbTester.organizations().insert(), builder().gateId("123").build()); - } - - private void verifyProject(ProjectQgateAssociation project, boolean expectedMembership, String expectedName) { - assertThat(project.isMember()).isEqualTo(expectedMembership); - assertThat(project.name()).isEqualTo(expectedName); - } - - private void verifyProjects(Association association, Long... expectedProjectIds) { - assertThat(association.projects()).extracting("id").containsOnly(expectedProjectIds); - } - - private void verifyPaging(Association association, boolean expectedHasMoreResults, Long... expectedProjectIds) { - assertThat(association.hasMoreResults()).isEqualTo(expectedHasMoreResults); - assertThat(association.projects()).extracting("id").containsOnly(expectedProjectIds); - } - - private void associateProjectToQualitGate(ComponentDto component, QualityGateDto qualityGate) { - dbClient.propertiesDao().saveProperty( - new PropertyDto().setKey(SONAR_QUALITYGATE_PROPERTY) - .setResourceId(component.getId()) - .setValue(Long.toString(qualityGate.getId()))); - dbTester.commit(); - } - - private static Map projectsById(List projects) { - return from(projects).uniqueIndex(ProjectToId.INSTANCE); - } - - private enum ProjectToId implements Function { - INSTANCE; - - @Override - public Long apply(@Nonnull ProjectQgateAssociation input) { - return input.id(); - } - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateModuleTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateModuleTest.java index afb06808535..63e25bf7e8d 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateModuleTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateModuleTest.java @@ -29,6 +29,6 @@ public class QualityGateModuleTest { public void verify_count_of_added_components() { ComponentContainer container = new ComponentContainer(); new QualityGateModule().configure(container); - assertThat(container.size()).isEqualTo(21 + 2); + assertThat(container.size()).isEqualTo(20 + 2); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/SearchActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/SearchActionTest.java index ebc4997eb21..4658e9edc59 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/SearchActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/SearchActionTest.java @@ -28,25 +28,30 @@ import org.sonar.db.DbSession; import org.sonar.db.DbTester; import org.sonar.db.component.ComponentDto; import org.sonar.db.organization.OrganizationDto; -import org.sonar.db.property.PropertyDto; import org.sonar.db.qualitygate.QualityGateDto; +import org.sonar.db.user.UserDto; import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.organization.TestDefaultOrganizationProvider; -import org.sonar.server.qualitygate.QgateProjectFinder; +import org.sonar.server.qualitygate.QualityGateFinder; import org.sonar.server.tester.UserSessionRule; import org.sonar.server.ws.WsActionTester; import org.sonarqube.ws.Qualitygates.SearchResponse; +import org.sonarqube.ws.Qualitygates.SearchResponse.Result; import static java.lang.String.format; import static java.lang.String.valueOf; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.AssertionsForClassTypes.tuple; -import static org.sonar.api.utils.System2.INSTANCE; +import static org.sonar.api.server.ws.WebService.SelectionMode.ALL; +import static org.sonar.api.server.ws.WebService.SelectionMode.DESELECTED; +import static org.sonar.api.server.ws.WebService.SelectionMode.SELECTED; +import static org.sonar.api.web.UserRole.USER; import static org.sonar.db.permission.OrganizationPermission.ADMINISTER_QUALITY_GATES; import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_GATE_ID; import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_ORGANIZATION; import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_PAGE; import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_PAGE_SIZE; +import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_SELECTED; public class SearchActionTest { @@ -57,16 +62,14 @@ public class SearchActionTest { public UserSessionRule userSession = UserSessionRule.standalone(); @Rule - public DbTester db = DbTester.create(INSTANCE); + public DbTester db = DbTester.create(); private DbClient dbClient = db.getDbClient(); private DbSession dbSession = db.getSession(); private TestDefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(db); - private QgateProjectFinder projectFinder = new QgateProjectFinder(dbClient, userSession); - private QualityGatesWsSupport wsSupport = new QualityGatesWsSupport(dbClient, userSession, defaultOrganizationProvider); - - private SearchAction underTest = new SearchAction(dbClient, projectFinder, wsSupport); + private SearchAction underTest = new SearchAction(dbClient, userSession, new QualityGateFinder(dbClient), + new QualityGatesWsSupport(dbClient, userSession, defaultOrganizationProvider)); private WsActionTester ws = new WsActionTester(underTest); @Test @@ -93,55 +96,219 @@ public class SearchActionTest { OrganizationDto organization = db.organizations().insert(); ComponentDto project = db.components().insertPublicProject(organization); QualityGateDto qualityGate = db.qualityGates().insertQualityGate(organization); - associateProjectToQualityGate(project, qualityGate); - userSession.addPermission(ADMINISTER_QUALITY_GATES, organization); + db.qualityGates().associateProjectToQualityGate(project, qualityGate); SearchResponse response = ws.newRequest() .setParam(PARAM_GATE_ID, valueOf(qualityGate.getId())) - .setParam(PARAM_ORGANIZATION, valueOf(organization.getKey())) + .setParam(PARAM_ORGANIZATION, organization.getKey()) .executeProtobuf(SearchResponse.class); - assertThat(response).isNotNull(); + assertThat(response.getResultsList()) + .extracting(Result::getId, Result::getName) + .containsExactlyInAnyOrder(tuple(project.getId(), project.name())); assertThat(response.getMore()).isFalse(); - assertThat(response.getResultsCount()).isEqualTo(1); - assertThat(response.getResults(0).getId()).isEqualTo(project.getId()); - assertThat(response.getResults(0).getName().substring(4)).isEqualTo(project.getKey().substring(3)); } @Test public void search_on_default_organization_when_none_is_provided() { OrganizationDto defaultOrganization = db.getDefaultOrganization(); - ComponentDto project = db.components().insertPublicProject(defaultOrganization); QualityGateDto qualityGate = db.qualityGates().insertQualityGate(defaultOrganization); - associateProjectToQualityGate(project, qualityGate); - userSession.addPermission(ADMINISTER_QUALITY_GATES, defaultOrganization); + db.qualityGates().associateProjectToQualityGate(project, qualityGate); SearchResponse response = ws.newRequest() .setParam(PARAM_GATE_ID, valueOf(qualityGate.getId())) .executeProtobuf(SearchResponse.class); - assertThat(response).isNotNull(); + assertThat(response.getResultsList()) + .extracting(Result::getId, Result::getName) + .containsExactlyInAnyOrder(tuple(project.getId(), project.name())); assertThat(response.getMore()).isFalse(); - assertThat(response.getResultsCount()).isEqualTo(1); - assertThat(response.getResults(0).getId()).isEqualTo(project.getId()); - assertThat(response.getResults(0).getName().substring(4)).isEqualTo(project.getKey().substring(3)); } @Test - public void fail_when_quality_gates_does_not_belong_to_organization() { + public void return_empty_association() { OrganizationDto organization = db.organizations().insert(); - OrganizationDto otherOrganization = db.organizations().insert(); - QualityGateDto qualityGate = db.qualityGates().insertQualityGate(otherOrganization); + QualityGateDto qualityGate = db.qualityGates().insertQualityGate(organization); - expectedException.expect(NotFoundException.class); - expectedException.expectMessage(format("Quality gate '%s' does not exists.", qualityGate.getId())); + SearchResponse response = ws.newRequest() + .setParam(PARAM_GATE_ID, valueOf(qualityGate.getId())) + .setParam(PARAM_ORGANIZATION, organization.getKey()) + .executeProtobuf(SearchResponse.class); - ws.newRequest() + assertThat(response.getResultsList()).isEmpty(); + } + + @Test + public void return_all_projects() { + OrganizationDto organization = db.organizations().insert(); + QualityGateDto qualityGate = db.qualityGates().insertQualityGate(organization); + ComponentDto unassociatedProject = db.components().insertPublicProject(organization); + ComponentDto associatedProject = db.components().insertPublicProject(organization); + db.qualityGates().associateProjectToQualityGate(associatedProject, qualityGate); + + SearchResponse response = ws.newRequest() + .setParam(PARAM_GATE_ID, valueOf(qualityGate.getId())) + .setParam(PARAM_ORGANIZATION, organization.getKey()) + .setParam(PARAM_SELECTED, ALL.value()) + .executeProtobuf(SearchResponse.class); + + assertThat(response.getResultsList()) + .extracting(Result::getName, Result::getSelected) + .containsExactlyInAnyOrder( + tuple(associatedProject.name(), true), + tuple(unassociatedProject.name(), false)); + } + + @Test + public void return_only_associated_project() { + OrganizationDto organization = db.organizations().insert(); + QualityGateDto qualityGate = db.qualityGates().insertQualityGate(organization); + ComponentDto associatedProject = db.components().insertPublicProject(organization); + ComponentDto unassociatedProject = db.components().insertPublicProject(organization); + db.qualityGates().associateProjectToQualityGate(associatedProject, qualityGate); + + SearchResponse response = ws.newRequest() + .setParam(PARAM_GATE_ID, valueOf(qualityGate.getId())) + .setParam(PARAM_ORGANIZATION, organization.getKey()) + .setParam(PARAM_SELECTED, SELECTED.value()) + .executeProtobuf(SearchResponse.class); + + assertThat(response.getResultsList()) + .extracting(Result::getName, Result::getSelected) + .containsExactlyInAnyOrder(tuple(associatedProject.name(), true)) + .doesNotContain(tuple(unassociatedProject.name(), false)); + } + + @Test + public void return_only_unassociated_project() { + OrganizationDto organization = db.organizations().insert(); + QualityGateDto qualityGate = db.qualityGates().insertQualityGate(organization); + ComponentDto associatedProject = db.components().insertPublicProject(organization); + ComponentDto unassociatedProject = db.components().insertPublicProject(organization); + db.qualityGates().associateProjectToQualityGate(associatedProject, qualityGate); + + SearchResponse response = ws.newRequest() + .setParam(PARAM_GATE_ID, valueOf(qualityGate.getId())) + .setParam(PARAM_ORGANIZATION, organization.getKey()) + .setParam(PARAM_SELECTED, DESELECTED.value()) + .executeProtobuf(SearchResponse.class); + + assertThat(response.getResultsList()) + .extracting(Result::getName, Result::getSelected) + .containsExactlyInAnyOrder(tuple(unassociatedProject.name(), false)) + .doesNotContain(tuple(associatedProject.name(), true)); + } + + @Test + public void return_only_authorized_projects() { + OrganizationDto organization = db.organizations().insert(); + QualityGateDto qualityGate = db.qualityGates().insertQualityGate(organization); + ComponentDto project1 = db.components().insertPrivateProject(organization); + ComponentDto project2 = db.components().insertPrivateProject(organization); + UserDto user = db.users().insertUser(); + // User can only see project1 1 + db.users().insertProjectPermissionOnUser(user, USER, project1); + userSession.logIn(user); + + SearchResponse response = ws.newRequest() + .setParam(PARAM_GATE_ID, valueOf(qualityGate.getId())) + .setParam(PARAM_ORGANIZATION, organization.getKey()) + .setParam(PARAM_SELECTED, ALL.value()) + .executeProtobuf(SearchResponse.class); + + assertThat(response.getResultsList()) + .extracting(Result::getName) + .containsExactlyInAnyOrder(project1.name()) + .doesNotContain(project2.name()); + } + + @Test + public void root_user() { + OrganizationDto organization = db.organizations().insert(); + QualityGateDto qualityGate = db.qualityGates().insertQualityGate(organization); + ComponentDto project = db.components().insertPrivateProject(organization); + userSession.logIn().setRoot(); + + SearchResponse response = ws.newRequest() .setParam(PARAM_GATE_ID, valueOf(qualityGate.getId())) - .setParam(PARAM_ORGANIZATION, valueOf(organization.getKey())) + .setParam(PARAM_ORGANIZATION, organization.getKey()) + .setParam(PARAM_SELECTED, ALL.value()) .executeProtobuf(SearchResponse.class); + assertThat(response.getResultsList()) + .extracting(Result::getName) + .containsExactlyInAnyOrder(project.name()); + } + + @Test + public void test_paging() throws Exception { + OrganizationDto organization = db.organizations().insert(); + QualityGateDto qualityGate = db.qualityGates().insertQualityGate(organization); + ComponentDto project1 = db.components().insertPublicProject(organization, p -> p.setName("Project 1")); + ComponentDto project2 = db.components().insertPublicProject(organization, p -> p.setName("Project 2")); + ComponentDto project3 = db.components().insertPublicProject(organization, p -> p.setName("Project 3")); + db.qualityGates().associateProjectToQualityGate(project1, qualityGate); + + // Return partial result on first page + assertThat(ws.newRequest() + .setParam(PARAM_GATE_ID, valueOf(qualityGate.getId())) + .setParam(PARAM_ORGANIZATION, organization.getKey()) + .setParam(PARAM_SELECTED, ALL.value()) + .setParam(PARAM_PAGE, "1") + .setParam(PARAM_PAGE_SIZE, "1") + .executeProtobuf(SearchResponse.class) + .getResultsList()) + .extracting(Result::getName) + .containsExactlyInAnyOrder(project1.name()); + + // Return partial result on second page + assertThat(ws.newRequest() + .setParam(PARAM_GATE_ID, valueOf(qualityGate.getId())) + .setParam(PARAM_ORGANIZATION, organization.getKey()) + .setParam(PARAM_SELECTED, ALL.value()) + .setParam(PARAM_PAGE, "2") + .setParam(PARAM_PAGE_SIZE, "1") + .executeProtobuf(SearchResponse.class) + .getResultsList()) + .extracting(Result::getName) + .containsExactlyInAnyOrder(project2.name()); + + // Return partial result on first page + assertThat(ws.newRequest() + .setParam(PARAM_GATE_ID, valueOf(qualityGate.getId())) + .setParam(PARAM_ORGANIZATION, organization.getKey()) + .setParam(PARAM_SELECTED, ALL.value()) + .setParam(PARAM_PAGE, "1") + .setParam(PARAM_PAGE_SIZE, "2") + .executeProtobuf(SearchResponse.class) + .getResultsList()) + .extracting(Result::getName) + .containsExactlyInAnyOrder(project1.name(), project2.name()); + + // Return all result on first page + assertThat(ws.newRequest() + .setParam(PARAM_GATE_ID, valueOf(qualityGate.getId())) + .setParam(PARAM_ORGANIZATION, organization.getKey()) + .setParam(PARAM_SELECTED, ALL.value()) + .setParam(PARAM_PAGE, "1") + .setParam(PARAM_PAGE_SIZE, "3") + .executeProtobuf(SearchResponse.class) + .getResultsList()) + .extracting(Result::getName) + .containsExactlyInAnyOrder(project1.name(), project2.name(), project3.name()); + + // Return no result as page index is off limit + assertThat(ws.newRequest() + .setParam(PARAM_GATE_ID, valueOf(qualityGate.getId())) + .setParam(PARAM_ORGANIZATION, organization.getKey()) + .setParam(PARAM_SELECTED, ALL.value()) + .setParam(PARAM_PAGE, "3") + .setParam(PARAM_PAGE_SIZE, "3") + .executeProtobuf(SearchResponse.class) + .getResultsList()) + .extracting(Result::getName) + .isEmpty(); } @Test @@ -149,29 +316,49 @@ public class SearchActionTest { OrganizationDto organization = db.organizations().insert(); QualityGateDto qualityGate = db.qualityGates().insertQualityGate(organization); for (int i = 0; i < 20; i++) { - ComponentDto project1 = db.components().insertPublicProject(); - associateProjectToQualityGate(project1, qualityGate); + ComponentDto project = db.components().insertPublicProject(); + db.qualityGates().associateProjectToQualityGate(project, qualityGate); } userSession.addPermission(ADMINISTER_QUALITY_GATES, organization); SearchResponse response = ws.newRequest() .setParam(PARAM_GATE_ID, valueOf(qualityGate.getId())) - .setParam(PARAM_ORGANIZATION, valueOf(organization.getKey())) + .setParam(PARAM_ORGANIZATION, organization.getKey()) .setParam(PARAM_PAGE_SIZE, valueOf(10)) .setParam(PARAM_PAGE, valueOf(1)) .executeProtobuf(SearchResponse.class); - assertThat(response).isNotNull(); assertThat(response.getMore()).isTrue(); assertThat(response.getResultsCount()).isEqualTo(10); } - private void associateProjectToQualityGate(ComponentDto componentDto, QualityGateDto qualityGateDto) { - dbClient.propertiesDao().saveProperty(dbSession, new PropertyDto() - .setKey("sonar.qualitygate") - .setResourceId(componentDto.getId()) - .setValue(valueOf(qualityGateDto.getId()))); - db.commit(); + @Test + public void fail_on_unknown_quality_gate() { + OrganizationDto organization = db.organizations().insert(); + + expectedException.expect(NotFoundException.class); + expectedException.expectMessage(format("No quality gate has been found for id 42 in organization %s", organization.getName())); + + ws.newRequest() + .setParam(PARAM_GATE_ID, "42") + .setParam(PARAM_ORGANIZATION, organization.getKey()) + .executeProtobuf(SearchResponse.class); + } + + @Test + public void fail_when_quality_gates_does_not_belong_to_organization() { + OrganizationDto organization = db.organizations().insert(); + OrganizationDto otherOrganization = db.organizations().insert(); + QualityGateDto qualityGate = db.qualityGates().insertQualityGate(otherOrganization); + + expectedException.expect(NotFoundException.class); + expectedException.expectMessage(format("No quality gate has been found for id %s in organization %s", qualityGate.getId(), organization.getName())); + + ws.newRequest() + .setParam(PARAM_GATE_ID, valueOf(qualityGate.getId())) + .setParam(PARAM_ORGANIZATION, organization.getKey()) + .executeProtobuf(SearchResponse.class); } + }