From f6b9c4743a8f02f33e79c483867b3c4581c76563 Mon Sep 17 00:00:00 2001 From: Simon Brandhof Date: Wed, 15 Mar 2017 16:27:01 +0100 Subject: [PATCH] SONAR-8857 add param "organization" to api/qualityprofiles/add_project/remove_project --- .../platformlevel/PlatformLevel4.java | 2 - .../qualityprofile/QProfileFactory.java | 20 -- .../server/qualityprofile/QProfileLookup.java | 24 +- .../QProfileProjectOperations.java | 87 ------- .../qualityprofile/ws/AddProjectAction.java | 84 ++++-- .../ws/ProjectAssociationFinder.java | 62 ----- .../ws/ProjectAssociationParameters.java | 62 ----- .../qualityprofile/ws/QProfileReference.java | 26 +- .../qualityprofile/ws/QProfileWsSupport.java | 4 +- .../qualityprofile/ws/QProfilesWsModule.java | 2 - .../ws/RemoveProjectAction.java | 80 ++++-- .../qualityprofile/ws/SearchDataLoader.java | 17 +- .../ws/AddProjectActionTest.java | 245 +++++++++++++----- .../ws/QProfilesWsMediumTest.java | 143 ---------- .../ws/QProfilesWsModuleTest.java | 2 +- .../qualityprofile/ws/QProfilesWsTest.java | 19 -- .../ws/RemoveProjectActionTest.java | 194 ++++++++++++++ .../qualityprofile/ws/SearchActionTest.java | 5 +- .../ws/SearchDataLoaderTest.java | 30 +-- 19 files changed, 527 insertions(+), 581 deletions(-) delete mode 100644 server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileProjectOperations.java delete mode 100644 server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ProjectAssociationFinder.java delete mode 100644 server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ProjectAssociationParameters.java create mode 100644 server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/RemoveProjectActionTest.java diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java index c6c29b3cf55..4eee2881c4e 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java @@ -147,7 +147,6 @@ import org.sonar.server.qualityprofile.QProfileExporters; import org.sonar.server.qualityprofile.QProfileFactory; import org.sonar.server.qualityprofile.QProfileLoader; import org.sonar.server.qualityprofile.QProfileLookup; -import org.sonar.server.qualityprofile.QProfileProjectOperations; import org.sonar.server.qualityprofile.QProfileResetImpl; import org.sonar.server.qualityprofile.QProfileService; import org.sonar.server.qualityprofile.RuleActivator; @@ -263,7 +262,6 @@ public class PlatformLevel4 extends PlatformLevel { XMLProfileSerializer.class, AnnotationProfileParser.class, QProfileLookup.class, - QProfileProjectOperations.class, QProfileComparison.class, SearchDataLoader.class, ProfilesWs.class, diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileFactory.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileFactory.java index 07c506873db..08db76df84b 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileFactory.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileFactory.java @@ -21,12 +21,9 @@ package org.sonar.server.qualityprofile; import com.google.common.collect.Lists; import java.util.ArrayList; -import java.util.Collection; import java.util.Date; import java.util.List; import java.util.Objects; -import java.util.Set; -import javax.annotation.CheckForNull; import javax.annotation.Nullable; import org.apache.commons.lang.StringUtils; import org.sonar.api.utils.System2; @@ -147,10 +144,6 @@ public class QProfileFactory { // ------------- DEFAULT PROFILE - public List getDefaults(DbSession session, OrganizationDto organization, Collection languageKeys) { - return db.qualityProfileDao().selectDefaultProfiles(session, organization, languageKeys); - } - /** * @deprecated replaced by {@link org.sonar.server.qualityprofile.ws.QProfileWsSupport#getProfile(DbSession, QProfileReference)} */ @@ -174,19 +167,6 @@ public class QProfileFactory { return checkFound(profile, "Unable to find a profile for language '%s' with name '%s'", language, profileName); } - @CheckForNull - public QualityProfileDto getByProjectAndLanguage(DbSession session, String projectKey, String language) { - return db.qualityProfileDao().selectByProjectAndLanguage(session, projectKey, language); - } - - public List getByProjectAndLanguages(DbSession session, OrganizationDto organization, String projectKey, Set languageKeys) { - return db.qualityProfileDao().selectByProjectAndLanguages(session, organization, projectKey, languageKeys); - } - - public List getByNameAndLanguages(DbSession session, OrganizationDto organization, String name, Collection languages) { - return db.qualityProfileDao().selectByNameAndLanguages(organization, name, languages, session); - } - private static void checkNotDefault(QualityProfileDto p) { if (p.isDefault()) { throw BadRequestException.create("The profile marked as default can not be deleted: " + p.getKey()); diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileLookup.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileLookup.java index 2ba025e55da..2a10697aa5b 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileLookup.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileLookup.java @@ -19,19 +19,16 @@ */ package org.sonar.server.qualityprofile; -import static com.google.common.collect.Lists.newArrayList; -import static org.sonar.core.util.stream.Collectors.toList; - import java.util.List; - -import javax.annotation.CheckForNull; - import org.sonar.api.server.ServerSide; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.organization.OrganizationDto; import org.sonar.db.qualityprofile.QualityProfileDto; +import static com.google.common.collect.Lists.newArrayList; +import static org.sonar.core.util.stream.Collectors.toList; + @ServerSide public class QProfileLookup { @@ -49,17 +46,6 @@ public class QProfileLookup { return toQProfiles(db.qualityProfileDao().selectByLanguage(dbSession, language), organization); } - @CheckForNull - public QProfile profile(String name, String language) { - try (DbSession dbSession = db.openSession(false)) { - QualityProfileDto dto = findQualityProfile(name, language, dbSession); - if (dto != null) { - return QProfile.from(dto, null); - } - return null; - } - } - public List ancestors(QualityProfileDto profile, DbSession session) { List ancestors = newArrayList(); incrementAncestors(QProfile.from(profile, null), ancestors, session); @@ -82,8 +68,4 @@ public class QProfileLookup { return dtos.stream().map(dto -> QProfile.from(dto, organization)).collect(toList(dtos.size())); } - @CheckForNull - private QualityProfileDto findQualityProfile(String name, String language, DbSession session) { - return db.qualityProfileDao().selectByNameAndLanguage(name, language, session); - } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileProjectOperations.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileProjectOperations.java deleted file mode 100644 index f9c9503e944..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileProjectOperations.java +++ /dev/null @@ -1,87 +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.qualityprofile; - -import org.sonar.api.server.ServerSide; -import org.sonar.api.web.UserRole; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.qualityprofile.QualityProfileDto; -import org.sonar.server.exceptions.ForbiddenException; -import org.sonar.db.permission.OrganizationPermission; -import org.sonar.server.user.UserSession; -import org.sonar.server.ws.WsUtils; - -/** - * Should be refactored in order to use project key. Maybe should it be move to {@link QProfileFactory} - * Permission checks should also be done in the upper service. - */ -@ServerSide -public class QProfileProjectOperations { - - private final DbClient db; - private final UserSession userSession; - - public QProfileProjectOperations(DbClient db, UserSession userSession) { - this.db = db; - this.userSession = userSession; - } - - public void addProject(DbSession dbSession, String profileKey, ComponentDto project) { - checkAdminOnProject(project); - QualityProfileDto qualityProfile = selectProfileByKey(dbSession, profileKey); - - QualityProfileDto currentProfile = db.qualityProfileDao().selectByProjectAndLanguage(dbSession, project.key(), qualityProfile.getLanguage()); - - boolean updated = false; - if (currentProfile == null) { - db.qualityProfileDao().insertProjectProfileAssociation(project.uuid(), qualityProfile.getKey(), dbSession); - updated = true; - } else if (!profileKey.equals(currentProfile.getKey())) { - db.qualityProfileDao().updateProjectProfileAssociation(project.uuid(), profileKey, currentProfile.getKey(), dbSession); - updated = true; - } - if (updated) { - dbSession.commit(); - } - } - - public void removeProject(DbSession dbSession, String profileKey, ComponentDto project) { - checkAdminOnProject(project); - QualityProfileDto qualityProfile = selectProfileByKey(dbSession, profileKey); - - db.qualityProfileDao().deleteProjectProfileAssociation(project.uuid(), qualityProfile.getKey(), dbSession); - dbSession.commit(); - } - - private QualityProfileDto selectProfileByKey(DbSession session, String profileKey) { - QualityProfileDto qualityProfile = db.qualityProfileDao().selectByKey(session, profileKey); - return WsUtils.checkFound(qualityProfile, "Quality profile does not exist"); - } - - private void checkAdminOnProject(ComponentDto project) { - if (!userSession.hasPermission(OrganizationPermission.ADMINISTER_QUALITY_PROFILES, project.getOrganizationUuid()) && - !userSession.hasComponentPermission(UserRole.ADMIN, project)) { - throw new ForbiddenException("Insufficient privileges"); - } - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/AddProjectAction.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/AddProjectAction.java index 6242c7ab145..abc09dd769c 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/AddProjectAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/AddProjectAction.java @@ -19,36 +19,40 @@ */ package org.sonar.server.qualityprofile.ws; +import org.sonar.api.resources.Languages; 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.server.ws.WebService.NewAction; +import org.sonar.api.web.UserRole; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.component.ComponentDto; -import org.sonar.server.qualityprofile.QProfileProjectOperations; -import org.sonarqube.ws.client.qualityprofile.AddProjectRequest; +import org.sonar.db.permission.OrganizationPermission; +import org.sonar.db.qualityprofile.QualityProfileDto; +import org.sonar.server.component.ComponentFinder; +import org.sonar.server.exceptions.ForbiddenException; +import org.sonar.server.user.UserSession; +import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001; import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.ACTION_ADD_PROJECT; -import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_LANGUAGE; -import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PROFILE_KEY; -import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PROFILE_NAME; import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PROJECT_KEY; import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PROJECT_UUID; public class AddProjectAction implements QProfileWsAction { - private final ProjectAssociationParameters projectAssociationParameters; - private final ProjectAssociationFinder projectAssociationFinder; - private final QProfileProjectOperations profileProjectOperations; private final DbClient dbClient; + private final UserSession userSession; + private final Languages languages; + private final ComponentFinder componentFinder; + private final QProfileWsSupport wsSupport; - public AddProjectAction(ProjectAssociationParameters projectAssociationParameters, QProfileProjectOperations profileProjectOperations, - ProjectAssociationFinder projectAssociationFinder, DbClient dbClient) { - this.projectAssociationParameters = projectAssociationParameters; - this.profileProjectOperations = profileProjectOperations; - this.projectAssociationFinder = projectAssociationFinder; + public AddProjectAction(DbClient dbClient, UserSession userSession, Languages languages, ComponentFinder componentFinder, QProfileWsSupport wsSupport) { this.dbClient = dbClient; + this.userSession = userSession; + this.languages = languages; + this.componentFinder = componentFinder; + this.wsSupport = wsSupport; } @Override @@ -56,31 +60,59 @@ public class AddProjectAction implements QProfileWsAction { NewAction action = controller.createAction(ACTION_ADD_PROJECT) .setSince("5.2") .setDescription("Associate a project with a quality profile.") + .setPost(true) .setHandler(this); - projectAssociationParameters.addParameters(action); + + QProfileReference.defineParams(action, languages); + QProfileWsSupport.createOrganizationParam(action).setSince("6.4"); + + action.createParam(PARAM_PROJECT_UUID) + .setDescription("A project UUID. Either this parameter, or projectKey must be set.") + .setExampleValue("69e57151-be0d-4157-adff-c06741d88879"); + action.createParam(PARAM_PROJECT_KEY) + .setDescription("A project key. Either this parameter, or projectUuid must be set.") + .setExampleValue(KEY_PROJECT_EXAMPLE_001); } @Override public void handle(Request request, Response response) throws Exception { - AddProjectRequest addProjectRequest = toWsRequest(request); + // fail fast if not logged in + userSession.checkLoggedIn(); try (DbSession dbSession = dbClient.openSession(false)) { - String profileKey = projectAssociationFinder.getProfileKey(addProjectRequest.getLanguage(), addProjectRequest.getProfileName(), addProjectRequest.getProfileKey()); - ComponentDto project = projectAssociationFinder.getProject(dbSession, addProjectRequest.getProjectKey(), addProjectRequest.getProjectUuid()); - profileProjectOperations.addProject(dbSession, profileKey, project); + ComponentDto project = loadProject(dbSession, request); + QualityProfileDto profile = wsSupport.getProfile(dbSession, QProfileReference.from(request)); + + if (!profile.getOrganizationUuid().equals(project.getOrganizationUuid())) { + throw new IllegalArgumentException("Project and Quality profile must have same organization"); + } + + QualityProfileDto currentProfile = dbClient.qualityProfileDao().selectByProjectAndLanguage(dbSession, project.key(), profile.getLanguage()); + if (currentProfile == null) { + // project uses the default profile + dbClient.qualityProfileDao().insertProjectProfileAssociation(project.uuid(), profile.getKey(), dbSession); + dbSession.commit(); + } else if (!profile.getKey().equals(currentProfile.getKey())) { + dbClient.qualityProfileDao().updateProjectProfileAssociation(project.uuid(), profile.getKey(), currentProfile.getKey(), dbSession); + dbSession.commit(); + } } response.noContent(); } - private static AddProjectRequest toWsRequest(Request request) { - return AddProjectRequest.builder() - .setLanguage(request.param(PARAM_LANGUAGE)) - .setProfileName(request.param(PARAM_PROFILE_NAME)) - .setProfileKey(request.param(PARAM_PROFILE_KEY)) - .setProjectKey(request.param(PARAM_PROJECT_KEY)) - .setProjectUuid(request.param(PARAM_PROJECT_UUID)) - .build(); + private ComponentDto loadProject(DbSession dbSession, Request request) { + String projectKey = request.param(PARAM_PROJECT_KEY); + String projectUuid = request.param(PARAM_PROJECT_UUID); + ComponentDto project = componentFinder.getByUuidOrKey(dbSession, projectUuid, projectKey, ComponentFinder.ParamNames.PROJECT_UUID_AND_KEY); + checkAdministrator(project); + return project; } + private void checkAdministrator(ComponentDto project) { + if (!userSession.hasPermission(OrganizationPermission.ADMINISTER_QUALITY_PROFILES, project.getOrganizationUuid()) && + !userSession.hasComponentPermission(UserRole.ADMIN, project)) { + throw new ForbiddenException("Insufficient privileges"); + } + } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ProjectAssociationFinder.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ProjectAssociationFinder.java deleted file mode 100644 index 973be899d2e..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ProjectAssociationFinder.java +++ /dev/null @@ -1,62 +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.qualityprofile.ws; - -import javax.annotation.Nullable; -import org.sonar.db.DbSession; -import org.sonar.db.component.ComponentDto; -import org.sonar.server.component.ComponentFinder; -import org.sonar.server.exceptions.NotFoundException; -import org.sonar.server.qualityprofile.QProfile; -import org.sonar.server.qualityprofile.QProfileLookup; - -import static com.google.common.base.Preconditions.checkArgument; -import static org.apache.commons.lang.StringUtils.isEmpty; - -public class ProjectAssociationFinder { - - private static final String BAD_PROFILE_PARAMETERS_ERROR = "Either profileKey or profileName + language must be set"; - - private final QProfileLookup profileLookup; - private final ComponentFinder componentFinder; - - public ProjectAssociationFinder(QProfileLookup profileLookup, ComponentFinder componentFinder) { - this.profileLookup = profileLookup; - this.componentFinder = componentFinder; - } - - public String getProfileKey(@Nullable String language, @Nullable String profileName, @Nullable String profileKey) { - checkArgument((!isEmpty(language) && !isEmpty(profileName)) ^ !isEmpty(profileKey), BAD_PROFILE_PARAMETERS_ERROR); - return profileKey == null ? getProfileKeyFromLanguageAndName(language, profileName) : profileKey; - } - - public ComponentDto getProject(DbSession dbSession, @Nullable String projectKey, @Nullable String projectUuid) { - return componentFinder.getByUuidOrKey(dbSession, projectUuid, projectKey, ComponentFinder.ParamNames.PROJECT_UUID_AND_KEY); - } - - private String getProfileKeyFromLanguageAndName(String language, String profileName) { - QProfile profile = profileLookup.profile(profileName, language); - if (profile == null) { - throw new NotFoundException(String.format("Unable to find a profile for language '%s' with name '%s'", language, profileName)); - } - return profile.key(); - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ProjectAssociationParameters.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ProjectAssociationParameters.java deleted file mode 100644 index 23d8552ac2e..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ProjectAssociationParameters.java +++ /dev/null @@ -1,62 +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.qualityprofile.ws; - -import org.sonar.api.resources.Languages; -import org.sonar.api.server.ws.WebService; -import org.sonar.core.util.Uuids; -import org.sonar.server.util.LanguageParamUtils; - -import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001; -import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_LANGUAGE; -import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PROFILE_KEY; -import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PROFILE_NAME; -import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PROJECT_KEY; -import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PROJECT_UUID; - -public class ProjectAssociationParameters { - - private final Languages languages; - - public ProjectAssociationParameters(Languages languages) { - this.languages = languages; - } - - void addParameters(WebService.NewAction action) { - action.setPost(true); - action.createParam(PARAM_PROJECT_UUID) - .setDescription("A project UUID. Either this parameter, or projectKey must be set.") - .setExampleValue("69e57151-be0d-4157-adff-c06741d88879"); - action.createParam(PARAM_PROJECT_KEY) - .setDescription("A project key. Either this parameter, or projectUuid must be set.") - .setExampleValue(KEY_PROJECT_EXAMPLE_001); - action.createParam(PARAM_PROFILE_KEY) - .setDescription("A quality profile key. Either this parameter, or a combination of profileName + language must be set.") - .setExampleValue(Uuids.UUID_EXAMPLE_01); - action.createParam(PARAM_PROFILE_NAME) - .setDescription("A quality profile name. If this parameter is set, profileKey must not be set and language must be set to disambiguate.") - .setExampleValue("Soanr way"); - action.createParam(PARAM_LANGUAGE) - .setDescription("A quality profile language. If this parameter is set, profileKey must not be set and profileName must be set to disambiguate.") - .setPossibleValues(LanguageParamUtils.getLanguageKeys(languages)) - .setExampleValue("js"); - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfileReference.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfileReference.java index c492fb73321..028f3caefab 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfileReference.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfileReference.java @@ -19,19 +19,24 @@ */ package org.sonar.server.qualityprofile.ws; +import java.util.Arrays; import java.util.Optional; import javax.annotation.Nullable; +import org.sonar.api.resources.Language; import org.sonar.api.resources.Languages; import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.WebService; import org.sonar.core.util.Uuids; -import org.sonar.server.util.LanguageParamUtils; +import org.sonar.core.util.stream.Collectors; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkState; import static java.util.Objects.requireNonNull; import static org.apache.commons.lang.StringUtils.isEmpty; import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_ORGANIZATION; +import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_LANGUAGE; +import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PROFILE_KEY; +import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PROFILE_NAME; /** * Reference to a Quality profile as defined by requests to web services api/qualityprofiles. @@ -43,10 +48,6 @@ import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_ORG */ public class QProfileReference { - public static final String DEFAULT_PARAM_PROFILE_KEY = "profileKey"; - public static final String DEFAULT_PARAM_LANGUAGE = "language"; - public static final String DEFAULT_PARAM_PROFILE_NAME = "profileName"; - private enum Type { KEY, NAME } @@ -149,10 +150,10 @@ public class QProfileReference { } public static QProfileReference from(Request request) { - String key = request.param(DEFAULT_PARAM_PROFILE_KEY); + String key = request.param(PARAM_PROFILE_KEY); String organizationKey = request.param(PARAM_ORGANIZATION); - String lang = request.param(DEFAULT_PARAM_LANGUAGE); - String name = request.param(DEFAULT_PARAM_PROFILE_NAME); + String lang = request.param(PARAM_LANGUAGE); + String name = request.param(PARAM_PROFILE_NAME); return from(key, organizationKey, lang, name); } @@ -174,15 +175,14 @@ public class QProfileReference { } public static void defineParams(WebService.NewAction action, Languages languages) { - action.createParam(DEFAULT_PARAM_PROFILE_KEY) + action.createParam(PARAM_PROFILE_KEY) .setDescription("A quality profile key. Either this parameter, or a combination of profileName + language must be set.") .setExampleValue(Uuids.UUID_EXAMPLE_01); - action.createParam(DEFAULT_PARAM_PROFILE_NAME) + action.createParam(PARAM_PROFILE_NAME) .setDescription("A quality profile name. If this parameter is set, profileKey must not be set and language must be set to disambiguate.") .setExampleValue("Sonar way"); - action.createParam(DEFAULT_PARAM_LANGUAGE) + action.createParam(PARAM_LANGUAGE) .setDescription("A quality profile language. If this parameter is set, profileKey must not be set and profileName must be set to disambiguate.") - .setPossibleValues(LanguageParamUtils.getLanguageKeys(languages)) - .setExampleValue("js"); + .setPossibleValues(Arrays.stream(languages.all()).map(Language::getKey).collect(Collectors.toSet())); } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfileWsSupport.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfileWsSupport.java index 284c0163971..27b728ea959 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfileWsSupport.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfileWsSupport.java @@ -82,8 +82,8 @@ public class QProfileWsSupport { .checkPermission(ADMINISTER_QUALITY_PROFILES, defaultOrganizationProvider.get().getUuid()); } - public static NewParam createOrganizationParam(NewAction create) { - return create + public static NewParam createOrganizationParam(NewAction action) { + return action .createParam(PARAM_ORGANIZATION) .setDescription("Organization key") .setRequired(false) diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfilesWsModule.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfilesWsModule.java index 2acbcfff247..50eaa911c26 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfilesWsModule.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfilesWsModule.java @@ -41,8 +41,6 @@ public class QProfilesWsModule extends Module { ImportersAction.class, InheritanceAction.class, QProfilesWs.class, - ProjectAssociationFinder.class, - ProjectAssociationParameters.class, ProjectsAction.class, RenameAction.class, RemoveProjectAction.class, diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/RemoveProjectAction.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/RemoveProjectAction.java index d0a9388a221..22ae3244565 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/RemoveProjectAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/RemoveProjectAction.java @@ -19,36 +19,40 @@ */ package org.sonar.server.qualityprofile.ws; +import org.sonar.api.resources.Languages; 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.server.ws.WebService.NewAction; +import org.sonar.api.web.UserRole; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.component.ComponentDto; -import org.sonar.server.qualityprofile.QProfileProjectOperations; -import org.sonarqube.ws.client.qualityprofile.RemoveProjectRequest; +import org.sonar.db.permission.OrganizationPermission; +import org.sonar.db.qualityprofile.QualityProfileDto; +import org.sonar.server.component.ComponentFinder; +import org.sonar.server.exceptions.ForbiddenException; +import org.sonar.server.user.UserSession; +import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001; import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.ACTION_REMOVE_PROJECT; -import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_LANGUAGE; -import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PROFILE_KEY; -import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PROFILE_NAME; import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PROJECT_KEY; import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PROJECT_UUID; public class RemoveProjectAction implements QProfileWsAction { - private final ProjectAssociationParameters projectAssociationParameters; - private final ProjectAssociationFinder projectAssociationFinder; - private final QProfileProjectOperations profileProjectOperations; private final DbClient dbClient; + private final UserSession userSession; + private final Languages languages; + private final ComponentFinder componentFinder; + private final QProfileWsSupport wsSupport; - public RemoveProjectAction(ProjectAssociationParameters projectAssociationParameters, ProjectAssociationFinder projectAssociationFinder, - QProfileProjectOperations profileProjectOperations, DbClient dbClient) { - this.projectAssociationParameters = projectAssociationParameters; - this.projectAssociationFinder = projectAssociationFinder; - this.profileProjectOperations = profileProjectOperations; + public RemoveProjectAction(DbClient dbClient, UserSession userSession, Languages languages, ComponentFinder componentFinder, QProfileWsSupport wsSupport) { this.dbClient = dbClient; + this.userSession = userSession; + this.languages = languages; + this.componentFinder = componentFinder; + this.wsSupport = wsSupport; } @Override @@ -56,29 +60,51 @@ public class RemoveProjectAction implements QProfileWsAction { NewAction action = controller.createAction(ACTION_REMOVE_PROJECT) .setSince("5.2") .setDescription("Remove a project's association with a quality profile.") + .setPost(true) .setHandler(this); - projectAssociationParameters.addParameters(action); + QProfileReference.defineParams(action, languages); + QProfileWsSupport.createOrganizationParam(action).setSince("6.4"); + + action.createParam(PARAM_PROJECT_UUID) + .setDescription("A project UUID. Either this parameter, or projectKey must be set.") + .setExampleValue("69e57151-be0d-4157-adff-c06741d88879"); + action.createParam(PARAM_PROJECT_KEY) + .setDescription("A project key. Either this parameter, or projectUuid must be set.") + .setExampleValue(KEY_PROJECT_EXAMPLE_001); } @Override public void handle(Request request, Response response) throws Exception { - RemoveProjectRequest removeProjectRequest = toWsRequest(request); + // fail fast if not logged in + userSession.checkLoggedIn(); + try (DbSession dbSession = dbClient.openSession(false)) { - String profileKey = projectAssociationFinder.getProfileKey(removeProjectRequest.getLanguage(), removeProjectRequest.getProfileName(), removeProjectRequest.getProfileKey()); - ComponentDto project = projectAssociationFinder.getProject(dbSession, removeProjectRequest.getProjectKey(), removeProjectRequest.getProjectUuid()); - profileProjectOperations.removeProject(dbSession, profileKey, project); + ComponentDto project = loadProject(dbSession, request); + QualityProfileDto profile = wsSupport.getProfile(dbSession, QProfileReference.from(request)); + + if (!profile.getOrganizationUuid().equals(project.getOrganizationUuid())) { + throw new IllegalArgumentException("Project and Quality profile must have same organization"); + } + + dbClient.qualityProfileDao().deleteProjectProfileAssociation(project.uuid(), profile.getKey(), dbSession); + dbSession.commit(); + + response.noContent(); } - response.noContent(); } - private static RemoveProjectRequest toWsRequest(Request request) { - return RemoveProjectRequest.builder() - .setLanguage(request.param(PARAM_LANGUAGE)) - .setProfileName(request.param(PARAM_PROFILE_NAME)) - .setProfileKey(request.param(PARAM_PROFILE_KEY)) - .setProjectKey(request.param(PARAM_PROJECT_KEY)) - .setProjectUuid(request.param(PARAM_PROJECT_UUID)) - .build(); + private ComponentDto loadProject(DbSession dbSession, Request request) { + String projectKey = request.param(PARAM_PROJECT_KEY); + String projectUuid = request.param(PARAM_PROJECT_UUID); + ComponentDto project = componentFinder.getByUuidOrKey(dbSession, projectUuid, projectKey, ComponentFinder.ParamNames.PROJECT_UUID_AND_KEY); + checkAdministrator(project); + return project; } + private void checkAdministrator(ComponentDto project) { + if (!userSession.hasPermission(OrganizationPermission.ADMINISTER_QUALITY_PROFILES, project.getOrganizationUuid()) && + !userSession.hasComponentPermission(UserRole.ADMIN, project)) { + throw new ForbiddenException("Insufficient privileges"); + } + } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/SearchDataLoader.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/SearchDataLoader.java index fdc42b1b6d0..d5909fd7f22 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/SearchDataLoader.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/SearchDataLoader.java @@ -38,7 +38,6 @@ import org.sonar.db.component.ComponentDto; import org.sonar.db.organization.OrganizationDto; import org.sonar.server.component.ComponentFinder; import org.sonar.server.qualityprofile.QProfile; -import org.sonar.server.qualityprofile.QProfileFactory; import org.sonar.server.qualityprofile.QProfileLookup; import org.sonarqube.ws.client.qualityprofile.SearchWsRequest; @@ -47,21 +46,19 @@ import static java.lang.String.format; public class SearchDataLoader { private static final Comparator Q_PROFILE_COMPARATOR = Comparator - .comparing(QProfile::language) - .thenComparing(QProfile::name); + .comparing(QProfile::language) + .thenComparing(QProfile::name); private final Languages languages; private final QProfileLookup profileLookup; - private final QProfileFactory profileFactory; private final DbClient dbClient; private final ComponentFinder componentFinder; private final QProfileWsSupport qProfileWsSupport; - public SearchDataLoader(Languages languages, QProfileLookup profileLookup, QProfileFactory profileFactory, DbClient dbClient, + public SearchDataLoader(Languages languages, QProfileLookup profileLookup, DbClient dbClient, ComponentFinder componentFinder, QProfileWsSupport qProfileWsSupport) { this.languages = languages; this.profileLookup = profileLookup; - this.profileFactory = profileFactory; this.dbClient = dbClient; this.componentFinder = componentFinder; this.qProfileWsSupport = qProfileWsSupport; @@ -134,7 +131,7 @@ public class SearchDataLoader { return languageKeys; } - profileFactory.getByNameAndLanguages(dbSession, organization, profileName, languageKeys) + dbClient.qualityProfileDao().selectByNameAndLanguages(organization, profileName, languageKeys, dbSession) .forEach(qualityProfile -> qualityProfiles .put(qualityProfile.getLanguage(), QProfile.from(qualityProfile, organization))); return difference(languageKeys, qualityProfiles.keySet()); @@ -147,8 +144,8 @@ public class SearchDataLoader { } ComponentDto project = getProject(moduleKey, dbSession); - profileFactory.getByProjectAndLanguages(dbSession, organization, project.getKey(), languageKeys) - .forEach(qualityProfile -> qualityProfiles.put(qualityProfile.getLanguage(), QProfile.from(qualityProfile, organization))); + dbClient.qualityProfileDao().selectByProjectAndLanguages(dbSession, organization, project.getKey(), languageKeys) + .forEach(qualityProfile -> qualityProfiles.put(qualityProfile.getLanguage(), QProfile.from(qualityProfile, organization))); return difference(languageKeys, qualityProfiles.keySet()); } @@ -182,7 +179,7 @@ public class SearchDataLoader { } private List findDefaultProfiles(final DbSession dbSession, OrganizationDto organization, Set languageKeys) { - return profileFactory.getDefaults(dbSession, organization, languageKeys).stream() + return dbClient.qualityProfileDao().selectDefaultProfiles(dbSession, organization, languageKeys).stream() .map(result -> QProfile.from(result, organization)) .collect(Collectors.toList()); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/AddProjectActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/AddProjectActionTest.java index c086786afef..7c3656561db 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/AddProjectActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/AddProjectActionTest.java @@ -19,116 +19,245 @@ */ package org.sonar.server.qualityprofile.ws; -import org.junit.Before; +import java.net.HttpURLConnection; import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; import org.sonar.api.resources.Languages; -import org.sonar.api.utils.System2; +import org.sonar.api.server.ws.WebService; +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.ComponentDto; -import org.sonar.db.component.ComponentTesting; -import org.sonar.db.qualityprofile.QualityProfileDbTester; +import org.sonar.db.organization.OrganizationDto; import org.sonar.db.qualityprofile.QualityProfileDto; import org.sonar.server.component.ComponentFinder; +import org.sonar.server.exceptions.ForbiddenException; +import org.sonar.server.exceptions.NotFoundException; +import org.sonar.server.exceptions.UnauthorizedException; import org.sonar.server.language.LanguageTesting; -import org.sonar.server.qualityprofile.QProfileLookup; -import org.sonar.server.qualityprofile.QProfileName; -import org.sonar.server.qualityprofile.QProfileProjectOperations; +import org.sonar.server.organization.TestDefaultOrganizationProvider; import org.sonar.server.tester.UserSessionRule; import org.sonar.server.ws.TestRequest; +import org.sonar.server.ws.TestResponse; import org.sonar.server.ws.WsActionTester; import static org.assertj.core.api.Assertions.assertThat; import static org.sonar.db.permission.OrganizationPermission.ADMINISTER_QUALITY_PROFILES; -import static org.sonar.server.qualityprofile.QProfileTesting.newQProfileDto; public class AddProjectActionTest { private static final String LANGUAGE_1 = "xoo"; private static final String LANGUAGE_2 = "foo"; - private System2 system2 = System2.INSTANCE; - @Rule - public DbTester dbTester = DbTester.create(system2); - + public DbTester db = DbTester.create(); + @Rule + public ExpectedException expectedException = ExpectedException.none(); @Rule public UserSessionRule userSession = UserSessionRule.standalone(); - private DbClient dbClient = dbTester.getDbClient(); - private DbSession session = dbTester.getSession(); - private QualityProfileDbTester qualityProfileDbTester = new QualityProfileDbTester(dbTester); - private QProfileProjectOperations qProfileProjectOperations = new QProfileProjectOperations(dbClient, userSession); + private DbClient dbClient = db.getDbClient(); private Languages languages = LanguageTesting.newLanguages(LANGUAGE_1, LANGUAGE_2); - private ProjectAssociationParameters projectAssociationParameters = new ProjectAssociationParameters(languages); + private QProfileWsSupport wsSupport = new QProfileWsSupport(dbClient, userSession, TestDefaultOrganizationProvider.from(db)); + private AddProjectAction underTest = new AddProjectAction(dbClient, userSession, languages, new ComponentFinder(dbClient), wsSupport); + private WsActionTester tester = new WsActionTester(underTest); + + @Test + public void test_definition() { + WebService.Action definition = tester.getDef(); + assertThat(definition.since()).isEqualTo("5.2"); + assertThat(definition.isPost()).isTrue(); + + // parameters + assertThat(definition.params()).extracting(WebService.Param::key).containsOnly("profileKey", "profileName", "projectKey", "language", "projectUuid", "organization"); + WebService.Param languageParam = definition.param("language"); + assertThat(languageParam.possibleValues()).containsOnly(LANGUAGE_1, LANGUAGE_2); + assertThat(languageParam.exampleValue()).isNull(); + WebService.Param organizationParam = definition.param("organization"); + assertThat(organizationParam.since()).isEqualTo("6.4"); + assertThat(organizationParam.isInternal()).isTrue(); + } - private ComponentDto project; + @Test + public void add_project_on_profile_of_default_organization() { + logInAsProfileAdmin(db.getDefaultOrganization()); + ComponentDto project = db.components().insertProject(db.getDefaultOrganization()); + QualityProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization()); + + TestResponse response = call(project, profile); + assertThat(response.getStatus()).isEqualTo(HttpURLConnection.HTTP_NO_CONTENT); + + assertProjectIsAssociatedToProfile(project, profile); + } + + @Test + public void add_project_on_profile_of_specified_organization() { + OrganizationDto org1 = db.organizations().insert(); + logInAsProfileAdmin(org1); + ComponentDto project = db.components().insertProject(org1); + QualityProfileDto profile = db.qualityProfiles().insert(org1, p -> p.setLanguage(LANGUAGE_1)); - private WsActionTester ws = new WsActionTester(new AddProjectAction(projectAssociationParameters, - qProfileProjectOperations, new ProjectAssociationFinder(new QProfileLookup(dbClient), - new ComponentFinder(dbClient)),dbClient)); + TestResponse response = call(org1, project, profile); + assertThat(response.getStatus()).isEqualTo(HttpURLConnection.HTTP_NO_CONTENT); - @Before - public void setUp() throws Exception { - project = dbTester.components().insertComponent(ComponentTesting.newProjectDto(dbTester.organizations().insert())); + assertProjectIsAssociatedToProfile(project, profile); } @Test - public void add_project() throws Exception { - setUserAsQualityProfileAdmin(); - QualityProfileDto profile = qualityProfileDbTester.insertQualityProfile(newQProfileDto("org-123", QProfileName.createFor(LANGUAGE_1, "profile1"), "Profile")); - session.commit(); + public void throw_IAE_if_profile_and_project_are_in_different_organizations() { + OrganizationDto org1 = db.organizations().insert(); + OrganizationDto org2 = db.organizations().insert(); + logInAsProfileAdmin(org1); + ComponentDto project = db.components().insertProject(org1); + QualityProfileDto profileInOrg2 = db.qualityProfiles().insert(org2, p -> p.setLanguage(LANGUAGE_1)); - executeRequest(project, profile); + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("Project and Quality profile must have same organization"); - assertProjectIsAssociatedToProfile(project.key(), LANGUAGE_1, profile.getKey()); + call(org2, project, profileInOrg2); + + assertProjectIsNotAssociatedToProfile(project, profileInOrg2); } @Test - public void change_project_association() throws Exception { - setUserAsQualityProfileAdmin(); - QualityProfileDto profile1 = newQProfileDto("org-123", QProfileName.createFor(LANGUAGE_1, "profile1"), "Profile 1"); - QualityProfileDto profile2 = newQProfileDto("org-123", QProfileName.createFor(LANGUAGE_1, "profile2"), "Profile 2"); - qualityProfileDbTester.insertQualityProfiles(profile1, profile2); - qualityProfileDbTester.associateProjectWithQualityProfile(project, profile1); - session.commit(); + public void throw_NotFoundException_if_profile_is_not_found_in_specified_organization() { + OrganizationDto org1 = db.organizations().insert(); + OrganizationDto org2 = db.organizations().insert(); + logInAsProfileAdmin(org1); + ComponentDto project = db.components().insertProject(org1); + QualityProfileDto profileInOrg2 = db.qualityProfiles().insert(org2, p -> p.setLanguage(LANGUAGE_1)); + + expectedException.expect(NotFoundException.class); + expectedException + .expectMessage("Quality Profile for language '" + LANGUAGE_1 + "' and name '" + profileInOrg2.getName() + "' does not exist in organization '" + org1.getKey() + "'"); - executeRequest(project, profile2); + call(org1, project, profileInOrg2); - assertProjectIsAssociatedToProfile(project.key(), LANGUAGE_1, profile2.getKey()); + assertProjectIsNotAssociatedToProfile(project, profileInOrg2); } @Test - public void change_project_association_when_project_is_linked_on_many_profiles() throws Exception { - setUserAsQualityProfileAdmin(); - QualityProfileDto profile1Language1 = newQProfileDto("org-123", QProfileName.createFor(LANGUAGE_1, "profile1"), "Profile 1"); - QualityProfileDto profile2Language2 = newQProfileDto("org-123", QProfileName.createFor(LANGUAGE_2, "profile2"), "Profile 2"); - QualityProfileDto profile3Language1 = newQProfileDto("org-123", QProfileName.createFor(LANGUAGE_1, "profile3"), "Profile 3"); - qualityProfileDbTester.insertQualityProfiles(profile1Language1, profile2Language2, profile3Language1); - qualityProfileDbTester.associateProjectWithQualityProfile(project, profile1Language1, profile2Language2); - session.commit(); + public void change_association_in_default_organization() throws Exception { + logInAsProfileAdmin(db.getDefaultOrganization()); - executeRequest(project, profile3Language1); + ComponentDto project = db.components().insertProject(db.getDefaultOrganization()); + // two profiles on same language + QualityProfileDto profile1 = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(LANGUAGE_1)); + QualityProfileDto profile2 = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(LANGUAGE_1)); + db.qualityProfiles().associateProjectWithQualityProfile(project, profile1); - assertProjectIsAssociatedToProfile(project.key(), LANGUAGE_1, profile3Language1.getKey()); - assertProjectIsAssociatedToProfile(project.key(), LANGUAGE_2, profile2Language2.getKey()); + call(project, profile2); + + assertProjectIsNotAssociatedToProfile(project, profile1); + assertProjectIsAssociatedToProfile(project, profile2); } - private void assertProjectIsAssociatedToProfile(String projectKey, String language, String expectedProfileKey) { - assertThat(dbClient.qualityProfileDao().selectByProjectAndLanguage(session, projectKey, language).getKey()).isEqualTo(expectedProfileKey); + @Test + public void changing_association_does_not_change_other_language_associations() throws Exception { + logInAsProfileAdmin(db.getDefaultOrganization()); + ComponentDto project = db.components().insertProject(db.getDefaultOrganization()); + QualityProfileDto profile1Language1 = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(LANGUAGE_1)); + QualityProfileDto profile2Language2 = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(LANGUAGE_2)); + QualityProfileDto profile3Language1 = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(LANGUAGE_1)); + db.qualityProfiles().associateProjectWithQualityProfile(project, profile1Language1, profile2Language2); + + call(project, profile3Language1); + + assertProjectIsAssociatedToProfile(project, profile3Language1); + assertProjectIsAssociatedToProfile(project, profile2Language2); } - private void setUserAsQualityProfileAdmin() { - userSession.logIn().addPermission(ADMINISTER_QUALITY_PROFILES, project.getOrganizationUuid()); + @Test + public void project_administrator_can_change_profile() throws Exception { + ComponentDto project = db.components().insertProject(db.getDefaultOrganization()); + QualityProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization()); + userSession.logIn().addProjectUuidPermissions(UserRole.ADMIN, project.uuid()); + + call(project, profile); + + assertProjectIsAssociatedToProfile(project, profile); } - private void executeRequest(ComponentDto project, QualityProfileDto qualityProfile) { - TestRequest request = ws.newRequest() + @Test + public void throw_ForbiddenException_if_not_project_nor_organization_administrator() { + userSession.logIn(); + ComponentDto project = db.components().insertProject(db.getDefaultOrganization()); + QualityProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization()); + + expectedException.expect(ForbiddenException.class); + expectedException.expectMessage("Insufficient privileges"); + + call(project, profile); + } + + @Test + public void throw_UnauthorizedException_if_not_logged_in() { + userSession.anonymous(); + ComponentDto project = db.components().insertProject(db.getDefaultOrganization()); + QualityProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization()); + + expectedException.expect(UnauthorizedException.class); + expectedException.expectMessage("Authentication is required"); + + call(project, profile); + } + + @Test + public void throw_NotFoundException_if_project_does_not_exist() { + logInAsProfileAdmin(db.getDefaultOrganization()); + QualityProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization()); + + expectedException.expect(NotFoundException.class); + expectedException.expectMessage("Component id 'unknown' not found"); + + tester.newRequest() + .setParam("projectUuid", "unknown") + .setParam("profileKey", profile.getKey()) + .execute(); + } + + @Test + public void throw_NotFoundException_if_profile_does_not_exist() { + logInAsProfileAdmin(db.getDefaultOrganization()); + ComponentDto project = db.components().insertProject(db.getDefaultOrganization()); + + expectedException.expect(NotFoundException.class); + expectedException.expectMessage("Quality Profile with key 'unknown' does not exist"); + + tester.newRequest() + .setParam("projectUuid", project.uuid()) + .setParam("profileKey", "unknown") + .execute(); + } + + private void assertProjectIsAssociatedToProfile(ComponentDto project, QualityProfileDto profile) { + QualityProfileDto loaded = dbClient.qualityProfileDao().selectByProjectAndLanguage(db.getSession(), project.getKey(), profile.getLanguage()); + assertThat(loaded.getKey()).isEqualTo(profile.getKey()); + } + + private void assertProjectIsNotAssociatedToProfile(ComponentDto project, QualityProfileDto profile) { + QualityProfileDto loaded = dbClient.qualityProfileDao().selectByProjectAndLanguage(db.getSession(), project.getKey(), profile.getLanguage()); + assertThat(loaded == null || !loaded.getKey().equals(profile.getKey())).isTrue(); + } + + private void logInAsProfileAdmin(OrganizationDto organization) { + userSession.logIn().addPermission(ADMINISTER_QUALITY_PROFILES, organization); + } + + private TestResponse call(ComponentDto project, QualityProfileDto qualityProfile) { + TestRequest request = tester.newRequest() .setParam("projectUuid", project.uuid()) .setParam("profileKey", qualityProfile.getKey()); - request.execute(); + return request.execute(); } + private TestResponse call(OrganizationDto organization, ComponentDto project, QualityProfileDto qualityProfile) { + TestRequest request = tester.newRequest() + .setParam("organization", organization.getKey()) + .setParam("projectUuid", project.uuid()) + .setParam("language", qualityProfile.getLanguage()) + .setParam("profileName", qualityProfile.getName()); + return request.execute(); + } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsMediumTest.java index 1ccc3ed5155..f36dd9f10e0 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsMediumTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsMediumTest.java @@ -32,10 +32,6 @@ import org.sonar.api.rule.Severity; import org.sonar.api.server.ws.WebService; import org.sonar.db.DbClient; import org.sonar.db.DbSession; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.component.ComponentTesting; -import org.sonar.db.organization.OrganizationDto; -import org.sonar.db.organization.OrganizationTesting; import org.sonar.db.qualityprofile.ActiveRuleDao; import org.sonar.db.qualityprofile.ActiveRuleDto; import org.sonar.db.qualityprofile.ActiveRuleKey; @@ -44,8 +40,6 @@ import org.sonar.db.rule.RuleDto; import org.sonar.db.rule.RuleTesting; import org.sonar.server.es.SearchOptions; import org.sonar.server.exceptions.BadRequestException; -import org.sonar.server.exceptions.NotFoundException; -import org.sonar.server.qualityprofile.QProfileFactory; import org.sonar.server.qualityprofile.QProfileName; import org.sonar.server.qualityprofile.QProfileTesting; import org.sonar.server.qualityprofile.index.ActiveRuleIndexer; @@ -436,143 +430,6 @@ public class QProfilesWsMediumTest { assertThat(db.activeRuleDao().selectOrFailByKey(session, active2.getKey()).getSeverityString()).isNotEqualTo("MINOR"); } - @Test - public void add_project_with_key_and_uuid() throws Exception { - OrganizationDto organizationDto = OrganizationTesting.newOrganizationDto(); - db.organizationDao().insert(session, organizationDto); - ComponentDto project = ComponentTesting.newProjectDto(organizationDto, "ABCD").setId(1L); - db.componentDao().insert(session, project); - QualityProfileDto profile = QProfileTesting.newXooP1("org-123"); - db.qualityProfileDao().insert(session, profile); - - session.commit(); - - wsTester.newPostRequest(QProfilesWs.API_ENDPOINT, "add_project") - .setParam("profileKey", profile.getKee()).setParam("projectUuid", project.uuid()) - .execute().assertNoContent(); - assertThat(tester.get(QProfileFactory.class).getByProjectAndLanguage(session, project.getKey(), "xoo").getKee()).isEqualTo(profile.getKee()); - - // Second call must not fail, do nothing - wsTester.newPostRequest(QProfilesWs.API_ENDPOINT, "add_project") - .setParam("profileKey", profile.getKee()).setParam("projectUuid", project.uuid()) - .execute().assertNoContent(); - assertThat(tester.get(QProfileFactory.class).getByProjectAndLanguage(session, project.getKey(), "xoo").getKee()).isEqualTo(profile.getKee()); - } - - @Test - public void change_project_association_with_key_and_uuid() throws Exception { - OrganizationDto organizationDto = OrganizationTesting.newOrganizationDto(); - db.organizationDao().insert(session, organizationDto); - ComponentDto project = ComponentTesting.newProjectDto(organizationDto, "ABCD").setId(1L); - db.componentDao().insert(session, project); - QualityProfileDto profile1 = QProfileTesting.newXooP1("org-123"); - QualityProfileDto profile2 = QProfileTesting.newXooP2("org-123"); - db.qualityProfileDao().insert(session, profile1, profile2); - db.qualityProfileDao().insertProjectProfileAssociation(project.uuid(), profile1.getKey(), session); - - session.commit(); - - wsTester.newPostRequest(QProfilesWs.API_ENDPOINT, "add_project") - .setParam("profileKey", profile2.getKee()).setParam("projectUuid", project.uuid()) - .execute().assertNoContent(); - assertThat(tester.get(QProfileFactory.class).getByProjectAndLanguage(session, project.getKey(), "xoo").getKee()).isEqualTo(profile2.getKee()); - } - - @Test - public void add_project_with_name_language_and_key() throws Exception { - OrganizationDto organizationDto = OrganizationTesting.newOrganizationDto(); - db.organizationDao().insert(session, organizationDto); - ComponentDto project = ComponentTesting.newProjectDto(organizationDto, "ABCD").setId(1L); - db.componentDao().insert(session, project); - QualityProfileDto profile = QProfileTesting.newXooP1("org-123"); - db.qualityProfileDao().insert(session, profile); - - session.commit(); - - wsTester.newPostRequest(QProfilesWs.API_ENDPOINT, "add_project") - .setParam("language", "xoo").setParam("profileName", profile.getName()).setParam("projectKey", project.getKey()) - .execute().assertNoContent(); - assertThat(tester.get(QProfileFactory.class).getByProjectAndLanguage(session, project.getKey(), "xoo").getKee()).isEqualTo(profile.getKee()); - } - - @Test(expected = IllegalArgumentException.class) - public void add_project_missing_language() throws Exception { - wsTester.newPostRequest(QProfilesWs.API_ENDPOINT, "add_project") - .setParam("profileName", "polop").setParam("projectKey", "palap") - .execute(); - } - - @Test(expected = IllegalArgumentException.class) - public void add_project_missing_name() throws Exception { - wsTester.newPostRequest(QProfilesWs.API_ENDPOINT, "add_project") - .setParam("language", "xoo").setParam("projectKey", "palap") - .execute(); - } - - @Test(expected = IllegalArgumentException.class) - public void add_project_too_many_profile_parameters() throws Exception { - wsTester.newPostRequest(QProfilesWs.API_ENDPOINT, "add_project") - .setParam("profileKey", "plouf").setParam("language", "xoo").setParam("profileName", "polop").setParam("projectUuid", "palap") - .execute(); - } - - @Test(expected = IllegalArgumentException.class) - public void add_project_missing_project() throws Exception { - wsTester.newPostRequest(QProfilesWs.API_ENDPOINT, "add_project") - .setParam("profileKey", "plouf") - .execute(); - } - - @Test(expected = IllegalArgumentException.class) - public void add_project_too_many_project_parameters() throws Exception { - wsTester.newPostRequest(QProfilesWs.API_ENDPOINT, "add_project") - .setParam("profileKey", "plouf").setParam("projectUuid", "polop").setParam("projectKey", "palap") - .execute(); - } - - @Test(expected = NotFoundException.class) - public void add_project_unknown_profile() throws Exception { - wsTester.newPostRequest(QProfilesWs.API_ENDPOINT, "add_project") - .setParam("projectUuid", "plouf").setParam("profileName", "polop").setParam("language", "xoo") - .execute(); - } - - @Test - public void remove_project_with_key_and_uuid() throws Exception { - OrganizationDto organizationDto = OrganizationTesting.newOrganizationDto(); - db.organizationDao().insert(session, organizationDto); - ComponentDto project = ComponentTesting.newProjectDto(organizationDto, "ABCD").setId(1L); - db.componentDao().insert(session, project); - QualityProfileDto profile = QProfileTesting.newXooP1("org-123"); - db.qualityProfileDao().insert(session, profile); - db.qualityProfileDao().insertProjectProfileAssociation(project.uuid(), profile.getKee(), session); - - session.commit(); - - wsTester.newPostRequest(QProfilesWs.API_ENDPOINT, "remove_project") - .setParam("profileKey", profile.getKee()).setParam("projectUuid", project.uuid()) - .execute().assertNoContent(); - assertThat(tester.get(QProfileFactory.class).getByProjectAndLanguage(session, project.getKey(), "xoo")).isNull(); - } - - @Test - public void remove_project_with_name_language_and_key() throws Exception { - OrganizationDto organizationDto = OrganizationTesting.newOrganizationDto(); - db.organizationDao().insert(session, organizationDto); - ComponentDto project = ComponentTesting.newProjectDto(organizationDto, "ABCD").setId(1L); - db.componentDao().insert(session, project); - QualityProfileDto profile = QProfileTesting.newXooP1("org-123"); - db.qualityProfileDao().insert(session, profile); - db.qualityProfileDao().insertProjectProfileAssociation(project.uuid(), profile.getKee(), session); - - session.commit(); - - wsTester.newPostRequest(QProfilesWs.API_ENDPOINT, "remove_project") - .setParam("language", "xoo").setParam("profileName", profile.getName()).setParam("projectKey", project.getKey()) - .execute().assertNoContent(); - assertThat(tester.get(QProfileFactory.class).getByProjectAndLanguage(session, project.getKey(), "xoo")).isNull(); - } - private QualityProfileDto createProfile(String lang) { QualityProfileDto profile = QProfileTesting.newQProfileDto("org-123", new QProfileName(lang, "P" + lang), "p" + lang); db.qualityProfileDao().insert(session, profile); diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsModuleTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsModuleTest.java index 60f84b6d05c..4c66f747be1 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsModuleTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsModuleTest.java @@ -29,6 +29,6 @@ public class QProfilesWsModuleTest { public void verify_count_of_added_components() { ComponentContainer container = new ComponentContainer(); new QProfilesWsModule().configure(container); - assertThat(container.size()).isEqualTo(26 + 2); + assertThat(container.size()).isEqualTo(24 + 2); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsTest.java index bc60c29e51c..defbe820c1a 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsTest.java @@ -57,15 +57,12 @@ public class QProfilesWsTest { DbClient dbClient = mock(DbClient.class); Languages languages = LanguageTesting.newLanguages(xoo1Key, xoo2Key); - ProjectAssociationParameters projectAssociationParameters = new ProjectAssociationParameters(languages); ProfileImporter[] importers = createImporters(languages); controller = new WsTester(new QProfilesWs( new RuleActivationActions(profileService), new BulkRuleActivationActions(profileService, null), - new AddProjectAction(projectAssociationParameters, null, null, dbClient), - new RemoveProjectAction(projectAssociationParameters, null, null, dbClient), new CreateAction(null, null, null, languages, wsSupport, userSessionRule, null, importers), new ImportersAction(importers), new SearchAction(null, languages, null, dbClient), @@ -133,22 +130,6 @@ public class QProfilesWsTest { assertThat(restoreProfiles.params()).hasSize(2); } - @Test - public void define_add_project_action() { - WebService.Action addProject = controller.action("add_project"); - assertThat(addProject).isNotNull(); - assertThat(addProject.isPost()).isTrue(); - assertThat(addProject.params()).hasSize(5); - } - - @Test - public void define_remove_project_action() { - WebService.Action removeProject = controller.action("remove_project"); - assertThat(removeProject).isNotNull(); - assertThat(removeProject.isPost()).isTrue(); - assertThat(removeProject.params()).hasSize(5); - } - @Test public void define_set_default_action() { WebService.Action setDefault = controller.action("set_default"); diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/RemoveProjectActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/RemoveProjectActionTest.java new file mode 100644 index 00000000000..5ff0737471c --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/RemoveProjectActionTest.java @@ -0,0 +1,194 @@ +/* + * 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.qualityprofile.ws; + +import java.net.HttpURLConnection; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.api.resources.Languages; +import org.sonar.api.server.ws.WebService; +import org.sonar.api.web.UserRole; +import org.sonar.db.DbClient; +import org.sonar.db.DbTester; +import org.sonar.db.component.ComponentDto; +import org.sonar.db.qualityprofile.QualityProfileDto; +import org.sonar.server.component.ComponentFinder; +import org.sonar.server.exceptions.ForbiddenException; +import org.sonar.server.exceptions.NotFoundException; +import org.sonar.server.exceptions.UnauthorizedException; +import org.sonar.server.language.LanguageTesting; +import org.sonar.server.organization.TestDefaultOrganizationProvider; +import org.sonar.server.tester.UserSessionRule; +import org.sonar.server.ws.TestRequest; +import org.sonar.server.ws.TestResponse; +import org.sonar.server.ws.WsActionTester; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.sonar.db.permission.OrganizationPermission.ADMINISTER_QUALITY_PROFILES; + +public class RemoveProjectActionTest { + private static final String LANGUAGE_1 = "xoo"; + private static final String LANGUAGE_2 = "foo"; + + @Rule + public DbTester db = DbTester.create(); + @Rule + public ExpectedException expectedException = ExpectedException.none(); + @Rule + public UserSessionRule userSession = UserSessionRule.standalone(); + + private DbClient dbClient = db.getDbClient(); + private Languages languages = LanguageTesting.newLanguages(LANGUAGE_1, LANGUAGE_2); + private QProfileWsSupport wsSupport = new QProfileWsSupport(dbClient, userSession, TestDefaultOrganizationProvider.from(db)); + private RemoveProjectAction underTest = new RemoveProjectAction(dbClient, userSession, languages, new ComponentFinder(dbClient), wsSupport); + private WsActionTester tester = new WsActionTester(underTest); + + @Test + public void test_definition() { + WebService.Action definition = tester.getDef(); + assertThat(definition.since()).isEqualTo("5.2"); + assertThat(definition.isPost()).isTrue(); + + // parameters + assertThat(definition.params()).extracting(WebService.Param::key).containsOnly("profileKey", "profileName", "projectKey", "language", "projectUuid", "organization"); + WebService.Param languageParam = definition.param("language"); + assertThat(languageParam.possibleValues()).containsOnly(LANGUAGE_1, LANGUAGE_2); + assertThat(languageParam.exampleValue()).isNull(); + WebService.Param organizationParam = definition.param("organization"); + assertThat(organizationParam.since()).isEqualTo("6.4"); + assertThat(organizationParam.isInternal()).isTrue(); + } + + @Test + public void remove_profile_from_project_in_default_organization() { + logInAsProfileAdmin(); + + ComponentDto project = db.components().insertProject(db.getDefaultOrganization()); + QualityProfileDto profileLang1 = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(LANGUAGE_1)); + QualityProfileDto profileLang2 = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(LANGUAGE_2)); + db.qualityProfiles().associateProjectWithQualityProfile(project, profileLang1); + db.qualityProfiles().associateProjectWithQualityProfile(project, profileLang2); + + TestResponse response = call(project, profileLang1); + assertThat(response.getStatus()).isEqualTo(HttpURLConnection.HTTP_NO_CONTENT); + + assertProjectIsNotAssociatedToProfile(project, profileLang1); + assertProjectIsAssociatedToProfile(project, profileLang2); + } + + @Test + public void removal_does_not_fail_if_profile_is_not_associated_to_project() { + logInAsProfileAdmin(); + + ComponentDto project = db.components().insertProject(db.getDefaultOrganization()); + QualityProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization()); + + TestResponse response = call(project, profile); + assertThat(response.getStatus()).isEqualTo(HttpURLConnection.HTTP_NO_CONTENT); + + assertProjectIsNotAssociatedToProfile(project, profile); + } + + @Test + public void project_administrator_can_remove_profile() throws Exception { + ComponentDto project = db.components().insertProject(db.getDefaultOrganization()); + QualityProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization()); + db.qualityProfiles().associateProjectWithQualityProfile(project, profile); + userSession.logIn().addProjectUuidPermissions(UserRole.ADMIN, project.uuid()); + + call(project, profile); + + assertProjectIsNotAssociatedToProfile(project, profile); + } + + @Test + public void throw_ForbiddenException_if_not_project_nor_organization_administrator() { + userSession.logIn(); + ComponentDto project = db.components().insertProject(db.getDefaultOrganization()); + QualityProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization()); + + expectedException.expect(ForbiddenException.class); + expectedException.expectMessage("Insufficient privileges"); + + call(project, profile); + } + + @Test + public void throw_UnauthorizedException_if_not_logged_in() { + userSession.anonymous(); + ComponentDto project = db.components().insertProject(db.getDefaultOrganization()); + QualityProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization()); + + expectedException.expect(UnauthorizedException.class); + expectedException.expectMessage("Authentication is required"); + + call(project, profile); + } + + @Test + public void throw_NotFoundException_if_project_does_not_exist() { + logInAsProfileAdmin(); + QualityProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization()); + + expectedException.expect(NotFoundException.class); + expectedException.expectMessage("Component id 'unknown' not found"); + + tester.newRequest() + .setParam("projectUuid", "unknown") + .setParam("profileKey", profile.getKey()) + .execute(); + } + + @Test + public void throw_NotFoundException_if_profile_does_not_exist() { + logInAsProfileAdmin(); + ComponentDto project = db.components().insertProject(db.getDefaultOrganization()); + + expectedException.expect(NotFoundException.class); + expectedException.expectMessage("Quality Profile with key 'unknown' does not exist"); + + tester.newRequest() + .setParam("projectUuid", project.uuid()) + .setParam("profileKey", "unknown") + .execute(); + } + + private void assertProjectIsAssociatedToProfile(ComponentDto project, QualityProfileDto profile) { + QualityProfileDto loaded = dbClient.qualityProfileDao().selectByProjectAndLanguage(db.getSession(), project.getKey(), profile.getLanguage()); + assertThat(loaded.getKey()).isEqualTo(profile.getKey()); + } + + private void assertProjectIsNotAssociatedToProfile(ComponentDto project, QualityProfileDto profile) { + QualityProfileDto loaded = dbClient.qualityProfileDao().selectByProjectAndLanguage(db.getSession(), project.getKey(), profile.getLanguage()); + assertThat(loaded == null || !loaded.getKey().equals(profile.getKey())).isTrue(); + } + + private void logInAsProfileAdmin() { + userSession.logIn().addPermission(ADMINISTER_QUALITY_PROFILES, db.getDefaultOrganization()); + } + + private TestResponse call(ComponentDto project, QualityProfileDto qualityProfile) { + TestRequest request = tester.newRequest() + .setParam("projectUuid", project.uuid()) + .setParam("profileKey", qualityProfile.getKey()); + return request.execute(); + } +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/SearchActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/SearchActionTest.java index f2dcb0fb894..fccaa2af6f9 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/SearchActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/SearchActionTest.java @@ -33,7 +33,6 @@ import org.sonar.api.resources.Language; import org.sonar.api.resources.Languages; import org.sonar.api.utils.DateUtils; import org.sonar.api.utils.System2; -import org.sonar.core.util.UuidFactoryFast; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.DbTester; @@ -51,7 +50,6 @@ import org.sonar.server.exceptions.BadRequestException; import org.sonar.server.language.LanguageTesting; import org.sonar.server.organization.DefaultOrganizationProvider; import org.sonar.server.organization.TestDefaultOrganizationProvider; -import org.sonar.server.qualityprofile.QProfileFactory; import org.sonar.server.qualityprofile.QProfileLookup; import org.sonar.server.qualityprofile.index.ActiveRuleIndex; import org.sonar.server.tester.UserSessionRule; @@ -78,7 +76,6 @@ import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters. import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PROFILE_NAME; import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PROJECT_KEY; - public class SearchActionTest { @Rule @@ -113,7 +110,6 @@ public class SearchActionTest { new SearchDataLoader( languages, new QProfileLookup(dbClient), - new QProfileFactory(dbClient, UuidFactoryFast.getInstance(), System2.INSTANCE), dbClient, new ComponentFinder(dbClient), qProfileWsSupport), languages, @@ -301,6 +297,7 @@ public class SearchActionTest { .contains("sonar-way-xoo1-12345", "sonar-way-xoo2-12345") .doesNotContain("sonar-way-xoo1-45678"); } + @Test public void search_default_profile_by_profile_name_and_org() { List profiles = new ArrayList<>(); diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/SearchDataLoaderTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/SearchDataLoaderTest.java index 215f30a9543..78d35c3c47c 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/SearchDataLoaderTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/SearchDataLoaderTest.java @@ -29,8 +29,6 @@ import org.junit.rules.ExpectedException; import org.sonar.api.resources.Language; import org.sonar.api.resources.Languages; import org.sonar.api.utils.System2; -import org.sonar.api.utils.internal.AlwaysIncreasingSystem2; -import org.sonar.core.util.UuidFactoryFast; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.DbTester; @@ -39,11 +37,9 @@ import org.sonar.db.organization.OrganizationDto; import org.sonar.db.qualityprofile.QualityProfileDto; import org.sonar.db.qualityprofile.QualityProfileTesting; import org.sonar.server.component.ComponentFinder; -import org.sonar.server.exceptions.BadRequestException; import org.sonar.server.language.LanguageTesting; import org.sonar.server.organization.TestDefaultOrganizationProvider; import org.sonar.server.qualityprofile.QProfile; -import org.sonar.server.qualityprofile.QProfileFactory; import org.sonar.server.qualityprofile.QProfileLookup; import org.sonar.server.qualityprofile.index.ActiveRuleIndex; import org.sonarqube.ws.client.qualityprofile.SearchWsRequest; @@ -55,7 +51,6 @@ import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; - public class SearchDataLoaderTest { @Rule @@ -66,7 +61,6 @@ public class SearchDataLoaderTest { private Languages languages; private QProfileLookup profileLookup; - private QProfileFactory profileFactory; private ComponentFinder componentFinder; private ActiveRuleIndex activeRuleIndex; private QProfileWsSupport qProfileWsSupport; @@ -80,23 +74,20 @@ public class SearchDataLoaderTest { profileLookup = new QProfileLookup(dbClient); TestDefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(dbTester); qProfileWsSupport = new QProfileWsSupport(dbClient, null, defaultOrganizationProvider); - profileFactory = new QProfileFactory(dbClient, UuidFactoryFast.getInstance(), new AlwaysIncreasingSystem2()); componentFinder = mock(ComponentFinder.class); } @Test public void find_no_profiles_if_database_is_empty() throws Exception { assertThat(findProfiles( - new SearchWsRequest() - )).isEmpty(); + new SearchWsRequest())).isEmpty(); } @Test public void findAll_in_default_organization() throws Exception { insertQualityProfile(dbTester.getDefaultOrganization()); assertThat(findProfiles( - new SearchWsRequest() - )).hasSize(1); + new SearchWsRequest())).hasSize(1); } @Test @@ -104,8 +95,7 @@ public class SearchDataLoaderTest { insertQualityProfile(organization); assertThat(findProfiles( new SearchWsRequest() - .setOrganizationKey(organization.getKey()) - )).hasSize(1); + .setOrganizationKey(organization.getKey()))).hasSize(1); } @Test @@ -114,8 +104,7 @@ public class SearchDataLoaderTest { assertThat(findProfiles( new SearchWsRequest() .setOrganizationKey(organization.getKey()) - .setDefaults(true) - )).hasSize(1); + .setDefaults(true))).hasSize(1); } @Test @@ -125,8 +114,7 @@ public class SearchDataLoaderTest { assertThat(findProfiles( new SearchWsRequest() .setOrganizationKey(organization.getKey()) - .setProjectKey(project1.getKey()) - )).hasSize(1); + .setProjectKey(project1.getKey()))).hasSize(1); } @Test @@ -135,17 +123,15 @@ public class SearchDataLoaderTest { assertThat(findProfiles( new SearchWsRequest() .setOrganizationKey(organization.getKey()) - .setLanguage(qualityProfile.getLanguage()) - )).hasSize(1); + .setLanguage(qualityProfile.getLanguage()))).hasSize(1); assertThat(findProfiles( new SearchWsRequest() .setOrganizationKey(organization.getKey()) - .setLanguage("other language") - )).hasSize(0); + .setLanguage("other language"))).hasSize(0); } private List findProfiles(SearchWsRequest request) { - return new SearchDataLoader(languages, profileLookup, profileFactory, dbTester.getDbClient(), componentFinder, qProfileWsSupport) + return new SearchDataLoader(languages, profileLookup, dbTester.getDbClient(), componentFinder, qProfileWsSupport) .findProfiles(dbTester.getSession(), request); } -- 2.39.5