diff --git a/it/it-tests/src/test/java/it/analysis/IssuesModeTest.java b/it/it-tests/src/test/java/it/analysis/IssuesModeTest.java index 0b96a811bd3f..d2038ab073c5 100644 --- a/it/it-tests/src/test/java/it/analysis/IssuesModeTest.java +++ b/it/it-tests/src/test/java/it/analysis/IssuesModeTest.java @@ -207,9 +207,8 @@ public void only_scan_changed_files_on_change() throws IOException { // SONAR-8518 @Test - public void shoud_support_sonar_profile_prop() throws IOException { + public void should_support_sonar_profile_prop() throws IOException { restoreProfile("one-issue-per-line.xml"); - restoreProfile("empty.xml"); orchestrator.getServer().provisionProject("sample", "xoo-sample"); orchestrator.getServer().associateProjectToQualityProfile("sample", "xoo", "empty"); diff --git a/it/it-tests/src/test/java/it/qualityProfile/OrganizationQualityProfilesPageTest.java b/it/it-tests/src/test/java/it/qualityProfile/OrganizationQualityProfilesPageTest.java index eeeab7003b0c..b5a8501810bd 100644 --- a/it/it-tests/src/test/java/it/qualityProfile/OrganizationQualityProfilesPageTest.java +++ b/it/it-tests/src/test/java/it/qualityProfile/OrganizationQualityProfilesPageTest.java @@ -152,9 +152,7 @@ public void testSettingDefault() throws Exception { public void testRestoration() throws Exception { deleteProfile("xoo", "empty"); - runSelenese(orchestrator, - "/organization/OrganizationQualityProfilesPageTest/should_restore.html", - "/organization/OrganizationQualityProfilesPageTest/should_restore_built_in.html"); + runSelenese(orchestrator, "/organization/OrganizationQualityProfilesPageTest/should_restore.html"); } private static void createProfile(String language, String name) { diff --git a/it/it-tests/src/test/java/it/qualityProfile/QualityProfilesPageTest.java b/it/it-tests/src/test/java/it/qualityProfile/QualityProfilesPageTest.java index 73e9902e4b58..6c29b8e9b1ef 100644 --- a/it/it-tests/src/test/java/it/qualityProfile/QualityProfilesPageTest.java +++ b/it/it-tests/src/test/java/it/qualityProfile/QualityProfilesPageTest.java @@ -134,9 +134,7 @@ public void testSettingDefault() throws Exception { public void testRestoration() throws Exception { deleteProfile("xoo", "empty"); - runSelenese(orchestrator, - "/qualityProfile/QualityProfilesPageTest/should_restore.html", - "/qualityProfile/QualityProfilesPageTest/should_restore_built_in.html"); + runSelenese(orchestrator, "/qualityProfile/QualityProfilesPageTest/should_restore.html"); } private static void createProfile(String language, String name) { diff --git a/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesPageTest/should_restore_built_in.html b/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesPageTest/should_restore_built_in.html deleted file mode 100644 index 82005c7102e6..000000000000 --- a/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesPageTest/should_restore_built_in.html +++ /dev/null @@ -1,95 +0,0 @@ - - - - - - - should_create - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
should_create
open/sessions/logout
open/sessions/login
typeid=passwordadmin
typeid=loginadmin
clickAndWaitname=commit
waitForElementPresentcss=.js-user-authenticated
open/organizations/test-org/quality_profiles
waitForElementPresentcss=.quality-profiles-table-row[data-name="sample"]
assertElementNotPresentcss=.quality-profiles-table-row[data-name="empty"]
clickcss=.js-more-admin-actions
clickcss=#quality-profiles-restore-built-in
clickcss=#restore-built-in-profiles-submit
waitForElementPresentcss=#restore-built-in-profiles-form .alert-success
clickcss=.js-modal-close
waitForElementPresentcss=.quality-profiles-table-row[data-name="empty"]
- - diff --git a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_restore_built_in.html b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_restore_built_in.html deleted file mode 100644 index 261b1f140cbf..000000000000 --- a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_restore_built_in.html +++ /dev/null @@ -1,95 +0,0 @@ - - - - - - - should_create - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
should_create
open/sessions/logout
open/sessions/login
typeid=passwordadmin
typeid=loginadmin
clickAndWaitname=commit
waitForElementPresentcss=.js-user-authenticated
open/profiles
waitForElementPresentcss=.quality-profiles-table-row[data-name="sample"]
assertElementNotPresentcss=.quality-profiles-table-row[data-name="empty"]
clickcss=.js-more-admin-actions
clickcss=#quality-profiles-restore-built-in
clickcss=#restore-built-in-profiles-submit
waitForElementPresentcss=#restore-built-in-profiles-form .alert-success
clickcss=.js-modal-close
waitForElementPresentcss=.quality-profiles-table-row[data-name="empty"]
- - 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 026bc8c7d3c5..0236aa159726 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 @@ -34,6 +34,7 @@ import org.sonar.server.exceptions.BadRequestException; import org.sonar.server.qualityprofile.index.ActiveRuleIndexer; +import static com.google.common.base.Preconditions.checkArgument; import static org.sonar.server.ws.WsUtils.checkRequest; /** @@ -55,12 +56,20 @@ public QProfileFactory(DbClient db, UuidFactory uuidFactory, System2 system2, Ac // ------------- CREATION + private static OrganizationDto requireNonNull(@Nullable OrganizationDto organization) { + Objects.requireNonNull(organization, "Organization is required, when creating a quality profile."); + return organization; + } + RulesProfileDto getOrCreateCustom(DbSession dbSession, OrganizationDto organization, QProfileName name) { requireNonNull(organization); RulesProfileDto profile = db.qualityProfileDao().selectByNameAndLanguage(organization, name.getName(), name.getLanguage(), dbSession); if (profile == null) { profile = doCreate(dbSession, organization, name, false, false); + } else { + checkArgument(!profile.isBuiltIn(), "Operation forbidden for built-in Quality Profile '%s' with language '%s'", profile.getName(), profile.getLanguage()); } + return profile; } @@ -85,11 +94,6 @@ public RulesProfileDto createBuiltIn(DbSession dbSession, OrganizationDto organi return doCreate(dbSession, requireNonNull(organization), name, isDefault, true); } - private static OrganizationDto requireNonNull(@Nullable OrganizationDto organization) { - Objects.requireNonNull(organization, "Organization is required, when creating a quality profile."); - return organization; - } - private RulesProfileDto doCreate(DbSession dbSession, OrganizationDto organization, QProfileName name, boolean isDefault, boolean isBuiltIn) { if (StringUtils.isEmpty(name.getName())) { throw BadRequestException.create("quality_profiles.profile_name_cant_be_blank"); diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileReset.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileReset.java index ed71be10acd7..97d8ecea1938 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileReset.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileReset.java @@ -21,15 +21,9 @@ import java.util.Collection; import org.sonar.db.DbSession; -import org.sonar.db.organization.OrganizationDto; import org.sonar.db.qualityprofile.RulesProfileDto; public interface QProfileReset { - /** - * Restore the built-in profiles provided by plugins for the specified language. - * Missing profiles are created and existing ones are updated. - */ - void resetLanguage(DbSession dbSession, OrganizationDto organization, String language); /** * Reset the rules of the specified profile. diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileResetImpl.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileResetImpl.java index b539981155af..b4ae1d524cf3 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileResetImpl.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileResetImpl.java @@ -19,84 +19,41 @@ */ package org.sonar.server.qualityprofile; -import com.google.common.collect.Lists; import com.google.common.collect.Sets; import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.Map; import java.util.Set; import org.sonar.api.rule.RuleKey; -import org.sonar.api.rules.ActiveRule; -import org.sonar.api.rules.ActiveRuleParam; 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.ActiveRuleDto; import org.sonar.db.qualityprofile.ActiveRuleKey; import org.sonar.db.qualityprofile.RulesProfileDto; -import org.sonar.db.rule.RuleParamDto; import org.sonar.server.exceptions.BadRequestException; import org.sonar.server.qualityprofile.index.ActiveRuleIndexer; +import static com.google.common.base.Preconditions.checkArgument; import static java.util.Objects.requireNonNull; @ServerSide public class QProfileResetImpl implements QProfileReset { private final DbClient db; - private final QProfileFactory factory; private final RuleActivator activator; private final ActiveRuleIndexer activeRuleIndexer; - private final BuiltInQProfileRepository builtInQProfileRepositories; - public QProfileResetImpl(DbClient db, RuleActivator activator, ActiveRuleIndexer activeRuleIndexer, QProfileFactory factory, - BuiltInQProfileRepository builtInQProfileRepository) { + public QProfileResetImpl(DbClient db, RuleActivator activator, ActiveRuleIndexer activeRuleIndexer) { this.db = db; this.activator = activator; this.activeRuleIndexer = activeRuleIndexer; - this.factory = factory; - this.builtInQProfileRepositories = builtInQProfileRepository; - } - - @Override - public void resetLanguage(DbSession dbSession, OrganizationDto organization, String language) { - builtInQProfileRepositories.getQProfilesByLanguage() - .entrySet() - .stream() - .filter(entry -> entry.getKey().equals(language)) - .map(Map.Entry::getValue) - .flatMap(List::stream) - .forEach(builtInQProfile -> resetProfile(dbSession, organization, builtInQProfile)); - } - - private void resetProfile(DbSession dbSession, OrganizationDto organization, BuiltInQProfile builtInQProfile) { - RulesProfileDto profile = factory.getOrCreateCustom(dbSession, organization, builtInQProfile.getQProfileName()); - - List activations = Lists.newArrayList(); - builtInQProfile.getActiveRules().forEach(activeRule -> activations.add(getRuleActivation(dbSession, activeRule))); - reset(dbSession, profile, activations); - } - - private RuleActivation getRuleActivation(DbSession dbSession, ActiveRule activeRule) { - RuleActivation activation = new RuleActivation(RuleKey.of(activeRule.getRepositoryKey(), activeRule.getRuleKey())); - activation.setSeverity(activeRule.getSeverity().name()); - if (!activeRule.getActiveRuleParams().isEmpty()) { - for (ActiveRuleParam param : activeRule.getActiveRuleParams()) { - activation.setParameter(param.getParamKey(), param.getValue()); - } - } else { - for (RuleParamDto param : db.ruleDao().selectRuleParamsByRuleKey(dbSession, activeRule.getRule().ruleKey())) { - activation.setParameter(param.getName(), param.getDefaultValue()); - } - } - return activation; } @Override public BulkChangeResult reset(DbSession dbSession, RulesProfileDto profile, Collection activations) { requireNonNull(profile.getId(), "Quality profile must be persisted"); + checkArgument(!profile.isBuiltIn(), "Operation forbidden for built-in Quality Profile '%s'", profile.getKee()); BulkChangeResult result = new BulkChangeResult(); Set ruleToBeDeactivated = Sets.newHashSet(); // Keep reference to all the activated rules before backup restore diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ActivateRuleAction.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ActivateRuleAction.java index 358a9b4cb6ec..ae042d08121f 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ActivateRuleAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ActivateRuleAction.java @@ -30,6 +30,7 @@ import org.sonar.core.util.Uuids; import org.sonar.db.DbClient; import org.sonar.db.DbSession; +import org.sonar.db.qualityprofile.RulesProfileDto; import org.sonar.server.qualityprofile.ActiveRuleChange; import org.sonar.server.qualityprofile.RuleActivation; import org.sonar.server.qualityprofile.RuleActivator; @@ -106,7 +107,9 @@ public void handle(Request request, Response response) throws Exception { String profileKey = request.mandatoryParam(PARAM_PROFILE_KEY); userSession.checkLoggedIn(); try (DbSession dbSession = dbClient.openSession(false)) { - wsSupport.checkPermission(dbSession, profileKey); + RulesProfileDto profile = wsSupport.getProfile(dbSession, QProfileReference.fromKey(profileKey)); + wsSupport.checkPermission(dbSession, profile); + wsSupport.checkNotBuiltInt(profile); List changes = ruleActivator.activate(dbSession, activation, profileKey); dbSession.commit(); activeRuleIndexer.index(changes); diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ActivateRulesAction.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ActivateRulesAction.java index a0816c04fdfa..0afa944d72de 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ActivateRulesAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ActivateRulesAction.java @@ -26,11 +26,13 @@ import org.sonar.api.server.ws.WebService; import org.sonar.db.DbClient; import org.sonar.db.DbSession; +import org.sonar.db.qualityprofile.RulesProfileDto; import org.sonar.server.qualityprofile.BulkChangeResult; import org.sonar.server.qualityprofile.RuleActivator; import org.sonar.server.rule.ws.RuleQueryFactory; import org.sonar.server.user.UserSession; +import static org.sonar.server.qualityprofile.ws.QProfileReference.fromKey; import static org.sonar.server.rule.ws.SearchAction.defineRuleSearchParameters; @ServerSide @@ -81,7 +83,9 @@ public void handle(Request request, Response response) throws Exception { userSession.checkLoggedIn(); BulkChangeResult result; try (DbSession dbSession = dbClient.openSession(false)) { - wsSupport.checkPermission(dbSession, qualityProfileKey); + RulesProfileDto profile = wsSupport.getProfile(dbSession, fromKey(qualityProfileKey)); + wsSupport.checkPermission(dbSession, profile); + wsSupport.checkNotBuiltInt(profile); result = ruleActivator.bulkActivate(ruleQueryFactory.createRuleQuery(dbSession, request), qualityProfileKey, request.param(SEVERITY)); } BulkChangeWsResponse.writeResponse(result, response); diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ChangeParentAction.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ChangeParentAction.java index e2ab0746b1c2..90781127d12e 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ChangeParentAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ChangeParentAction.java @@ -90,6 +90,7 @@ public void handle(Request request, Response response) throws Exception { OrganizationDto organization = dbClient.organizationDao().selectByUuid(dbSession, organizationUuid) .orElseThrow(() -> new IllegalStateException(String.format("Could not find organization with uuid '%s' of profile '%s'", organizationUuid, profile.getKee()))); userSession.checkPermission(ADMINISTER_QUALITY_PROFILES, organization); + wsSupport.checkNotBuiltInt(profile); String parentKey = request.param(PARAM_PARENT_KEY); String parentName = request.param(PARAM_PARENT_NAME); diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/DeactivateRuleAction.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/DeactivateRuleAction.java index 3f6d1f66fcbc..43ae0be68b90 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/DeactivateRuleAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/DeactivateRuleAction.java @@ -28,6 +28,7 @@ import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.qualityprofile.ActiveRuleKey; +import org.sonar.db.qualityprofile.RulesProfileDto; import org.sonar.server.qualityprofile.RuleActivator; import org.sonar.server.user.UserSession; @@ -75,7 +76,9 @@ public void handle(Request request, Response response) throws Exception { String qualityProfileKey = request.mandatoryParam(PARAM_PROFILE_KEY); userSession.checkLoggedIn(); try (DbSession dbSession = dbClient.openSession(false)) { - wsSupport.checkPermission(dbSession, qualityProfileKey); + RulesProfileDto profile = wsSupport.getProfile(dbSession, QProfileReference.fromKey(qualityProfileKey)); + wsSupport.checkPermission(dbSession, profile); + wsSupport.checkNotBuiltInt(profile); ActiveRuleKey activeRuleKey = ActiveRuleKey.of(qualityProfileKey, ruleKey); ruleActivator.deactivateAndUpdateIndex(dbSession, activeRuleKey); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/DeactivateRulesAction.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/DeactivateRulesAction.java index 5273652df087..862be86aa712 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/DeactivateRulesAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/DeactivateRulesAction.java @@ -25,6 +25,7 @@ import org.sonar.api.server.ws.WebService; import org.sonar.db.DbClient; import org.sonar.db.DbSession; +import org.sonar.db.qualityprofile.RulesProfileDto; import org.sonar.server.qualityprofile.BulkChangeResult; import org.sonar.server.qualityprofile.RuleActivator; import org.sonar.server.rule.ws.RuleQueryFactory; @@ -76,7 +77,9 @@ public void handle(Request request, Response response) throws Exception { userSession.checkLoggedIn(); BulkChangeResult result; try (DbSession dbSession = dbClient.openSession(false)) { - wsSupport.checkPermission(dbSession, qualityProfileKey); + RulesProfileDto profile = wsSupport.getProfile(dbSession, QProfileReference.fromKey(qualityProfileKey)); + wsSupport.checkPermission(dbSession, profile); + wsSupport.checkNotBuiltInt(profile); result = ruleActivator.bulkDeactivate(ruleQueryFactory.createRuleQuery(dbSession, request), qualityProfileKey); } BulkChangeWsResponse.writeResponse(result, response); diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/DeleteAction.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/DeleteAction.java index 2a0572021d01..8e838d80b79d 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/DeleteAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/DeleteAction.java @@ -44,14 +44,14 @@ public class DeleteAction implements QProfileWsAction { private final QProfileFactory profileFactory; private final DbClient dbClient; private final UserSession userSession; - private final QProfileWsSupport qProfileWsSupport; + private final QProfileWsSupport wsSupport; - public DeleteAction(Languages languages, QProfileFactory profileFactory, DbClient dbClient, UserSession userSession, QProfileWsSupport qProfileWsSupport) { + public DeleteAction(Languages languages, QProfileFactory profileFactory, DbClient dbClient, UserSession userSession, QProfileWsSupport wsSupport) { this.languages = languages; this.profileFactory = profileFactory; this.dbClient = dbClient; this.userSession = userSession; - this.qProfileWsSupport = qProfileWsSupport; + this.wsSupport = wsSupport; } @Override @@ -72,8 +72,9 @@ public void handle(Request request, Response response) { userSession.checkLoggedIn(); try (DbSession dbSession = dbClient.openSession(false)) { - RulesProfileDto profile = qProfileWsSupport.getProfile(dbSession, QProfileReference.from(request)); + RulesProfileDto profile = wsSupport.getProfile(dbSession, QProfileReference.from(request)); userSession.checkPermission(ADMINISTER_QUALITY_PROFILES, profile.getOrganizationUuid()); + wsSupport.checkNotBuiltInt(profile); List descendants = selectDescendants(dbSession, profile); ensureNoneIsMarkedAsDefault(dbSession, profile, descendants); 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 ee97ba8ce40f..824b1fd14e96 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 @@ -35,6 +35,7 @@ import static java.util.Objects.requireNonNull; import static org.sonar.server.ws.WsUtils.checkFound; +import static org.sonar.server.ws.WsUtils.checkRequest; import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_ORGANIZATION; @ServerSide @@ -50,6 +51,15 @@ public QProfileWsSupport(DbClient dbClient, UserSession userSession, DefaultOrga this.defaultOrganizationProvider = defaultOrganizationProvider; } + public static NewParam createOrganizationParam(NewAction action) { + return action + .createParam(PARAM_ORGANIZATION) + .setDescription("Organization key") + .setRequired(false) + .setInternal(true) + .setExampleValue("my-org"); + } + public OrganizationDto getOrganization(DbSession dbSession, RulesProfileDto profile) { requireNonNull(profile); String organizationUuid = profile.getOrganizationUuid(); @@ -65,15 +75,6 @@ public OrganizationDto getOrganizationByKey(DbSession dbSession, @Nullable Strin "No organization with key '%s'", organizationOrDefaultKey); } - public static NewParam createOrganizationParam(NewAction action) { - return action - .createParam(PARAM_ORGANIZATION) - .setDescription("Organization key") - .setRequired(false) - .setInternal(true) - .setExampleValue("my-org"); - } - /** * Get the Quality profile specified by the reference {@code ref}. * @@ -93,9 +94,12 @@ public RulesProfileDto getProfile(DbSession dbSession, QProfileReference ref) { return profile; } - public void checkPermission(DbSession dbSession, String qualityProfileKey) { - RulesProfileDto qualityProfile = dbClient.qualityProfileDao().selectByKey(dbSession, qualityProfileKey); - OrganizationDto organization = getOrganization(dbSession, qualityProfile); + public void checkPermission(DbSession dbSession, RulesProfileDto rulesProfile) { + OrganizationDto organization = getOrganization(dbSession, rulesProfile); userSession.checkPermission(OrganizationPermission.ADMINISTER_QUALITY_PROFILES, organization); } + + public void checkNotBuiltInt(RulesProfileDto profile) { + checkRequest(!profile.isBuiltIn(), "Operation forbidden for built-in Quality Profile '%s' with language '%s'", profile.getName(), profile.getLanguage()); + } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/RenameAction.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/RenameAction.java index 7a4193138ffd..1d46426707b8 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/RenameAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/RenameAction.java @@ -32,7 +32,6 @@ import org.sonar.db.organization.OrganizationDto; import org.sonar.db.qualityprofile.RulesProfileDto; import org.sonar.server.exceptions.BadRequestException; -import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.user.UserSession; import static java.lang.String.format; @@ -48,10 +47,12 @@ public class RenameAction implements QProfileWsAction { private final DbClient dbClient; private final UserSession userSession; + private final QProfileWsSupport wsSupport; - public RenameAction(DbClient dbClient, UserSession userSession) { + public RenameAction(DbClient dbClient, UserSession userSession, QProfileWsSupport wsSupport) { this.dbClient = dbClient; this.userSession = userSession; + this.wsSupport = wsSupport; } @Override @@ -88,11 +89,11 @@ void doHandle(String newName, String profileKey) { userSession.checkLoggedIn(); try (DbSession dbSession = dbClient.openSession(false)) { - RulesProfileDto qualityProfile = ofNullable(dbClient.qualityProfileDao().selectByKey(dbSession, profileKey)) - .orElseThrow(() -> new NotFoundException("Quality profile not found: " + profileKey)); + RulesProfileDto qualityProfile = wsSupport.getProfile(dbSession, QProfileReference.fromKey(profileKey)); String organizationUuid = qualityProfile.getOrganizationUuid(); userSession.checkPermission(ADMINISTER_QUALITY_PROFILES, organizationUuid); + wsSupport.checkNotBuiltInt(qualityProfile); if (!Objects.equals(newName, qualityProfile.getName())) { OrganizationDto organization = dbClient.organizationDao().selectByUuid(dbSession, organizationUuid) diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/RestoreAction.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/RestoreAction.java index edcefa69f4ea..0e6d30370064 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/RestoreAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/RestoreAction.java @@ -31,7 +31,6 @@ import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.organization.OrganizationDto; -import org.sonar.db.permission.OrganizationPermission; import org.sonar.db.qualityprofile.RulesProfileDto; import org.sonar.server.qualityprofile.BulkChangeResult; import org.sonar.server.qualityprofile.QProfileBackuper; @@ -40,6 +39,7 @@ import static com.google.common.base.Preconditions.checkArgument; import static java.nio.charset.StandardCharsets.UTF_8; +import static org.sonar.db.permission.OrganizationPermission.ADMINISTER_QUALITY_PROFILES; import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_ORGANIZATION; import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.ACTION_RESTORE; import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.RestoreActionParameters.PARAM_BACKUP; @@ -91,7 +91,7 @@ public void handle(Request request, Response response) throws Exception { reader = new InputStreamReader(backup, UTF_8); OrganizationDto organization = wsSupport.getOrganizationByKey(dbSession, organizationKey); - userSession.checkPermission(OrganizationPermission.ADMINISTER_QUALITY_PROFILES, organization); + userSession.checkPermission(ADMINISTER_QUALITY_PROFILES, organization); QProfileRestoreSummary summary = backuper.restore(dbSession, reader, organization, null); writeResponse(response.newJsonWriter(), organization, summary); diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/RestoreBuiltInAction.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/RestoreBuiltInAction.java index 05ea696751b3..37f5d3869e3f 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/RestoreBuiltInAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/RestoreBuiltInAction.java @@ -19,64 +19,26 @@ */ 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.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.organization.OrganizationDto; -import org.sonar.db.permission.OrganizationPermission; -import org.sonar.server.qualityprofile.QProfileReset; -import org.sonar.server.user.UserSession; - -import static org.sonar.server.util.LanguageParamUtils.getExampleValue; -import static org.sonar.server.util.LanguageParamUtils.getLanguageKeys; -import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_ORGANIZATION; +import org.sonar.server.ws.RemovedWebServiceHandler; public class RestoreBuiltInAction implements QProfileWsAction { - private final DbClient dbClient; - private final QProfileReset reset; - private final Languages languages; - private final UserSession userSession; - private final QProfileWsSupport qProfileWsSupport; - - public RestoreBuiltInAction(DbClient dbClient, QProfileReset reset, Languages languages, UserSession userSession, QProfileWsSupport qProfileWsSupport) { - this.dbClient = dbClient; - this.reset = reset; - this.languages = languages; - this.userSession = userSession; - this.qProfileWsSupport = qProfileWsSupport; - } - @Override public void define(WebService.NewController controller) { - WebService.NewAction action = controller.createAction("restore_built_in") - .setDescription("Restore built-in profiles from the definitions declared by plugins. " + - "Missing profiles are created, existing ones are updated.") + controller.createAction("restore_built_in") + .setDescription("This web service has no effect since 6.4. It's no more possible to restore built-in quality profiles because they are automatically " + + "updated and read only. Returns HTTP code 410.") .setSince("4.4") + .setDeprecatedSince("6.4") .setPost(true) .setHandler(this); - action.createParam("language") - .setDescription("Restore the built-in profiles defined for this language") - .setExampleValue(getExampleValue(languages)) - .setPossibleValues(getLanguageKeys(languages)) - .setRequired(true); - - QProfileWsSupport.createOrganizationParam(action).setSince("6.4"); } @Override - public void handle(Request request, Response response) { - userSession.checkLoggedIn(); - - try (DbSession dbSession = dbClient.openSession(false)) { - OrganizationDto organization = qProfileWsSupport.getOrganizationByKey(dbSession, request.param(PARAM_ORGANIZATION)); - userSession.checkPermission(OrganizationPermission.ADMINISTER_QUALITY_PROFILES, organization); - - reset.resetLanguage(dbSession, organization, request.mandatoryParam("language")); - } - response.noContent(); + public void handle(Request request, Response response) throws Exception { + RemovedWebServiceHandler.INSTANCE.handle(request, response); } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/SearchAction.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/SearchAction.java index 44339c5f9c73..bba002aa86e9 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/SearchAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/SearchAction.java @@ -89,29 +89,27 @@ public void define(WebService.NewController controller) { .setSince("6.4"); action - .createParam(PARAM_LANGUAGE) - .setDescription( - format("Language key. If provided, only profiles for the given language are returned. " + - "It should not be used with '%s', '%s or '%s' at the same time.", PARAM_DEFAULTS, PARAM_PROJECT_KEY, PARAM_PROFILE_NAME)) - .setPossibleValues(LanguageParamUtils.getLanguageKeys(languages)) - .setDeprecatedSince("6.4"); + .createParam(PARAM_DEFAULTS) + .setDescription(format("If set to true, return only the quality profile marked as default for each language, the '%s' parameter must not be set.", PARAM_PROJECT_KEY)) + .setDefaultValue(false) + .setBooleanPossibleValues(); action.createParam(PARAM_PROJECT_KEY) - .setDescription(format("Project or module key. If provided, '%s' and '%s' parameters should not be provided.", - PARAM_LANGUAGE, PARAM_DEFAULTS)) + .setDescription(format("Project or module key. If provided, the '%s' parameter should not be provided.", PARAM_DEFAULTS)) .setExampleValue("my-project-key"); action - .createParam(PARAM_DEFAULTS) - .setDescription(format("If set to true, return only the quality profile marked as default for each language, '%s' and '%s' parameters must not be set.", - PARAM_LANGUAGE, PARAM_PROJECT_KEY)) - .setDefaultValue(false) - .setBooleanPossibleValues(); + .createParam(PARAM_LANGUAGE) + .setDeprecatedSince("6.4") + .setDescription( + format("Language key. If provided, only profiles for the given language are returned. " + + "It should not be used with '%s', '%s or '%s' at the same time.", PARAM_DEFAULTS, PARAM_PROJECT_KEY, PARAM_PROFILE_NAME)) + .setPossibleValues(LanguageParamUtils.getLanguageKeys(languages)); action.createParam(PARAM_PROFILE_NAME) + .setDeprecatedSince("6.4") .setDescription(format("Profile name. It should be always used with the '%s' or '%s' parameter.", PARAM_PROJECT_KEY, PARAM_DEFAULTS)) - .setExampleValue("SonarQube Way") - .setDeprecatedSince("6.4"); + .setExampleValue("SonarQube Way"); } @Override diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileResetMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileResetMediumTest.java deleted file mode 100644 index 0c3d4bddbcf4..000000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileResetMediumTest.java +++ /dev/null @@ -1,240 +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 java.util.List; -import javax.annotation.Nullable; -import org.junit.After; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Rule; -import org.junit.Test; -import org.sonar.api.profiles.ProfileDefinition; -import org.sonar.api.profiles.RulesProfile; -import org.sonar.api.rule.RuleKey; -import org.sonar.api.rules.RuleParam; -import org.sonar.api.rules.RulePriority; -import org.sonar.api.server.rule.RuleParamType; -import org.sonar.api.server.rule.RulesDefinition; -import org.sonar.api.utils.ValidationMessages; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.db.organization.OrganizationDto; -import org.sonar.db.qualityprofile.ActiveRuleDao; -import org.sonar.db.qualityprofile.ActiveRuleDto; -import org.sonar.db.qualityprofile.ActiveRuleKey; -import org.sonar.db.qualityprofile.ActiveRuleParamDto; -import org.sonar.db.qualityprofile.QualityProfileDao; -import org.sonar.db.qualityprofile.RulesProfileDto; -import org.sonar.server.platform.Platform; -import org.sonar.server.tester.ServerTester; -import org.sonar.server.tester.UserSessionRule; - -import static com.google.common.collect.Lists.newArrayList; -import static org.assertj.core.api.Assertions.assertThat; -import static org.sonar.api.rule.Severity.BLOCKER; -import static org.sonar.api.rule.Severity.CRITICAL; -import static org.sonar.api.rule.Severity.MAJOR; -import static org.sonar.api.rule.Severity.MINOR; - -// TODO Replace ServerTester by EsTester and DbTester -public class QProfileResetMediumTest { - - static final XooRulesDefinition RULE_DEFS = new XooRulesDefinition(); - static final XooProfileDefinition PROFILE_DEFS = new XooProfileDefinition(); - - @ClassRule - public static ServerTester tester = new ServerTester() - .withEsIndexes() - .addXoo().addComponents(PROFILE_DEFS, RULE_DEFS); - - @Rule - public UserSessionRule userSessionRule = UserSessionRule.forServerTester(tester); - - private DbClient db; - private DbSession dbSession; - private QProfileReset reset; - private OrganizationDto defaultOrganization; - - @Before - public void before() { - tester.clearDbAndIndexes(); - db = tester.get(DbClient.class); - dbSession = db.openSession(false); - reset = tester.get(QProfileReset.class); - defaultOrganization = QProfileTesting.getDefaultOrganization(tester, db, dbSession); - } - - @After - public void after() { - dbSession.close(); - } - - private void register(@Nullable Rules rules, @Nullable RulesProfile profile) { - if (dbSession != null) { - dbSession.close(); - } - RULE_DEFS.set(rules); - PROFILE_DEFS.set(profile); - tester.get(Platform.class).restart(); - - db = tester.get(DbClient.class); - dbSession = tester.get(DbClient.class).openSession(false); - dbSession.clearCache(); - - reset = tester.get(QProfileReset.class); - } - - @Test - public void reset_language_profile() { - RulesProfile defProfile = RulesProfile.create("Basic", ServerTester.Xoo.KEY); - defProfile.activateRule( - org.sonar.api.rules.Rule.create("xoo", "x1").setParams(newArrayList(new RuleParam().setKey("acceptWhitespace"))), - RulePriority.CRITICAL).setParameter("acceptWhitespace", "true"); - - register(new Rules() { - @Override - public void init(RulesDefinition.NewRepository repository) { - RulesDefinition.NewRule x1 = repository.createRule("x1") - .setName("x1 name") - .setHtmlDescription("x1 desc") - .setSeverity(MINOR); - x1.createParam("acceptWhitespace") - .setDefaultValue("false") - .setType(RuleParamType.BOOLEAN) - .setDescription("Accept whitespaces on the line"); - } - }, - defProfile); - - RuleKey ruleKey = RuleKey.of("xoo", "x1"); - RulesProfileDto profile = tester.get(QualityProfileDao.class).selectByNameAndLanguage(defaultOrganization, "Basic", ServerTester.Xoo.KEY, dbSession); - ActiveRuleKey activeRuleKey = ActiveRuleKey.of(profile.getKee(), ruleKey); - - // Change the severity and the value of the parameter in the active rule - tester.get(RuleActivator.class).activate(dbSession, - new RuleActivation(ruleKey).setSeverity(BLOCKER) - .setParameter("acceptWhitespace", "false"), - profile.getKee()); - dbSession.commit(); - - // Verify severity and param has changed - ActiveRuleDto activeRuleDto = tester.get(ActiveRuleDao.class).selectOrFailByKey(dbSession, activeRuleKey); - assertThat(activeRuleDto.getSeverityString()).isEqualTo(BLOCKER); - List activeRuleParamDtos = tester.get(ActiveRuleDao.class).selectParamsByActiveRuleId(dbSession, activeRuleDto.getId()); - assertThat(activeRuleParamDtos.get(0).getKey()).isEqualTo("acceptWhitespace"); - assertThat(activeRuleParamDtos.get(0).getValue()).isEqualTo("false"); - - OrganizationDto organization = db.organizationDao().selectByUuid(dbSession, profile.getOrganizationUuid()).get(); - reset.resetLanguage(dbSession, organization, ServerTester.Xoo.KEY); - dbSession.commit(); - - // Severity and parameter value come back to origin after reset - activeRuleDto = tester.get(ActiveRuleDao.class).selectOrFailByKey(dbSession, activeRuleKey); - assertThat(activeRuleDto.getSeverityString()).isEqualTo(CRITICAL); - - activeRuleParamDtos = tester.get(ActiveRuleDao.class).selectParamsByActiveRuleId(dbSession, activeRuleDto.getId()); - assertThat(activeRuleParamDtos.get(0).getKey()).isEqualTo("acceptWhitespace"); - assertThat(activeRuleParamDtos.get(0).getValue()).isEqualTo("true"); - } - - @Test - public void reset_language_profile_param_when_rule_definition_has_changed() { - RulesProfile defProfile = RulesProfile.create("Basic", ServerTester.Xoo.KEY); - defProfile.activateRule(org.sonar.api.rules.Rule.create("xoo", "x1"), null); - - register(new Rules() { - @Override - public void init(RulesDefinition.NewRepository repository) { - RulesDefinition.NewRule x1 = repository.createRule("x1") - .setName("x1 name") - .setHtmlDescription("x1 desc") - .setSeverity(MAJOR); - x1.createParam("acceptWhitespace") - .setDefaultValue("false") - .setType(RuleParamType.BOOLEAN) - .setDescription("Accept whitespaces on the line"); - } - }, defProfile); - - RulesProfileDto profile = tester.get(QualityProfileDao.class).selectByNameAndLanguage(defaultOrganization, "Basic", ServerTester.Xoo.KEY, dbSession); - ActiveRuleKey activeRuleKey = ActiveRuleKey.of(profile.getKee(), RuleKey.of("xoo", "x1")); - - // Change param in the rule def - register(new Rules() { - @Override - public void init(RulesDefinition.NewRepository repository) { - RulesDefinition.NewRule x1 = repository.createRule("x1") - .setName("x1 name") - .setHtmlDescription("x1 desc") - .setSeverity(MAJOR); - x1.createParam("acceptWhitespace") - .setDefaultValue("true") - .setType(RuleParamType.BOOLEAN) - .setDescription("Accept whitespaces on the line"); - } - }, defProfile); - - OrganizationDto organization = db.organizationDao().selectByUuid(dbSession, profile.getOrganizationUuid()).get(); - reset.resetLanguage(dbSession, organization, ServerTester.Xoo.KEY); - - // Parameter value come back to origin after reset - ActiveRuleDto activeRuleDto = tester.get(ActiveRuleDao.class).selectOrFailByKey(dbSession, activeRuleKey); - List params = tester.get(ActiveRuleDao.class).selectParamsByActiveRuleId(dbSession, activeRuleDto.getId()); - assertThat(params).hasSize(1); - assertThat(params.get(0).getKey()).isEqualTo("acceptWhitespace"); - assertThat(params.get(0).getValue()).isEqualTo("true"); - } - - interface Rules { - void init(RulesDefinition.NewRepository repository); - } - - public static class XooRulesDefinition implements RulesDefinition { - private Rules rules = null; - - void set(@Nullable Rules rules) { - this.rules = rules; - } - - @Override - public void define(Context context) { - if (rules != null) { - RulesDefinition.NewRepository repository = context.createRepository("xoo", ServerTester.Xoo.KEY).setName("Xoo Repo"); - rules.init(repository); - repository.done(); - } - } - } - - public static class XooProfileDefinition extends ProfileDefinition { - private RulesProfile profile; - - void set(@Nullable RulesProfile profile) { - this.profile = profile; - } - - @Override - public RulesProfile createProfile(ValidationMessages validation) { - return profile; - } - } - -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ActivateRuleActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ActivateRuleActionTest.java index f291007af2bd..e672b00b8642 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ActivateRuleActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ActivateRuleActionTest.java @@ -36,6 +36,7 @@ import org.sonar.db.permission.OrganizationPermission; import org.sonar.db.qualityprofile.RulesProfileDto; import org.sonar.db.rule.RuleTesting; +import org.sonar.server.exceptions.BadRequestException; import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.exceptions.UnauthorizedException; import org.sonar.server.organization.TestDefaultOrganizationProvider; @@ -62,7 +63,7 @@ public class ActivateRuleActionTest { @Rule public UserSessionRule userSession = UserSessionRule.standalone(); @Rule - public ExpectedException thrown = ExpectedException.none(); + public ExpectedException expectedException = ExpectedException.none(); private DbClient dbClient = dbTester.getDbClient(); private RuleActivator ruleActivator = mock(RuleActivator.class); @@ -94,7 +95,7 @@ public void should_fail_if_not_logged_in() { .setParam("rule_key", RuleTesting.newRuleDto().getKey().toString()) .setParam("profile_key", randomAlphanumeric(UUID_SIZE)); - thrown.expect(UnauthorizedException.class); + expectedException.expect(UnauthorizedException.class); request.execute(); } @@ -107,7 +108,24 @@ public void should_fail_if_not_organization_quality_profile_administrator() { .setParam("rule_key", RuleTesting.newRuleDto().getKey().toString()) .setParam("profile_key", qualityProfile.getKee()); - thrown.expect(ForbiddenException.class); + expectedException.expect(ForbiddenException.class); + + request.execute(); + } + + @Test + public void fail_activate_if_built_in_profile() { + userSession.logIn().addPermission(OrganizationPermission.ADMINISTER_QUALITY_PROFILES, defaultOrganization); + + RulesProfileDto qualityProfile = dbTester.qualityProfiles().insert(defaultOrganization, profile -> profile.setIsBuiltIn(true).setName("Xoo profile").setLanguage("xoo")); + TestRequest request = wsActionTester.newRequest() + .setMethod("POST") + .setParam("rule_key", RuleTesting.newRuleDto().getKey().toString()) + .setParam("profile_key", qualityProfile.getKee()); + + expectedException.expect(BadRequestException.class); + expectedException.expectMessage("Operation forbidden for built-in Quality Profile 'Xoo profile' with language 'xoo'"); + request.execute(); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ActivateRulesActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ActivateRulesActionTest.java index ba85b4c51fe1..f12867f12c06 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ActivateRulesActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ActivateRulesActionTest.java @@ -29,6 +29,7 @@ import org.sonar.db.organization.OrganizationDto; import org.sonar.db.permission.OrganizationPermission; import org.sonar.db.qualityprofile.RulesProfileDto; +import org.sonar.server.exceptions.BadRequestException; import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.exceptions.UnauthorizedException; import org.sonar.server.organization.TestDefaultOrganizationProvider; @@ -106,6 +107,19 @@ public void should_fail_if_not_logged_in() { request.execute(); } + @Test + public void fail_if_built_in_profile() { + userSession.logIn().addPermission(OrganizationPermission.ADMINISTER_QUALITY_PROFILES, defaultOrganization); + RulesProfileDto qualityProfile = dbTester.qualityProfiles().insert(defaultOrganization, p -> p.setIsBuiltIn(true)); + TestRequest request = wsActionTester.newRequest() + .setMethod("POST") + .setParam("profile_key", qualityProfile.getKee()); + + thrown.expect(BadRequestException.class); + + request.execute(); + } + @Test public void should_fail_if_not_organization_quality_profile_administrator() { userSession.logIn().addPermission(OrganizationPermission.ADMINISTER_QUALITY_PROFILES, defaultOrganization); diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ChangeParentActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ChangeParentActionTest.java index aaf97b48ce5e..7cb6d5ce44ae 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ChangeParentActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ChangeParentActionTest.java @@ -40,13 +40,14 @@ import org.sonar.db.DbTester; import org.sonar.db.organization.OrganizationDto; import org.sonar.db.qualityprofile.ActiveRuleDto; -import org.sonar.db.qualityprofile.RulesProfileDto; import org.sonar.db.qualityprofile.QualityProfileTesting; +import org.sonar.db.qualityprofile.RulesProfileDto; import org.sonar.db.rule.RuleDefinitionDto; import org.sonar.db.rule.RuleTesting; import org.sonar.server.es.EsClient; import org.sonar.server.es.EsTester; import org.sonar.server.es.SearchOptions; +import org.sonar.server.exceptions.BadRequestException; import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.language.LanguageTesting; import org.sonar.server.organization.TestDefaultOrganizationProvider; @@ -325,6 +326,25 @@ public void remove_parent_with_empty_key() throws Exception { assertThat(ruleIndex.search(new RuleQuery().setActivation(true).setQProfileKey(child.getKee()), new SearchOptions()).getIds()).isEmpty(); } + @Test + public void fail_if_built_in_profile() { + RulesProfileDto child = dbTester.qualityProfiles().insert(organization, p -> p + .setLanguage(language.getKey()) + .setIsBuiltIn(true)); + + assertThat(dbClient.activeRuleDao().selectByProfileKey(dbSession, child.getKee())).isEmpty(); + assertThat(ruleIndex.search(new RuleQuery().setActivation(true).setQProfileKey(child.getKee()), new SearchOptions()).getIds()).isEmpty(); + + TestRequest request = wsActionTester.newRequest() + .setMethod("POST") + .setParam(PARAM_PROFILE_KEY, child.getKee()) + .setParam("parentKey", "palap"); + + thrown.expect(BadRequestException.class); + + request.execute(); + } + @Test public void fail_if_parent_key_and_name_both_set() throws Exception { RulesProfileDto child = createProfile(); diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/DeactivateRuleActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/DeactivateRuleActionTest.java index 9b86c8721e50..f4fb92d191aa 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/DeactivateRuleActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/DeactivateRuleActionTest.java @@ -36,6 +36,7 @@ import org.sonar.db.qualityprofile.ActiveRuleKey; import org.sonar.db.qualityprofile.RulesProfileDto; import org.sonar.db.rule.RuleTesting; +import org.sonar.server.exceptions.BadRequestException; import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.exceptions.UnauthorizedException; import org.sonar.server.organization.TestDefaultOrganizationProvider; @@ -106,6 +107,21 @@ public void should_fail_if_not_organization_quality_profile_administrator() { request.execute(); } + @Test + public void fail_deactivate_if_built_in_profile() { + userSession.logIn().addPermission(OrganizationPermission.ADMINISTER_QUALITY_PROFILES, defaultOrganization); + + RulesProfileDto qualityProfile = dbTester.qualityProfiles().insert(defaultOrganization, profile -> profile.setIsBuiltIn(true)); + TestRequest request = wsActionTester.newRequest() + .setMethod("POST") + .setParam("rule_key", RuleTesting.newRuleDto().getKey().toString()) + .setParam("profile_key", qualityProfile.getKee()); + + thrown.expect(BadRequestException.class); + + request.execute(); + } + @Test public void deactivate_rule_in_default_organization() { userSession.logIn().addPermission(OrganizationPermission.ADMINISTER_QUALITY_PROFILES, defaultOrganization); diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/DeactivateRulesActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/DeactivateRulesActionTest.java index 4ac08a7aadfd..667c612985ad 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/DeactivateRulesActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/DeactivateRulesActionTest.java @@ -29,6 +29,7 @@ import org.sonar.db.organization.OrganizationDto; import org.sonar.db.permission.OrganizationPermission; import org.sonar.db.qualityprofile.RulesProfileDto; +import org.sonar.server.exceptions.BadRequestException; import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.exceptions.UnauthorizedException; import org.sonar.server.organization.TestDefaultOrganizationProvider; @@ -91,8 +92,7 @@ public void define_bulk_deactivate_rule_action() { "available_since", "activation", "severities", - "organization" - ); + "organization"); } @Test @@ -105,6 +105,19 @@ public void should_fail_if_not_logged_in() { request.execute(); } + @Test + public void fail_if_built_in_profile() { + userSession.logIn().addPermission(OrganizationPermission.ADMINISTER_QUALITY_PROFILES, defaultOrganization); + RulesProfileDto qualityProfile = dbTester.qualityProfiles().insert(defaultOrganization, p -> p.setIsBuiltIn(true)); + TestRequest request = wsActionTester.newRequest() + .setMethod("POST") + .setParam("profile_key", qualityProfile.getKee()); + + thrown.expect(BadRequestException.class); + + request.execute(); + } + @Test public void should_fail_if_not_organization_quality_profile_administrator() { userSession.logIn().addPermission(OrganizationPermission.ADMINISTER_QUALITY_PROFILES, defaultOrganization); diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/DeleteActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/DeleteActionTest.java index d0ed9f98eab3..e2f93cd6666e 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/DeleteActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/DeleteActionTest.java @@ -32,6 +32,7 @@ import org.sonar.db.component.ComponentDto; import org.sonar.db.organization.OrganizationDto; import org.sonar.db.qualityprofile.RulesProfileDto; +import org.sonar.server.exceptions.BadRequestException; import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.exceptions.UnauthorizedException; @@ -131,6 +132,20 @@ public void delete_profile_by_language_and_name_in_specified_organization() { verifyProfileExists(profile2); } + @Test + public void fail_if_built_in_profile() { + OrganizationDto organization = dbTester.organizations().insert(); + RulesProfileDto profile1 = dbTester.qualityProfiles().insert(organization, p -> p.setIsBuiltIn(true)); + logInAsQProfileAdministrator(organization); + + expectedException.expect(BadRequestException.class); + + tester.newRequest() + .setMethod("POST") + .setParam("profileKey", profile1.getKee()) + .execute(); + } + @Test public void throw_ForbiddenException_if_not_profile_administrator() { OrganizationDto organization1 = dbTester.organizations().insert(); 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 7fc63c2e5a72..b5766f981725 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 @@ -69,7 +69,7 @@ public void setUp() { new DeleteAction(languages, null, null, userSessionRule, wsSupport), new ExportersAction(), new InheritanceAction(null, null, null, languages), - new RenameAction(dbClient, userSessionRule))).controller(QProfilesWs.API_ENDPOINT); + new RenameAction(dbClient, userSessionRule, wsSupport))).controller(QProfilesWs.API_ENDPOINT); } private ProfileImporter[] createImporters(Languages languages) { diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/RenameActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/RenameActionTest.java index a2326a71f344..442e974f7022 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/RenameActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/RenameActionTest.java @@ -66,7 +66,7 @@ public void setUp() { QProfileWsSupport wsSupport = new QProfileWsSupport(dbClient, userSessionRule, defaultOrganizationProvider); underTest = new RenameAction( dbClient, - userSessionRule); + userSessionRule, wsSupport); tester = new WsTester(new QProfilesWs( underTest)); organization = db.organizations().insert(); @@ -194,7 +194,7 @@ public void fail_if_profile_does_not_exist() throws Exception { logInAsQProfileAdministrator(); expectedException.expect(NotFoundException.class); - expectedException.expectMessage("Quality profile not found: polop"); + expectedException.expectMessage("Quality Profile with key 'polop' does not exist"); tester.newPostRequest("api/qualityprofiles", "rename") .setParam("key", "polop") @@ -202,6 +202,16 @@ public void fail_if_profile_does_not_exist() throws Exception { .execute(); } + @Test + public void fail_if_profile_is_built_in() { + logInAsQProfileAdministrator(); + String qualityProfileKey = db.qualityProfiles().insert(organization, p -> p.setIsBuiltIn(true)).getKee(); + + expectedException.expect(BadRequestException.class); + + underTest.doHandle("the new name", qualityProfileKey); + } + @Test public void allow_100_characters_as_name_and_not_more() throws Exception { logInAsQProfileAdministrator(); @@ -232,7 +242,7 @@ public void fail_renaming_if_profile_not_found() { logInAsQProfileAdministrator(); expectedException.expect(NotFoundException.class); - expectedException.expectMessage("Quality profile not found: unknown"); + expectedException.expectMessage("Quality Profile with key 'unknown' does not exist"); underTest.doHandle("the new name", "unknown"); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/RestoreBuiltInActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/RestoreBuiltInActionTest.java index 9dcd8772b040..e72672c2d2f6 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/RestoreBuiltInActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/RestoreBuiltInActionTest.java @@ -22,153 +22,40 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import org.mockito.ArgumentCaptor; -import org.sonar.api.resources.Languages; import org.sonar.api.server.ws.WebService; -import org.sonar.db.DbSession; -import org.sonar.db.DbTester; -import org.sonar.db.organization.OrganizationDto; -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.DefaultOrganizationProvider; -import org.sonar.server.organization.TestDefaultOrganizationProvider; -import org.sonar.server.qualityprofile.QProfileReset; -import org.sonar.server.tester.UserSessionRule; -import org.sonar.server.ws.TestResponse; +import org.sonar.server.exceptions.ServerException; import org.sonar.server.ws.WsActionTester; +import static java.net.HttpURLConnection.HTTP_GONE; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.sonar.db.permission.OrganizationPermission.ADMINISTER_QUALITY_PROFILES; +import static org.junit.Assert.fail; public class RestoreBuiltInActionTest { - @Rule - public DbTester db = DbTester.create(); - @Rule public ExpectedException expectedException = ExpectedException.none(); - @Rule - public UserSessionRule userSession = UserSessionRule.standalone(); - - private QProfileReset reset = mock(QProfileReset.class); - private Languages languages = LanguageTesting.newLanguages("xoo"); - private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(db); - private QProfileWsSupport wsSupport = new QProfileWsSupport(db.getDbClient(), userSession, defaultOrganizationProvider); - private RestoreBuiltInAction underTest = new RestoreBuiltInAction(db.getDbClient(), reset, languages, userSession, wsSupport); - private WsActionTester tester = new WsActionTester(underTest); + private RestoreBuiltInAction underTest = new RestoreBuiltInAction(); + private WsActionTester ws = new WsActionTester(underTest); @Test public void test_definition() { - WebService.Action action = tester.getDef(); + WebService.Action action = ws.getDef(); assertThat(action.key()).isEqualTo("restore_built_in"); assertThat(action.isPost()).isTrue(); assertThat(action.responseExampleAsString()).isNull(); + assertThat(action.deprecatedSince()).isEqualTo("6.4"); - // parameters - assertThat(action.params()).hasSize(2); - WebService.Param languageParam = action.param("language"); - assertThat(languageParam.isRequired()).isTrue(); - assertThat(languageParam.since()).isNull();//introduced at the same time than the web service - - WebService.Param organizationParam = action.param("organization"); - assertThat(organizationParam.isRequired()).isFalse(); - assertThat(organizationParam.since()).isEqualTo("6.4"); + assertThat(action.params()).isEmpty(); } @Test - public void restore_built_in_profiles_on_default_organization() { - OrganizationDto organization = db.getDefaultOrganization(); - logInAsQProfileAdministrator(organization); - TestResponse response = tester.newRequest().setParam("language", "xoo").execute(); - - ArgumentCaptor organizationArgument = ArgumentCaptor.forClass(OrganizationDto.class); - verify(reset).resetLanguage(any(DbSession.class), organizationArgument.capture(), eq("xoo")); - assertThat(organizationArgument.getValue().getUuid()).isEqualTo(organization.getUuid()); - assertThat(response.getStatus()).isEqualTo(204); - } - - @Test - public void restore_built_in_profiles_on_specified_organization() { - OrganizationDto organization = db.organizations().insert(); - logInAsQProfileAdministrator(organization); - TestResponse response = tester.newRequest() - .setParam("language", "xoo") - .setParam("organization", organization.getKey()) - .execute(); - - ArgumentCaptor organizationArgument = ArgumentCaptor.forClass(OrganizationDto.class); - verify(reset).resetLanguage(any(DbSession.class), organizationArgument.capture(), eq("xoo")); - assertThat(organizationArgument.getValue().getUuid()).isEqualTo(organization.getUuid()); - assertThat(response.getStatus()).isEqualTo(204); - } - - @Test - public void throw_IAE_if_language_does_not_exist() throws Exception { - logInAsQProfileAdministrator(db.getDefaultOrganization()); - - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Value of parameter 'language' (unknown) must be one of: [xoo]"); - - tester.newRequest().setParam("language", "unknown").execute(); - } - - @Test - public void throw_NotFoundException_if_organization_does_not_exist() throws Exception { - userSession.logIn(); - - expectedException.expect(NotFoundException.class); - expectedException.expectMessage("No organization with key 'does_not_exist'"); - - tester.newRequest() - .setParam("language", "unknown") - .setParam("organization", "does_not_exist") - .execute(); - } - - @Test - public void throw_ForbiddenException_if_not_profile_administrator_of_default_organization() throws Exception { - userSession.logIn(); - - expectedException.expect(ForbiddenException.class); - expectedException.expectMessage("Insufficient privileges"); - - tester.newRequest().setParam("language", "xoo").execute(); - } - - @Test - public void throw_ForbiddenException_if_not_profile_administrator_of_specified_organization() throws Exception { - OrganizationDto org = db.organizations().insert(); - userSession.logIn().addPermission(ADMINISTER_QUALITY_PROFILES, db.getDefaultOrganization()); - - expectedException.expect(ForbiddenException.class); - expectedException.expectMessage("Insufficient privileges"); - - tester.newRequest() - .setParam("language", "xoo") - .setParam("organization", org.getKey()) - .execute(); - } - - @Test - public void throw_UnauthorizedException_if_not_logged_in() throws Exception { - userSession.anonymous(); - - expectedException.expect(UnauthorizedException.class); - expectedException.expectMessage("Authentication is required"); - - tester.newRequest().setParam("language", "xoo").execute(); - } - - private void logInAsQProfileAdministrator(OrganizationDto organization) { - userSession - .logIn() - .addPermission(ADMINISTER_QUALITY_PROFILES, organization.getUuid()); + public void fail_when_ws_is_called() { + try { + ws.newRequest().execute(); + fail(); + } catch (ServerException e) { + assertThat(e.httpCode()).isEqualTo(HTTP_GONE); + } } } 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 20790befbfde..5ecb400568a2 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 @@ -40,8 +40,8 @@ import org.sonar.db.organization.OrganizationTesting; import org.sonar.db.qualityprofile.QualityProfileDao; import org.sonar.db.qualityprofile.QualityProfileDbTester; -import org.sonar.db.qualityprofile.RulesProfileDto; import org.sonar.db.qualityprofile.QualityProfileTesting; +import org.sonar.db.qualityprofile.RulesProfileDto; import org.sonar.db.rule.RuleDefinitionDto; import org.sonar.server.exceptions.BadRequestException; import org.sonar.server.language.LanguageTesting; @@ -106,20 +106,35 @@ public void setUp() { } @Test - public void define_search() { - WebService.Action search = ws.getDef(); - assertThat(search).isNotNull(); - assertThat(search.isPost()).isFalse(); - assertThat(search.param("language").possibleValues()).containsExactly("xoo1", "xoo2"); - assertThat(search.param("language").deprecatedSince()).isEqualTo("6.4"); - assertThat(search.param("profileName").deprecatedSince()).isEqualTo("6.4"); - assertThat(search.param("projectKey")).isNotNull(); - assertThat(search.param("defaults")).isNotNull(); - assertThat(search.param("organization")).isNotNull(); - assertThat(search.param("organization").isRequired()).isFalse(); - assertThat(search.param("organization").isInternal()).isTrue(); - assertThat(search.param("organization").description()).isNotEmpty(); - assertThat(search.param("organization").since()).isEqualTo("6.4"); + public void definition() { + WebService.Action action = ws.getDef(); + assertThat(action.key()).isEqualTo("search"); + assertThat(action.responseExampleAsString()).isNotEmpty(); + assertThat(action.isPost()).isFalse(); + + WebService.Param organization = action.param("organization"); + assertThat(organization).isNotNull(); + assertThat(organization.isRequired()).isFalse(); + assertThat(organization.isInternal()).isTrue(); + assertThat(organization.description()).isNotEmpty(); + assertThat(organization.since()).isEqualTo("6.4"); + + WebService.Param defaults = action.param("defaults"); + assertThat(defaults.description()).isEqualTo("If set to true, return only the quality profile marked as default for each language, " + + "the 'projectKey' parameter must not be set."); + + WebService.Param projectKey = action.param("projectKey"); + assertThat(projectKey.description()).isEqualTo("Project or module key. If provided, the 'defaults' parameter should not be provided."); + + WebService.Param language = action.param("language"); + assertThat(language.possibleValues()).containsExactly("xoo1", "xoo2"); + assertThat(language.deprecatedSince()).isEqualTo("6.4"); + assertThat(language.description()).isEqualTo("Language key. If provided, only profiles for the given language are returned. " + + "It should not be used with 'defaults', 'projectKey or 'profileName' at the same time."); + + WebService.Param profileName = action.param("profileName"); + assertThat(profileName.deprecatedSince()).isEqualTo("6.4"); + assertThat(profileName.description()).isEqualTo("Profile name. It should be always used with the 'projectKey' or 'defaults' parameter."); } @Test