From d075d50dec37ed658ee3deff4df7e5fea5b8259d Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Lievremont Date: Tue, 21 Jan 2014 16:19:48 +0100 Subject: [PATCH] SONAR-4326 Allow to add and remove tags on a rule --- .../java/org/sonar/core/rule/RuleTagDao.java | 19 ++++- .../org/sonar/core/rule/RuleTagMapper.java | 2 + .../org/sonar/core/rule/RuleTagMapper.xml | 6 ++ .../org/sonar/core/rule/RuleTagDaoTest.java | 67 +++++++++++++++++ .../rule/RuleTagDaoTest/delete-result.xml | 7 ++ .../rule/RuleTagDaoTest/insert-result.xml | 9 +++ .../sonar/core/rule/RuleTagDaoTest/shared.xml | 8 ++ .../QProfileRuleOperations.java | 70 ++++++++++++++++-- .../server/qualityprofile/QProfiles.java | 13 ++++ .../rules_configuration_controller.rb | 17 +++++ .../views/rules_configuration/_rule.html.erb | 18 ++--- .../rules_configuration/_rule_tags.html.erb | 9 +++ .../rules_configuration/_select_tags.html.erb | 37 ++++++++++ .../QProfileRuleOperationsTest.java | 73 ++++++++++++++++++- .../server/qualityprofile/QProfilesTest.java | 36 ++++++++- 15 files changed, 366 insertions(+), 25 deletions(-) create mode 100644 sonar-core/src/test/java/org/sonar/core/rule/RuleTagDaoTest.java create mode 100644 sonar-core/src/test/resources/org/sonar/core/rule/RuleTagDaoTest/delete-result.xml create mode 100644 sonar-core/src/test/resources/org/sonar/core/rule/RuleTagDaoTest/insert-result.xml create mode 100644 sonar-core/src/test/resources/org/sonar/core/rule/RuleTagDaoTest/shared.xml create mode 100644 sonar-server/src/main/webapp/WEB-INF/app/views/rules_configuration/_rule_tags.html.erb create mode 100644 sonar-server/src/main/webapp/WEB-INF/app/views/rules_configuration/_select_tags.html.erb diff --git a/sonar-core/src/main/java/org/sonar/core/rule/RuleTagDao.java b/sonar-core/src/main/java/org/sonar/core/rule/RuleTagDao.java index 7e5696ef77f..275b73f841b 100644 --- a/sonar-core/src/main/java/org/sonar/core/rule/RuleTagDao.java +++ b/sonar-core/src/main/java/org/sonar/core/rule/RuleTagDao.java @@ -19,9 +19,9 @@ */ package org.sonar.core.rule; -import org.sonar.core.persistence.MyBatis; -import org.sonar.api.ServerExtension; import org.apache.ibatis.session.SqlSession; +import org.sonar.api.ServerExtension; +import org.sonar.core.persistence.MyBatis; import java.util.List; @@ -50,6 +50,7 @@ public class RuleTagDao implements ServerExtension { SqlSession session = myBatis.openSession(); try { insert(newRuleTag, session); + session.commit(); } finally { MyBatis.closeQuietly(session); } @@ -63,6 +64,7 @@ public class RuleTagDao implements ServerExtension { SqlSession session = myBatis.openSession(); try { delete(tagId, session); + session.commit(); } finally { MyBatis.closeQuietly(session); } @@ -71,4 +73,17 @@ public class RuleTagDao implements ServerExtension { public void delete(long tagId, SqlSession session) { session.getMapper(RuleTagMapper.class).delete(tagId); } + + public Long selectId(String tag) { + SqlSession session = myBatis.openSession(); + try { + return selectId(tag, session); + } finally { + MyBatis.closeQuietly(session); + } + } + + public Long selectId(String tag, SqlSession session) { + return session.getMapper(RuleTagMapper.class).selectId(tag); + } } diff --git a/sonar-core/src/main/java/org/sonar/core/rule/RuleTagMapper.java b/sonar-core/src/main/java/org/sonar/core/rule/RuleTagMapper.java index 656313007af..5798e0da0da 100644 --- a/sonar-core/src/main/java/org/sonar/core/rule/RuleTagMapper.java +++ b/sonar-core/src/main/java/org/sonar/core/rule/RuleTagMapper.java @@ -28,4 +28,6 @@ public interface RuleTagMapper { void insert(RuleTagDto newTag); void delete(Long tagId); + + Long selectId(String tag); } diff --git a/sonar-core/src/main/resources/org/sonar/core/rule/RuleTagMapper.xml b/sonar-core/src/main/resources/org/sonar/core/rule/RuleTagMapper.xml index e2c8b16fe52..b2c0f2758f1 100644 --- a/sonar-core/src/main/resources/org/sonar/core/rule/RuleTagMapper.xml +++ b/sonar-core/src/main/resources/org/sonar/core/rule/RuleTagMapper.xml @@ -17,5 +17,11 @@ DELETE FROM rule_tags WHERE id=#{tagId} + + diff --git a/sonar-core/src/test/java/org/sonar/core/rule/RuleTagDaoTest.java b/sonar-core/src/test/java/org/sonar/core/rule/RuleTagDaoTest.java new file mode 100644 index 00000000000..a26b1f21639 --- /dev/null +++ b/sonar-core/src/test/java/org/sonar/core/rule/RuleTagDaoTest.java @@ -0,0 +1,67 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 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.core.rule; + +import org.junit.Before; +import org.junit.Test; +import org.sonar.core.persistence.AbstractDaoTestCase; + +import static org.fest.assertions.Assertions.assertThat; + +public class RuleTagDaoTest extends AbstractDaoTestCase { + + RuleTagDao dao; + + @Before + public void createDao() { + dao = new RuleTagDao(getMyBatis()); + } + + @Test + public void should_select_all_tags() { + setupData("shared"); + + assertThat(dao.selectAll()).hasSize(3); + } + + @Test + public void should_select_id() { + setupData("shared"); + + assertThat(dao.selectId("tag1")).isEqualTo(1L); + assertThat(dao.selectId("unknown")).isNull(); + } + + @Test + public void should_insert_tag() { + setupData("shared"); + + dao.insert(new RuleTagDto().setTag("tag4")); + checkTable("insert", "rule_tags"); + } + + @Test + public void should_delete_tag() { + setupData("shared"); + + dao.delete(1L); + checkTable("delete", "rule_tags"); + } +} diff --git a/sonar-core/src/test/resources/org/sonar/core/rule/RuleTagDaoTest/delete-result.xml b/sonar-core/src/test/resources/org/sonar/core/rule/RuleTagDaoTest/delete-result.xml new file mode 100644 index 00000000000..8c9c2d034f9 --- /dev/null +++ b/sonar-core/src/test/resources/org/sonar/core/rule/RuleTagDaoTest/delete-result.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/sonar-core/src/test/resources/org/sonar/core/rule/RuleTagDaoTest/insert-result.xml b/sonar-core/src/test/resources/org/sonar/core/rule/RuleTagDaoTest/insert-result.xml new file mode 100644 index 00000000000..3b805137bdd --- /dev/null +++ b/sonar-core/src/test/resources/org/sonar/core/rule/RuleTagDaoTest/insert-result.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/sonar-core/src/test/resources/org/sonar/core/rule/RuleTagDaoTest/shared.xml b/sonar-core/src/test/resources/org/sonar/core/rule/RuleTagDaoTest/shared.xml new file mode 100644 index 00000000000..e7085790921 --- /dev/null +++ b/sonar-core/src/test/resources/org/sonar/core/rule/RuleTagDaoTest/shared.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileRuleOperations.java b/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileRuleOperations.java index 754a981b3e9..9f9d267bcf4 100644 --- a/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileRuleOperations.java +++ b/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileRuleOperations.java @@ -24,6 +24,9 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Function; import com.google.common.base.Strings; import com.google.common.collect.Iterables; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import org.apache.commons.lang.StringUtils; import org.apache.ibatis.session.SqlSession; import org.sonar.api.ServerComponent; import org.sonar.api.rule.Severity; @@ -34,17 +37,16 @@ import org.sonar.core.permission.GlobalPermissions; import org.sonar.core.persistence.MyBatis; import org.sonar.core.qualityprofile.db.ActiveRuleDao; import org.sonar.core.qualityprofile.db.ActiveRuleDto; -import org.sonar.core.rule.RuleDao; -import org.sonar.core.rule.RuleDto; -import org.sonar.core.rule.RuleParamDto; -import org.sonar.core.rule.RuleRuleTagDto; +import org.sonar.core.rule.*; import org.sonar.server.exceptions.BadRequestException; +import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.rule.RuleRegistry; import org.sonar.server.user.UserSession; import java.util.Date; import java.util.List; import java.util.Map; +import java.util.Set; import static com.google.common.collect.Lists.newArrayList; @@ -53,19 +55,21 @@ public class QProfileRuleOperations implements ServerComponent { private final MyBatis myBatis; private final ActiveRuleDao activeRuleDao; private final RuleDao ruleDao; + private final RuleTagDao ruleTagDao; private final RuleRegistry ruleRegistry; private final System2 system; - public QProfileRuleOperations(MyBatis myBatis, ActiveRuleDao activeRuleDao, RuleDao ruleDao, RuleRegistry ruleRegistry) { - this(myBatis, activeRuleDao, ruleDao, ruleRegistry, System2.INSTANCE); + public QProfileRuleOperations(MyBatis myBatis, ActiveRuleDao activeRuleDao, RuleDao ruleDao, RuleTagDao ruleTagDao, RuleRegistry ruleRegistry) { + this(myBatis, activeRuleDao, ruleDao, ruleTagDao, ruleRegistry, System2.INSTANCE); } @VisibleForTesting - QProfileRuleOperations(MyBatis myBatis, ActiveRuleDao activeRuleDao, RuleDao ruleDao, RuleRegistry ruleRegistry, System2 system) { + QProfileRuleOperations(MyBatis myBatis, ActiveRuleDao activeRuleDao, RuleDao ruleDao, RuleTagDao ruleTagDao, RuleRegistry ruleRegistry, System2 system) { this.myBatis = myBatis; this.activeRuleDao = activeRuleDao; this.ruleDao = ruleDao; + this.ruleTagDao = ruleTagDao; this.ruleRegistry = ruleRegistry; this.system = system; } @@ -219,6 +223,57 @@ public class QProfileRuleOperations implements ServerComponent { } } + public void updateTags(RuleDto rule, List newTags, UserSession userSession) { + checkPermission(userSession); + SqlSession session = myBatis.openSession(); + try { + boolean ruleChanged = false; + Map neededTagIds = Maps.newHashMap(); + Set unknownTags = Sets.newHashSet(); + for (String tag: newTags) { + Long tagId = ruleTagDao.selectId(tag, session); + if (tagId == null) { + unknownTags.add(tag); + } else { + neededTagIds.put(tag, tagId); + } + } + if (!unknownTags.isEmpty()) { + throw new NotFoundException("The following tags are unknown and must be created before association: " + + StringUtils.join(unknownTags, ", ")); + } + + Set tagsToKeep = Sets.newHashSet(); + final Integer ruleId = rule.getId(); + + List currentTags = ruleDao.selectTags(ruleId, session); + for (RuleRuleTagDto existingTag: currentTags) { + if(existingTag.getType() == RuleTagType.ADMIN && !newTags.contains(existingTag.getTag())) { + ruleDao.deleteTag(existingTag, session); + ruleChanged = true; + } else { + tagsToKeep.add(existingTag.getTag()); + } + } + + for (String tag: newTags) { + if (! tagsToKeep.contains(tag)) { + ruleDao.insert(new RuleRuleTagDto().setRuleId(ruleId).setTagId(neededTagIds.get(tag)).setType(RuleTagType.ADMIN), session); + ruleChanged = true; + } + } + + if (ruleChanged) { + rule.setUpdatedAt(new Date(system.now())); + ruleDao.update(rule, session); + session.commit(); + reindexRule(rule, session); + } + } finally { + MyBatis.closeQuietly(session); + } + } + private void reindexRule(RuleDto rule, SqlSession session) { reindexRule(rule, ruleDao.selectParameters(rule.getId(), session), ruleDao.selectTags(rule.getId(), session)); } @@ -243,5 +298,4 @@ public class QProfileRuleOperations implements ServerComponent { private static int getSeverityOrdinal(String severity) { return Severity.ALL.indexOf(severity); } - } diff --git a/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfiles.java b/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfiles.java index 8abc1dd1ef4..6db47467ae3 100644 --- a/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfiles.java +++ b/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfiles.java @@ -20,6 +20,8 @@ package org.sonar.server.qualityprofile; +import com.google.common.collect.ImmutableList; + import com.google.common.base.Strings; import org.sonar.api.ServerComponent; import org.sonar.api.component.Component; @@ -39,6 +41,7 @@ import org.sonar.server.rule.ProfileRuleQuery; import org.sonar.server.rule.ProfileRules; import org.sonar.server.rule.RuleTagLookup; import org.sonar.server.user.UserSession; +import org.sonar.server.util.RubyUtils; import org.sonar.server.util.Validation; import javax.annotation.CheckForNull; @@ -375,6 +378,16 @@ public class QProfiles implements ServerComponent { return ruleTagLookup.listAllTags(); } + public QProfileRule updateRuleTags(int ruleId, Object tags) { + RuleDto rule = findRuleNotNull(ruleId); + List newTags = RubyUtils.toStrings(tags); + if (newTags == null) { + newTags = ImmutableList.of(); + } + ruleOperations.updateTags(rule, newTags, UserSession.get()); + return rules.findByRuleId(ruleId); + } + // // Quality profile validation // diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/rules_configuration_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/rules_configuration_controller.rb index 7d25064f006..622158d0f44 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/rules_configuration_controller.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/rules_configuration_controller.rb @@ -337,6 +337,23 @@ class RulesConfigurationController < ApplicationController render :partial => 'active_rule_note', :locals => {:rule => rule} end + def show_select_tags + rule = Internal.quality_profiles.findByRule(params[:rule_id].to_i) + tags = [] + Internal.quality_profiles.listAllTags().sort.each do |tag| + tags.push({ + :value => tag, + :selected => (rule.systemTags.contains?(tag) || rule.adminTags.contains?(tag)), + :read_only => rule.systemTags.contains?(tag) + }) + end + render :partial => 'select_tags', :locals => { :rule => rule, :tags => tags, :profile_id => params[:profile_id] } + end + + def select_tags + rule = Internal.quality_profiles.updateRuleTags(params[:rule_id].to_i, params[:tags]) + render :partial => 'rule_tags', :locals => {:rule => rule} + end private diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/rules_configuration/_rule.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/rules_configuration/_rule.html.erb index e0f8f0bf338..6ad68ac712a 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/rules_configuration/_rule.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/rules_configuration/_rule.html.erb @@ -37,17 +37,9 @@ <% end %> <% end %> - <% unless rule.systemTags.isEmpty && rule.adminTags.isEmpty %> -
- <% rule.systemTags.each do |tag| %> - <%= tag -%> - <% end %> - <% rule.adminTags.each do |tag| %> - <%= tag -%> - <% end %> +
+ <%= render :partial => 'rule_tags', :locals => {:rule => rule} -%>
- <% end %> -
<%= link_to_function("#{h rule.name}", nil, :class => "") do |page| page.toggle "desc_#{rule.id}" @@ -100,6 +92,12 @@ <% end %> + <% if profiles_administrator? %> + + <% end %> + <% if is_activated %>
<%= render :partial => 'active_rule_note', :locals => {:rule => rule} %> diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/rules_configuration/_rule_tags.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/rules_configuration/_rule_tags.html.erb new file mode 100644 index 00000000000..13aba0f0c29 --- /dev/null +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/rules_configuration/_rule_tags.html.erb @@ -0,0 +1,9 @@ +<% #locals = rule -%> +<% unless rule.systemTags.isEmpty && rule.adminTags.isEmpty %> + <% rule.systemTags.each do |tag| %> + <%= tag -%> + <% end %> + <% rule.adminTags.each do |tag| %> + <%= tag -%> + <% end %> +<% end %> diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/rules_configuration/_select_tags.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/rules_configuration/_select_tags.html.erb new file mode 100644 index 00000000000..e58680e8164 --- /dev/null +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/rules_configuration/_select_tags.html.erb @@ -0,0 +1,37 @@ +<% #locals = rule, tags, profile_id -%> +
+ <%= hidden_field_tag :rule_id, rule.id -%> + <%= hidden_field_tag :profile_id, profile_id -%> +
+ + +
+
diff --git a/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileRuleOperationsTest.java b/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileRuleOperationsTest.java index 22059a53748..6036e2f9655 100644 --- a/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileRuleOperationsTest.java +++ b/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileRuleOperationsTest.java @@ -20,6 +20,7 @@ package org.sonar.server.qualityprofile; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import org.apache.ibatis.session.SqlSession; import org.junit.Before; @@ -41,6 +42,7 @@ import org.sonar.core.qualityprofile.db.ActiveRuleDao; import org.sonar.core.qualityprofile.db.ActiveRuleDto; import org.sonar.core.rule.*; import org.sonar.server.exceptions.ForbiddenException; +import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.rule.RuleRegistry; import org.sonar.server.user.MockUserSession; import org.sonar.server.user.UserSession; @@ -72,6 +74,9 @@ public class QProfileRuleOperationsTest { @Mock RuleDao ruleDao; + @Mock + RuleTagDao ruleTagDao; + @Mock RuleRegistry ruleRegistry; @@ -99,7 +104,7 @@ public class QProfileRuleOperationsTest { } }).when(activeRuleDao).insert(any(ActiveRuleDto.class), any(SqlSession.class)); - operations = new QProfileRuleOperations(myBatis, activeRuleDao, ruleDao, ruleRegistry, system); + operations = new QProfileRuleOperations(myBatis, activeRuleDao, ruleDao, ruleTagDao, ruleRegistry, system); } @Test @@ -283,4 +288,70 @@ public class QProfileRuleOperationsTest { verify(ruleRegistry).deleteActiveRules(newArrayList(activeRuleId)); } + @Test(expected = ForbiddenException.class) + public void should_fail_update_tags_on_unauthorized_user() { + operations.updateTags(new RuleDto(), ImmutableList.of("polop"), unauthorizedUserSession); + } + + @Test(expected = NotFoundException.class) + public void should_fail_update_tags_on_unknown_tag() { + final String tag = "polop"; + when(ruleTagDao.selectId(tag, session)).thenReturn(null); + operations.updateTags(new RuleDto(), ImmutableList.of(tag), authorizedUserSession); + } + + @Test + public void should_add_new_tags() { + final int ruleId = 24; + final RuleDto rule = new RuleDto().setId(ruleId); + final String tag = "polop"; + final long tagId = 42L; + when(ruleTagDao.selectId(tag, session)).thenReturn(tagId); + + operations.updateTags(rule, ImmutableList.of(tag), authorizedUserSession); + + verify(ruleTagDao).selectId(tag, session); + ArgumentCaptor capture = ArgumentCaptor.forClass(RuleRuleTagDto.class); + verify(ruleDao).insert(capture.capture(), eq(session)); + final RuleRuleTagDto newTag = capture.getValue(); + assertThat(newTag.getRuleId()).isEqualTo(ruleId); + assertThat(newTag.getTagId()).isEqualTo(tagId); + assertThat(newTag.getType()).isEqualTo(RuleTagType.ADMIN); + verify(ruleDao).update(rule, session); + verify(session).commit(); + } + + @Test + public void should_delete_removed_tags() { + final int ruleId = 24; + final RuleDto rule = new RuleDto().setId(ruleId); + final String tag = "polop"; + RuleRuleTagDto existingTag = new RuleRuleTagDto().setTag(tag).setType(RuleTagType.ADMIN); + when(ruleDao.selectTags(ruleId, session)).thenReturn(ImmutableList.of(existingTag)); + + + operations.updateTags(rule, ImmutableList.of(), authorizedUserSession); + + verify(ruleDao, atLeast(1)).selectTags(ruleId, session); + verify(ruleDao).deleteTag(existingTag, session); + verify(ruleDao).update(rule, session); + verify(session).commit(); + } + + @Test + public void should_not_update_rule_if_tags_unchanged() { + final int ruleId = 24; + final RuleDto rule = new RuleDto().setId(ruleId); + final String tag = "polop"; + final long tagId = 42L; + when(ruleTagDao.selectId(tag, session)).thenReturn(tagId); + RuleRuleTagDto existingTag = new RuleRuleTagDto().setTag(tag).setType(RuleTagType.ADMIN); + when(ruleDao.selectTags(ruleId, session)).thenReturn(ImmutableList.of(existingTag)); + + operations.updateTags(rule, ImmutableList.of(tag), authorizedUserSession); + + verify(ruleTagDao).selectId(tag, session); + verify(ruleDao).selectTags(ruleId, session); + verify(ruleDao, never()).update(rule); + } } diff --git a/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfilesTest.java b/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfilesTest.java index e93baef7a65..12a43f93b50 100644 --- a/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfilesTest.java +++ b/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfilesTest.java @@ -20,6 +20,7 @@ package org.sonar.server.qualityprofile; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Maps; import org.junit.Before; @@ -43,16 +44,15 @@ import org.sonar.server.rule.ProfileRules; import org.sonar.server.rule.RuleTagLookup; import org.sonar.server.user.UserSession; +import java.util.Collection; +import java.util.List; import java.util.Map; import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Maps.newHashMap; import static org.fest.assertions.Assertions.assertThat; import static org.fest.assertions.Fail.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; +import static org.mockito.Matchers.*; import static org.mockito.Mockito.*; @RunWith(MockitoJUnitRunner.class) @@ -648,4 +648,32 @@ public class QProfilesTest { assertThat(qProfiles.countActiveRules(rule)).isEqualTo(2); } + @Test + public void should_find_all_tags() { + Collection tags = ImmutableList.of("tag1", "tag2"); + when(ruleTagLookup.listAllTags()).thenReturn(tags); + assertThat(qProfiles.listAllTags()).isEqualTo(tags); + verify(ruleTagLookup).listAllTags(); + } + + @Test + public void should_pass_tags_to_update() { + final int ruleId = 11; + RuleDto rule = new RuleDto().setId(ruleId).setRepositoryKey("squid").setRuleKey("XPath_1387869254").setParentId(10); + when(ruleDao.selectById(ruleId)).thenReturn(rule); + + qProfiles.updateRuleTags(ruleId, null); + verify(ruleOperations).updateTags(eq(rule), isA(List.class), any(UserSession.class)); + } + + @Test + public void should_prepare_empty_tag_list() { + final int ruleId = 11; + RuleDto rule = new RuleDto().setId(ruleId).setRepositoryKey("squid").setRuleKey("XPath_1387869254").setParentId(10); + when(ruleDao.selectById(ruleId)).thenReturn(rule); + + List tags = ImmutableList.of("tag1", "tag2"); + qProfiles.updateRuleTags(ruleId, tags); + verify(ruleOperations).updateTags(eq(rule), eq(tags), any(UserSession.class)); + } } -- 2.39.5