@@ -207,9 +207,8 @@ public class IssuesModeTest { | |||
// 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"); | |||
@@ -152,9 +152,7 @@ public class OrganizationQualityProfilesPageTest { | |||
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) { |
@@ -134,9 +134,7 @@ public class QualityProfilesPageTest { | |||
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) { |
@@ -1,95 +0,0 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> | |||
<head profile="http://selenium-ide.openqa.org/profiles/test-case"> | |||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> | |||
<link rel="selenium.base" href="http://localhost:49506"/> | |||
<title>should_create</title> | |||
</head> | |||
<body> | |||
<table cellpadding="1" cellspacing="1" border="1"> | |||
<thead> | |||
<tr> | |||
<td rowspan="1" colspan="3">should_create</td> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
<tr> | |||
<td>open</td> | |||
<td>/sessions/logout</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>open</td> | |||
<td>/sessions/login</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>id=password</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>id=login</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>clickAndWait</td> | |||
<td>name=commit</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForElementPresent</td> | |||
<td>css=.js-user-authenticated</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>open</td> | |||
<td>/organizations/test-org/quality_profiles</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForElementPresent</td> | |||
<td>css=.quality-profiles-table-row[data-name="sample"]</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>assertElementNotPresent</td> | |||
<td>css=.quality-profiles-table-row[data-name="empty"]</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>click</td> | |||
<td>css=.js-more-admin-actions</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>click</td> | |||
<td>css=#quality-profiles-restore-built-in</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>click</td> | |||
<td>css=#restore-built-in-profiles-submit</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForElementPresent</td> | |||
<td>css=#restore-built-in-profiles-form .alert-success</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>click</td> | |||
<td>css=.js-modal-close</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForElementPresent</td> | |||
<td>css=.quality-profiles-table-row[data-name="empty"]</td> | |||
<td></td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
</body> | |||
</html> |
@@ -1,95 +0,0 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> | |||
<head profile="http://selenium-ide.openqa.org/profiles/test-case"> | |||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> | |||
<link rel="selenium.base" href="http://localhost:49506"/> | |||
<title>should_create</title> | |||
</head> | |||
<body> | |||
<table cellpadding="1" cellspacing="1" border="1"> | |||
<thead> | |||
<tr> | |||
<td rowspan="1" colspan="3">should_create</td> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
<tr> | |||
<td>open</td> | |||
<td>/sessions/logout</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>open</td> | |||
<td>/sessions/login</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>id=password</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>type</td> | |||
<td>id=login</td> | |||
<td>admin</td> | |||
</tr> | |||
<tr> | |||
<td>clickAndWait</td> | |||
<td>name=commit</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForElementPresent</td> | |||
<td>css=.js-user-authenticated</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>open</td> | |||
<td>/profiles</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForElementPresent</td> | |||
<td>css=.quality-profiles-table-row[data-name="sample"]</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>assertElementNotPresent</td> | |||
<td>css=.quality-profiles-table-row[data-name="empty"]</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>click</td> | |||
<td>css=.js-more-admin-actions</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>click</td> | |||
<td>css=#quality-profiles-restore-built-in</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>click</td> | |||
<td>css=#restore-built-in-profiles-submit</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForElementPresent</td> | |||
<td>css=#restore-built-in-profiles-form .alert-success</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>click</td> | |||
<td>css=.js-modal-close</td> | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>waitForElementPresent</td> | |||
<td>css=.quality-profiles-table-row[data-name="empty"]</td> | |||
<td></td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
</body> | |||
</html> |
@@ -34,6 +34,7 @@ import org.sonar.db.qualityprofile.RulesProfileDto; | |||
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 class QProfileFactory { | |||
// ------------- 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 class QProfileFactory { | |||
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"); |
@@ -21,15 +21,9 @@ package org.sonar.server.qualityprofile; | |||
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. |
@@ -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<RuleActivation> 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<RuleActivation> 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<RuleKey> ruleToBeDeactivated = Sets.newHashSet(); | |||
// Keep reference to all the activated rules before backup restore |
@@ -30,6 +30,7 @@ import org.sonar.api.utils.KeyValueFormat; | |||
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 class ActivateRuleAction implements QProfileWsAction { | |||
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<ActiveRuleChange> changes = ruleActivator.activate(dbSession, activation, profileKey); | |||
dbSession.commit(); | |||
activeRuleIndexer.index(changes); |
@@ -26,11 +26,13 @@ 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.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 class ActivateRulesAction implements QProfileWsAction { | |||
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); |
@@ -90,6 +90,7 @@ public class ChangeParentAction implements QProfileWsAction { | |||
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); |
@@ -28,6 +28,7 @@ import org.sonar.core.util.Uuids; | |||
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 class DeactivateRuleAction implements QProfileWsAction { | |||
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); | |||
} |
@@ -25,6 +25,7 @@ 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.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 class DeactivateRulesAction implements QProfileWsAction { | |||
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); |
@@ -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 class DeleteAction implements QProfileWsAction { | |||
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<RulesProfileDto> descendants = selectDescendants(dbSession, profile); | |||
ensureNoneIsMarkedAsDefault(dbSession, profile, descendants); |
@@ -35,6 +35,7 @@ import org.sonar.server.ws.WsUtils; | |||
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 class QProfileWsSupport { | |||
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 class QProfileWsSupport { | |||
"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 class QProfileWsSupport { | |||
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()); | |||
} | |||
} |
@@ -32,7 +32,6 @@ import org.sonar.db.DbSession; | |||
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 @@ public class RenameAction implements QProfileWsAction { | |||
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) |
@@ -31,7 +31,6 @@ import org.sonar.api.utils.text.JsonWriter; | |||
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 org.sonar.server.user.UserSession; | |||
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 class RestoreAction implements QProfileWsAction { | |||
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); |
@@ -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); | |||
} | |||
} |
@@ -89,29 +89,27 @@ public class SearchAction implements QProfileWsAction { | |||
.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 |
@@ -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<ActiveRuleParamDto> 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<ActiveRuleParamDto> 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; | |||
} | |||
} | |||
} |
@@ -36,6 +36,7 @@ import org.sonar.db.organization.OrganizationDto; | |||
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 class ActivateRuleActionTest { | |||
.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 class ActivateRuleActionTest { | |||
.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(); | |||
} | |||
@@ -29,6 +29,7 @@ import org.sonar.db.DbTester; | |||
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 class ActivateRulesActionTest { | |||
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); |
@@ -40,13 +40,14 @@ import org.sonar.db.DbSession; | |||
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 class ChangeParentActionTest { | |||
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(); |
@@ -36,6 +36,7 @@ import org.sonar.db.permission.OrganizationPermission; | |||
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 class DeactivateRuleActionTest { | |||
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); |
@@ -29,6 +29,7 @@ import org.sonar.db.DbTester; | |||
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 class DeactivateRulesActionTest { | |||
"available_since", | |||
"activation", | |||
"severities", | |||
"organization" | |||
); | |||
"organization"); | |||
} | |||
@Test | |||
@@ -105,6 +105,19 @@ public class DeactivateRulesActionTest { | |||
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); |
@@ -32,6 +32,7 @@ import org.sonar.db.DbTester; | |||
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 class DeleteActionTest { | |||
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(); |
@@ -69,7 +69,7 @@ public class QProfilesWsTest { | |||
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) { |
@@ -66,7 +66,7 @@ public class RenameActionTest { | |||
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 class RenameActionTest { | |||
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 class RenameActionTest { | |||
.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 class RenameActionTest { | |||
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"); | |||
} |
@@ -22,153 +22,40 @@ package org.sonar.server.qualityprofile.ws; | |||
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<OrganizationDto> 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<OrganizationDto> 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); | |||
} | |||
} | |||
} |
@@ -40,8 +40,8 @@ import org.sonar.db.organization.OrganizationDto; | |||
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 class SearchActionTest { | |||
} | |||
@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 |