import org.apache.commons.lang.StringUtils;
import org.sonar.api.database.DatabaseSession;
import org.sonar.api.profiles.RulesProfile;
-import org.sonar.api.rules.*;
+import org.sonar.api.rules.ActiveRule;
+import org.sonar.api.rules.ActiveRuleChange;
+import org.sonar.api.rules.Rule;
+import org.sonar.api.rules.RuleParam;
+import org.sonar.api.rules.RulePriority;
import org.sonar.core.preview.PreviewCache;
import org.sonar.jpa.dao.BaseDao;
-import org.sonar.api.rules.ActiveRuleChange;
-import org.sonar.jpa.dao.RulesDao;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import java.util.List;
-import org.sonar.api.rules.ActiveRule;
/**
* @deprecated to be dropped in 4.4
@Deprecated
public class ProfilesManager extends BaseDao {
- private RulesDao rulesDao;
private PreviewCache dryRunCache;
- public ProfilesManager(DatabaseSession session, RulesDao rulesDao, PreviewCache dryRunCache) {
- super(session);
- this.rulesDao = rulesDao;
- this.dryRunCache = dryRunCache;
- }
-
public ProfilesManager(DatabaseSession session, PreviewCache dryRunCache) {
super(session);
this.dryRunCache = dryRunCache;
}
- public int copyProfile(int profileId, String newProfileName) {
- RulesProfile profile = getSession().getSingleResult(RulesProfile.class, "id", profileId);
- RulesProfile toImport = (RulesProfile) profile.clone();
- toImport.setName(newProfileName);
- ProfilesBackup pb = new ProfilesBackup(getSession(), dryRunCache);
- pb.importProfile(rulesDao, toImport);
- getSession().commit();
- dryRunCache.reportGlobalModification();
- return toImport.getId();
- }
-
// Managing inheritance of profiles
public RuleInheritanceActions profileParentChanged(Integer profileId, @Nullable String parentName, String userName) {
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
+import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.codehaus.staxmate.SMInputFactory;
import org.codehaus.staxmate.in.SMHierarchicCursor;
import org.sonar.server.qualityprofile.index.ActiveRuleIndex;
import org.sonar.server.search.IndexClient;
+import javax.annotation.Nullable;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import java.io.Reader;
xml.end("profile").close();
}
- public void restore(Reader reader) {
+ /**
+ *
+ * @param reader the XML backup
+ * @param profileKey the target profile. If <code>null</code>, then use the
+ * key declared in the backup
+ */
+ public void restore(Reader reader, @Nullable QualityProfileKey profileKey) {
try {
String profileLang = null, profileName = null;
SMInputFactory inputFactory = initStax();
profileLang = StringUtils.trim(cursor.collectDescendantText(false));
} else if (StringUtils.equals("rules", nodeName)) {
- QualityProfileKey profileKey = QualityProfileKey.of(profileName, profileLang);
+ QualityProfileKey targetKey = (QualityProfileKey)ObjectUtils.defaultIfNull(
+ profileKey, QualityProfileKey.of(profileName, profileLang));
SMInputCursor rulesCursor = cursor.childElementCursor("rule");
- doRestore(rulesCursor, profileKey);
+ doRestore(rulesCursor, targetKey);
}
}
} catch (XMLStreamException e) {
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.qualityprofile;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.ServerComponent;
+import org.sonar.api.utils.TempFolder;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.qualityprofile.db.QualityProfileDto;
+import org.sonar.core.qualityprofile.db.QualityProfileKey;
+import org.sonar.server.db.DbClient;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.Writer;
+
+public class QProfileCopier implements ServerComponent {
+
+ private final DbClient db;
+ private final QProfileBackuper backuper;
+ private final TempFolder temp;
+
+ public QProfileCopier(DbClient db, QProfileBackuper backuper, TempFolder temp) {
+ this.db = db;
+ this.backuper = backuper;
+ this.temp = temp;
+ }
+
+ void copy(QualityProfileKey from, QualityProfileKey to) {
+ verifyKeys(from, to);
+ prepareProfiles(from, to);
+ File backupFile = temp.newFile();
+ backup(from, backupFile);
+ restore(backupFile, to);
+ FileUtils.deleteQuietly(backupFile);
+ }
+
+ private void verifyKeys(QualityProfileKey from, QualityProfileKey to) {
+ if (from.equals(to)) {
+ throw new IllegalArgumentException(String.format(
+ "Source and target profiles are equal: %s", from));
+ }
+ if (!StringUtils.equals(from.lang(), to.lang())) {
+ throw new IllegalArgumentException(String.format(
+ "Source and target profiles do not have the same language: %s and %s", from, to));
+ }
+ }
+
+ private void prepareProfiles(QualityProfileKey from, QualityProfileKey to) {
+ DbSession dbSession = db.openSession(false);
+ try {
+ QualityProfileDto fromProfile = db.qualityProfileDao().getByKey(from, dbSession);
+ if (fromProfile == null) {
+ throw new IllegalArgumentException("Quality profile does not exist: " + from);
+ }
+ QualityProfileDto toProfile = db.qualityProfileDao().getByKey(to, dbSession);
+ if (toProfile == null) {
+ // Do not delegate creation to QualityProfileBackuper because we need to keep
+ // the parent-child association, if exists.
+ toProfile = QualityProfileDto.createFor(to).setParent(fromProfile.getParent());
+ db.qualityProfileDao().insert(dbSession, toProfile);
+ }
+ dbSession.commit();
+
+ } finally {
+ dbSession.close();
+ }
+ }
+
+ private void backup(QualityProfileKey from, File backupFile) {
+ Writer writer = null;
+ try {
+ writer = new OutputStreamWriter(FileUtils.openOutputStream(backupFile));
+ backuper.backup(from, writer);
+ } catch (IOException e) {
+ throw new IllegalStateException("Fail to open temporary backup file: " + backupFile, e);
+ } finally {
+ IOUtils.closeQuietly(writer);
+ }
+ }
+
+ private void restore(File backupFile, QualityProfileKey to) {
+ Reader reader = null;
+ try {
+ reader = new InputStreamReader(FileUtils.openInputStream(backupFile));
+ backuper.restore(reader, to);
+ } catch (IOException e) {
+ throw new IllegalStateException("Fail to create temporary backup file: " + backupFile, e);
+ } finally {
+ IOUtils.closeQuietly(reader);
+ }
+ }
+}
}
}
- public void copyProfile(int profileId, String copyProfileName, UserSession userSession) {
- checkPermission(userSession);
- DbSession session = myBatis.openSession(false);
- try {
- QualityProfileDto profileDto = findNotNull(profileId, session);
- checkNotAlreadyExists(copyProfileName, profileDto.getLanguage(), session);
- int copyProfileId = profilesManager.copyProfile(profileId, copyProfileName);
-
- // Cannot reuse same session as hibernate as create active rules in another session
-// esActiveRule.bulkIndexProfile(copyProfileId);
- } finally {
- MyBatis.closeQuietly(session);
- }
- }
-
@VisibleForTesting
boolean isCycle(QualityProfileDto childProfile, @Nullable QualityProfileDto parentProfile, DbSession session) {
QualityProfileDto currentParent = parentProfile;
private final IndexClient index;
private final RuleActivator ruleActivator;
private final QProfileBackuper backuper;
+ private final QProfileCopier copier;
- public QProfileService(IndexClient index, RuleActivator ruleActivator, QProfileBackuper backuper) {
+ public QProfileService(IndexClient index, RuleActivator ruleActivator, QProfileBackuper backuper,
+ QProfileCopier copier) {
this.index = index;
this.ruleActivator = ruleActivator;
this.backuper = backuper;
+ this.copier = copier;
}
@CheckForNull
public void restore(Reader backup) {
verifyAdminPermission();
- backuper.restore(backup);
+ backuper.restore(backup, null);
}
/**
verifyAdminPermission();
}
- public void copy(QualityProfileKey key, String newName) {
- // TODO
+ public void copy(QualityProfileKey from, QualityProfileKey to) {
verifyAdminPermission();
+ copier.copy(from, to);
}
public void delete(QualityProfileKey key) {
operations.setDefaultProfile(profileId, UserSession.get());
}
- public void copyProfile(int profileId, String copyProfileName) {
- checkProfileNameParam(copyProfileName);
- operations.copyProfile(profileId, copyProfileName, UserSession.get());
- }
-
@CheckForNull
public QProfile parent(QProfile profile) {
return profileLookup.parent(profile);
return this.cascade;
}
- public RuleActivation isCascade(boolean cascade){
- this.cascade = cascade;
+ public RuleActivation isCascade(boolean b){
+ this.cascade = b;
return this;
}
// 3. else defined by rule defaults
change.setSeverity(StringUtils.defaultIfEmpty(activation.getSeverity(), context.defaultSeverity()));
for (RuleParamDto ruleParamDto : context.ruleParams()) {
-
String value = StringUtils.defaultIfEmpty(
activation.getParameters().get(ruleParamDto.getName()),
context.defaultParam(ruleParamDto.getName()));
action.createParam("name")
.setDescription("Profile name. If not set, the default profile for the selected language is used")
.setExampleValue("Sonar way");
+ RailsHandler.addFormatParam(action);
}
private void defineRestoreAction(NewController controller) {
action.createParam("backup")
.setRequired(true)
.setDescription("Path to the file containing the backup (HTML format)");
+ RailsHandler.addJsonOnlyFormatParam(action);
}
private void defineDestroyAction(NewController controller) {
call_backend do
@profiles = Internal.quality_profiles.allProfiles().to_a
end
- Api::Utils.insensitive_sort!(@profiles){|profile| profile.name()}
+ Api::Utils.insensitive_sort!(@profiles) { |profile| profile.name() }
end
# GET /profiles/create_form?language=<language>
call_backend do
@default_profile_names = Internal.profile_backup.findDefaultProfileNamesByLanguage(@language.getKey()).to_a
profiles = Internal.quality_profiles.profilesByLanguage(@language.getKey()).to_a
- @existing_default_profiles = profiles.select{|p| @default_profile_names.find{|default_profile| default_profile == p.name()}}.collect{|p| p.name()}
+ @existing_default_profiles = profiles.select { |p| @default_profile_names.find { |default_profile| default_profile == p.name() } }.collect { |p| p.name() }
end
render :partial => 'profiles/recreate_built_in_form'
end
verify_ajax_request
require_parameters 'id'
- profile_id = params[:id].to_i
- name = params['name']
+ source_key=profile_id_to_key(params[:id].to_i)
+ target_name = params['name']
+ target_key=Java::OrgSonarCoreQualityprofileDb::QualityProfileKey.of(target_name, source_key.lang())
+
call_backend do
- @profile = Internal.quality_profiles.copyProfile(profile_id, name)
- flash[:notice]= message('quality_profiles.profile_x_not_activated', :params => name)
+ Internal.component(Java::OrgSonarServerQualityprofile::QProfileService.java_class).copy(source_key, target_key)
+ flash[:notice]= message('quality_profiles.profile_x_not_activated', :params => target_name)
render :text => 'ok', :status => 200
end
end
profile_key=profile_id_to_key(params[:id].to_i)
- xml = Internal.component(Java::OrgSonarServerQualityprofile::QProfileService.java_class).backup(profile_key)
- filename = profile_key.toString().gsub(' ', '_')
- send_data(xml, :type => 'text/xml', :disposition => "attachment; filename=#{filename}.xml")
+ call_backend do
+ xml = Internal.component(Java::OrgSonarServerQualityprofile::QProfileService.java_class).backup(profile_key)
+ filename = profile_key.toString().gsub(' ', '_')
+ send_data(xml, :type => 'text/xml', :disposition => "attachment; filename=#{filename}.xml")
+ end
end
@parent = Internal.quality_profiles.parent(@profile) if @profile.parent
@ancestors = Internal.quality_profiles.ancestors(@profile).to_a
@children = Internal.quality_profiles.children(@profile).to_a
- profiles = Internal.quality_profiles.profilesByLanguage(@profile.language()).to_a.reject{|p| p.id == @profile.id() || p.parent() == @profile.name()}
- profiles = Api::Utils.insensitive_sort(profiles) { |p| p.name()}
+ profiles = Internal.quality_profiles.profilesByLanguage(@profile.language()).to_a.reject { |p| p.id == @profile.id() || p.parent() == @profile.name() }
+ profiles = Api::Utils.insensitive_sort(profiles) { |p| p.name() }
@select_parent = [[message('none'), nil]] + profiles.collect { |profile| [profile.name(), profile.id()] }
end
versions = ActiveRuleChange.all(:select => 'profile_version, MAX(change_date) AS change_date', :conditions => ['profile_id=?', @profile.id], :group => 'profile_version')
# Add false change version 1 when no change have been made in profile version 1
- versions << ActiveRuleChange.new(:profile_version => 1, :profile_id => @profile.id) unless versions.find {|version| version.profile_version == 1}
+ versions << ActiveRuleChange.new(:profile_version => 1, :profile_id => @profile.id) unless versions.find { |version| version.profile_version == 1 }
versions.sort! { |a, b| b.profile_version <=> a.profile_version }
# SONAR-2986
@profile2 = Profile.find(params[:id2])
arules1 = ActiveRule.all(:include => [{:active_rule_parameters => :rules_parameter}, :rule],
- :conditions => ['active_rules.profile_id=?', @profile1.id])
+ :conditions => ['active_rules.profile_id=?', @profile1.id])
arules2 = ActiveRule.all(:order => 'rules.plugin_name, rules.plugin_rule_key', :include => [{:active_rule_parameters => :rules_parameter}, :rule],
- :conditions => ['active_rules.profile_id=?', @profile2.id])
+ :conditions => ['active_rules.profile_id=?', @profile2.id])
arules1.reject! { |arule| arule.rule.removed? }
arules2.reject! { |arule| arule.rule.removed? }
def status
@status ||=
- begin
- if @arule1.nil?
- @status=(@arule2 ? DIFF_IN2 : nil)
- else
- if @arule2
- # compare severity and parameters
- @removed_params=[]
- @added_params=[]
- @rule.parameters.each do |param|
- v1=@arule1.value(param.id)
- v2=@arule2.value(param.id)
- if v1
- if v2
- if v1!=v2
+ begin
+ if @arule1.nil?
+ @status=(@arule2 ? DIFF_IN2 : nil)
+ else
+ if @arule2
+ # compare severity and parameters
+ @removed_params=[]
+ @added_params=[]
+ @rule.parameters.each do |param|
+ v1=@arule1.value(param.id)
+ v2=@arule2.value(param.id)
+ if v1
+ if v2
+ if v1!=v2
+ @removed_params<<@arule1.parameter(param.name)
+ @added_params<<@arule2.parameter(param.name)
+ end
+ else
@removed_params<<@arule1.parameter(param.name)
- @added_params<<@arule2.parameter(param.name)
end
- else
- @removed_params<<@arule1.parameter(param.name)
+ elsif v2
+ @added_params<<@arule2.parameter(param.name)
end
- elsif v2
- @added_params<<@arule2.parameter(param.name)
end
+ diff=(@arule1.priority!=@arule2.priority) || !@removed_params.empty? || !@added_params.empty?
+ @status=(diff ? DIFF_MODIFIED : DIFF_SAME)
+ else
+ @status=DIFF_IN1
end
- diff=(@arule1.priority!=@arule2.priority) || !@removed_params.empty? || !@added_params.empty?
- @status=(diff ? DIFF_MODIFIED : DIFF_SAME)
- else
- @status=DIFF_IN1
end
end
- end
end
def <=>(other)
added = added +1
else
rule = active_rule1.rule # = active_rule2.rule
- #compare severity
+ #compare severity
diff = true if active_rule1.priority != active_rule2.priority
- #compare parameters
+ #compare parameters
rule.parameters.each do |param|
diff = true if active_rule1.value(param.id) != active_rule2.value(param.id)
end
@Before
public void setUp() {
- profilesManager = new ProfilesManager(getSession(), null, mock(PreviewCache.class));
+ profilesManager = new ProfilesManager(getSession(), mock(PreviewCache.class));
}
@Test
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.qualityprofile;
-
-import org.junit.Before;
-import org.sonar.core.preview.PreviewCache;
-import org.sonar.jpa.test.AbstractDbUnitTestCase;
-
-import static org.mockito.Mockito.mock;
-
-public class ProfilesManagerTest extends AbstractDbUnitTestCase {
-
- private ProfilesManager manager;
-
- @Before
- public void before() {
- manager = new ProfilesManager(getSession(), null, mock(PreviewCache.class));
- }
-
-}
@Test
public void restore_and_create_profile() throws Exception {
tester.get(QProfileBackuper.class).restore(new StringReader(
- Resources.toString(getClass().getResource("QProfileBackuperMediumTest/restore.xml"), Charsets.UTF_8)));
+ Resources.toString(getClass().getResource("QProfileBackuperMediumTest/restore.xml"), Charsets.UTF_8)),
+ null);
List<ActiveRule> activeRules = tester.get(QProfileService.class).findActiveRulesByProfile(XOO_PROFILE_KEY);
assertThat(activeRules).hasSize(1);
// restore backup, which activates only x1
// -> update x1 and deactivate x2
tester.get(QProfileBackuper.class).restore(new StringReader(
- Resources.toString(getClass().getResource("QProfileBackuperMediumTest/restore.xml"), Charsets.UTF_8)));
+ Resources.toString(getClass().getResource("QProfileBackuperMediumTest/restore.xml"), Charsets.UTF_8)), null);
List<ActiveRule> activeRules = tester.get(QProfileService.class).findActiveRulesByProfile(XOO_PROFILE_KEY);
// restore backup of child profile -> overrides x1
tester.get(QProfileBackuper.class).restore(new StringReader(
- Resources.toString(getClass().getResource("QProfileBackuperMediumTest/restore-child.xml"), Charsets.UTF_8)));
+ Resources.toString(getClass().getResource("QProfileBackuperMediumTest/restore-child.xml"), Charsets.UTF_8)), null);
// parent profile is unchanged
List<ActiveRule> activeRules = tester.get(QProfileService.class).findActiveRulesByProfile(XOO_PROFILE_KEY);
// restore backup of parent profile -> update x1 and propagates to child
tester.get(QProfileBackuper.class).restore(new StringReader(
- Resources.toString(getClass().getResource("QProfileBackuperMediumTest/restore-parent.xml"), Charsets.UTF_8)));
+ Resources.toString(getClass().getResource("QProfileBackuperMediumTest/restore-parent.xml"), Charsets.UTF_8)), null);
// parent profile is updated
List<ActiveRule> activeRules = tester.get(QProfileService.class).findActiveRulesByProfile(XOO_PROFILE_KEY);
// backup of child profile does not contain x1
try {
tester.get(QProfileBackuper.class).restore(new StringReader(
- Resources.toString(getClass().getResource("QProfileBackuperMediumTest/restore_fails_to_deactivate_inherited_rule.xml"), Charsets.UTF_8)));
+ Resources.toString(getClass().getResource("QProfileBackuperMediumTest/restore_fails_to_deactivate_inherited_rule.xml"), Charsets.UTF_8)), null);
fail();
} catch (IllegalStateException e) {
assertThat(e).hasMessage("Cannot deactivate inherited rule 'xoo:x1'");
public void fail_to_restore_if_not_xml_backup() throws Exception {
try {
tester.get(QProfileBackuper.class).restore(new StringReader(
- Resources.toString(getClass().getResource("QProfileBackuperMediumTest/not-xml-backup.txt"), Charsets.UTF_8)));
+ Resources.toString(getClass().getResource("QProfileBackuperMediumTest/not-xml-backup.txt"), Charsets.UTF_8)), null);
fail();
} catch (IllegalStateException e) {
assertThat(e).hasMessage("Fail to restore Quality profile backup");
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 com.google.common.collect.ImmutableMap;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rule.Severity;
+import org.sonar.api.server.rule.RuleParamType;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.qualityprofile.db.ActiveRuleDto;
+import org.sonar.core.qualityprofile.db.ActiveRuleKey;
+import org.sonar.core.qualityprofile.db.QualityProfileDto;
+import org.sonar.core.qualityprofile.db.QualityProfileKey;
+import org.sonar.core.rule.RuleDto;
+import org.sonar.core.rule.RuleParamDto;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.qualityprofile.index.ActiveRuleIndex;
+import org.sonar.server.rule.RuleTesting;
+import org.sonar.server.search.IndexClient;
+import org.sonar.server.tester.ServerTester;
+
+import javax.annotation.Nullable;
+import java.util.List;
+import java.util.Map;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.fest.assertions.Fail.fail;
+
+public class QProfileCopierMediumTest {
+
+ static final QualityProfileKey XOO_PROFILE_1 = QualityProfileKey.of("P1", "xoo");
+ static final QualityProfileKey XOO_CHILD_1 = QualityProfileKey.of("P1CHILD", "xoo");
+ static final QualityProfileKey XOO_PROFILE_2 = QualityProfileKey.of("P2", "xoo");
+ static final RuleKey XOO_RULE_1 = RuleKey.of("xoo", "x1");
+ static final RuleKey XOO_RULE_2 = RuleKey.of("xoo", "x2");
+
+ @ClassRule
+ public static ServerTester tester = new ServerTester();
+
+ DbClient db;
+ DbSession dbSession;
+ ActiveRuleIndex index;
+ RuleActivator ruleActivator;
+ QProfileCopier copier;
+
+ @Before
+ public void before() {
+ tester.clearDbAndIndexes();
+ db = tester.get(DbClient.class);
+ dbSession = db.openSession(false);
+ ruleActivator = tester.get(RuleActivator.class);
+ index = tester.get(ActiveRuleIndex.class);
+ copier = tester.get(QProfileCopier.class);
+
+ // create pre-defined rules
+ RuleDto xooRule1 = RuleTesting.newDto(XOO_RULE_1)
+ .setSeverity("MINOR").setLanguage("xoo");
+ RuleDto xooRule2 = RuleTesting.newDto(XOO_RULE_2)
+ .setSeverity("MAJOR").setLanguage("xoo");
+ db.ruleDao().insert(dbSession, xooRule1, xooRule2);
+ db.ruleDao().addRuleParam(dbSession, xooRule1, RuleParamDto.createFor(xooRule1)
+ .setName("max").setDefaultValue("10").setType(RuleParamType.INTEGER.type()));
+
+ // create pre-defined profile
+ db.qualityProfileDao().insert(dbSession, QualityProfileDto.createFor(XOO_PROFILE_1));
+ dbSession.commit();
+ dbSession.clearCache();
+ }
+
+ @After
+ public void after() throws Exception {
+ dbSession.close();
+ }
+
+ @Test
+ public void create_target_profile() throws Exception {
+ // source
+ RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_1, XOO_RULE_1));
+ activation.setSeverity(Severity.BLOCKER);
+ activation.setParameter("max", "7");
+ ruleActivator.activate(activation);
+
+ // target does not exist
+ copier.copy(XOO_PROFILE_1, XOO_PROFILE_2);
+
+ verifyOneActiveRule(XOO_PROFILE_2, Severity.BLOCKER, null, ImmutableMap.of("max", "7"));
+ }
+
+ @Test
+ public void update_target_profile() throws Exception {
+ // source with x1 activated
+ RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_1, XOO_RULE_1));
+ activation.setSeverity(Severity.BLOCKER);
+ activation.setParameter("max", "7");
+ ruleActivator.activate(activation);
+
+ // create target with both x1 and x2 activated
+ db.qualityProfileDao().insert(dbSession, QualityProfileDto.createFor(XOO_PROFILE_2));
+ activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_2, XOO_RULE_1));
+ activation.setSeverity(Severity.CRITICAL);
+ activation.setParameter("max", "20");
+ ruleActivator.activate(dbSession, activation);
+ dbSession.commit();
+ activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_2, XOO_RULE_2));
+ activation.setSeverity(Severity.CRITICAL);
+ ruleActivator.activate(dbSession, activation);
+ dbSession.commit();
+ dbSession.clearCache();
+
+ // copy -> reset x1 and deactivate x2
+ copier.copy(XOO_PROFILE_1, XOO_PROFILE_2);
+
+ verifyOneActiveRule(XOO_PROFILE_2, Severity.BLOCKER, null, ImmutableMap.of("max", "7"));
+ }
+
+ @Test
+ public void create_target_profile_with_same_parent_than_source() throws Exception {
+ // two profiles : parent and its child
+ db.qualityProfileDao().insert(dbSession, QualityProfileDto.createFor(XOO_CHILD_1)
+ .setParent(XOO_PROFILE_1.name()));
+ dbSession.commit();
+
+ // parent and child with x1 activated
+ RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_1, XOO_RULE_1));
+ activation.setSeverity(Severity.BLOCKER);
+ activation.setParameter("max", "7");
+ ruleActivator.activate(activation);
+ dbSession.clearCache();
+
+ // copy child -> profile2 is created with parent P1
+ copier.copy(XOO_CHILD_1, XOO_PROFILE_2);
+
+ verifyOneActiveRule(XOO_PROFILE_2, Severity.BLOCKER, ActiveRuleDto.INHERITED, ImmutableMap.of("max", "7"));
+ QualityProfileDto profile2Dto = db.qualityProfileDao().getByKey(XOO_PROFILE_2, dbSession);
+ assertThat(profile2Dto.getParent()).isEqualTo(XOO_PROFILE_1.name());
+ }
+
+ @Test
+ public void fail_to_copy_on_self() throws Exception {
+ RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_1, XOO_RULE_1));
+ activation.setSeverity(Severity.BLOCKER);
+ activation.setParameter("max", "7");
+ ruleActivator.activate(activation);
+
+ try {
+ copier.copy(XOO_PROFILE_1, XOO_PROFILE_1);
+ fail();
+ } catch (IllegalArgumentException e) {
+ assertThat(e).hasMessage("Source and target profiles are equal: P1:xoo");
+ }
+ }
+
+ @Test
+ public void fail_to_copy_on_different_language() throws Exception {
+ RuleActivation activation = new RuleActivation(ActiveRuleKey.of(XOO_PROFILE_1, XOO_RULE_1));
+ activation.setSeverity(Severity.BLOCKER);
+ activation.setParameter("max", "7");
+ ruleActivator.activate(activation);
+
+ try {
+ copier.copy(XOO_PROFILE_1, QualityProfileKey.of("NEW", "java"));
+ fail();
+ } catch (IllegalArgumentException e) {
+ assertThat(e).hasMessage("Source and target profiles do not have the same language: P1:xoo and NEW:java");
+ }
+ }
+
+ private void verifyOneActiveRule(QualityProfileKey profileKey, String expectedSeverity,
+ @Nullable String expectedInheritance, Map<String, String> expectedParams) {
+
+ List<ActiveRule> activeRules = index.findByProfile(profileKey);
+ assertThat(activeRules).hasSize(1);
+ ActiveRule activeRule = activeRules.get(0);
+ assertThat(activeRule.severity()).isEqualTo(expectedSeverity);
+ assertThat(activeRule.inheritance()).isEqualTo(expectedInheritance == null ? ActiveRule.Inheritance.NONE : ActiveRule.Inheritance.valueOf(expectedInheritance));
+
+ // verify parameters
+ assertThat(activeRule.params()).hasSize(expectedParams.size());
+ for (Map.Entry<String, String> entry : expectedParams.entrySet()) {
+ String value = activeRule.params().get(entry.getKey());
+ assertThat(value).isEqualTo(entry.getValue());
+ }
+ }
+}
verify(qualityProfileDao, never()).delete(anyInt(), eq(session));
verifyZeroInteractions(propertiesDao);
}
-
- @Test
- public void copy_profile() throws Exception {
- when(qualityProfileDao.selectById(1, session)).thenReturn(new QualityProfileDto().setId(1).setName("Default").setLanguage("java"));
- when(profilesManager.copyProfile(1, "Copy Default")).thenReturn(2);
-
- operations.copyProfile(1, "Copy Default", authorizedUserSession);
-
- verify(profilesManager).copyProfile(1, "Copy Default");
- }
-
- @Test
- public void fail_to_copy_profile_on_unknown_profile() throws Exception {
- when(qualityProfileDao.selectById(1, session)).thenReturn(null);
- when(profilesManager.copyProfile(1, "Copy Default")).thenReturn(2);
-
- try {
- operations.copyProfile(1, "Copy Default", authorizedUserSession);
- fail();
- } catch (Exception e) {
- assertThat(e).isInstanceOf(NotFoundException.class);
- }
-
- verifyZeroInteractions(profilesManager);
- verify(session, never()).commit();
- }
-
- @Test
- public void fail_to_copy_profile_if_name_already_exists() throws Exception {
- when(qualityProfileDao.selectById(1, session)).thenReturn(new QualityProfileDto().setId(1).setName("Default").setLanguage("java"));
- when(qualityProfileDao.selectByNameAndLanguage(anyString(), anyString(), eq(session))).thenReturn(new QualityProfileDto());
- when(profilesManager.copyProfile(1, "Copy Default")).thenReturn(2);
-
- try {
- operations.copyProfile(1, "Copy Default", authorizedUserSession);
- fail();
- } catch (Exception e) {
- assertThat(e).isInstanceOf(BadRequestException.class);
- }
-
- verifyZeroInteractions(profilesManager);
- verify(session, never()).commit();
- }
-
}
verify(profileOperations).setDefaultProfile(eq(1), any(UserSession.class));
}
- @Test
- public void copy_profile() throws Exception {
- qProfiles.copyProfile(1, "Copy Profile");
- verify(profileOperations).copyProfile(eq(1), eq("Copy Profile"), any(UserSession.class));
- }
-
@Test
public void update_parent_profile() throws Exception {
qProfiles.updateParentProfile(1, 2);
@After
public void after() throws Exception {
dbSession.close();
-
}
@Test
import org.junit.Before;
import org.junit.Test;
import org.sonar.api.rules.ActiveRuleChange;
-import org.sonar.api.rules.Rule;
import org.sonar.api.rules.RulePriority;
import org.sonar.core.preview.PreviewCache;
import org.sonar.jpa.test.AbstractDbUnitTestCase;
@Before
public void setUp() {
- profilesManager = new ProfilesManager(getSession(), null, mock(PreviewCache.class));
+ profilesManager = new ProfilesManager(getSession(), mock(PreviewCache.class));
}
@Test