You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

QProfileTreeImplTest.java 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2019 SonarSource SA
  4. * mailto:info AT sonarsource DOT com
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program; if not, write to the Free Software Foundation,
  18. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. package org.sonar.server.qualityprofile;
  21. import java.util.List;
  22. import java.util.Map;
  23. import java.util.Optional;
  24. import javax.annotation.Nullable;
  25. import org.junit.Rule;
  26. import org.junit.Test;
  27. import org.junit.rules.ExpectedException;
  28. import org.sonar.api.rule.RuleStatus;
  29. import org.sonar.api.rule.Severity;
  30. import org.sonar.api.utils.System2;
  31. import org.sonar.api.utils.internal.AlwaysIncreasingSystem2;
  32. import org.sonar.db.DbTester;
  33. import org.sonar.db.qualityprofile.ActiveRuleParamDto;
  34. import org.sonar.db.qualityprofile.OrgActiveRuleDto;
  35. import org.sonar.db.qualityprofile.QProfileDto;
  36. import org.sonar.db.rule.RuleDefinitionDto;
  37. import org.sonar.server.es.EsTester;
  38. import org.sonar.server.exceptions.BadRequestException;
  39. import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
  40. import org.sonar.server.tester.UserSessionRule;
  41. import org.sonar.server.util.IntegerTypeValidation;
  42. import org.sonar.server.util.StringTypeValidation;
  43. import org.sonar.server.util.TypeValidations;
  44. import static java.util.Arrays.asList;
  45. import static java.util.Collections.emptyMap;
  46. import static java.util.Collections.singleton;
  47. import static org.assertj.core.api.Assertions.assertThat;
  48. import static org.sonar.api.rule.Severity.BLOCKER;
  49. import static org.sonar.server.qualityprofile.ActiveRuleInheritance.INHERITED;
  50. public class QProfileTreeImplTest {
  51. @Rule
  52. public ExpectedException expectedException = ExpectedException.none();
  53. private System2 system2 = new AlwaysIncreasingSystem2();
  54. @Rule
  55. public DbTester db = DbTester.create(system2);
  56. @Rule
  57. public EsTester es = EsTester.create();
  58. @Rule
  59. public UserSessionRule userSession = UserSessionRule.standalone();
  60. private ActiveRuleIndexer activeRuleIndexer = new ActiveRuleIndexer(db.getDbClient(), es.client());
  61. private TypeValidations typeValidations = new TypeValidations(asList(new StringTypeValidation(), new IntegerTypeValidation()));
  62. private RuleActivator ruleActivator = new RuleActivator(system2, db.getDbClient(), typeValidations, userSession);
  63. private QProfileRules qProfileRules = new QProfileRulesImpl(db.getDbClient(), ruleActivator, null, activeRuleIndexer);
  64. private QProfileTree underTest = new QProfileTreeImpl(db.getDbClient(), ruleActivator, System2.INSTANCE, activeRuleIndexer);
  65. @Test
  66. public void set_itself_as_parent_fails() {
  67. RuleDefinitionDto rule = createRule();
  68. QProfileDto profile = createProfile(rule);
  69. expectedException.expect(BadRequestException.class);
  70. expectedException.expectMessage(" can not be selected as parent of ");
  71. underTest.setParentAndCommit(db.getSession(), profile, profile);
  72. }
  73. @Test
  74. public void set_child_as_parent_fails() {
  75. RuleDefinitionDto rule = createRule();
  76. QProfileDto parentProfile = createProfile(rule);
  77. QProfileDto childProfile = createChildProfile(parentProfile);
  78. expectedException.expect(BadRequestException.class);
  79. expectedException.expectMessage(" can not be selected as parent of ");
  80. underTest.setParentAndCommit(db.getSession(), parentProfile, childProfile);
  81. }
  82. @Test
  83. public void set_grandchild_as_parent_fails() {
  84. RuleDefinitionDto rule = createRule();
  85. QProfileDto parentProfile = createProfile(rule);
  86. QProfileDto childProfile = createChildProfile(parentProfile);
  87. QProfileDto grandchildProfile = createChildProfile(childProfile);
  88. expectedException.expect(BadRequestException.class);
  89. expectedException.expectMessage(" can not be selected as parent of ");
  90. underTest.setParentAndCommit(db.getSession(), parentProfile, grandchildProfile);
  91. }
  92. @Test
  93. public void cannot_set_parent_if_language_is_different() {
  94. RuleDefinitionDto rule1 = db.rules().insert(r -> r.setLanguage("foo"));
  95. RuleDefinitionDto rule2 = db.rules().insert(r -> r.setLanguage("bar"));
  96. QProfileDto parentProfile = createProfile(rule1);
  97. List<ActiveRuleChange> changes = activate(parentProfile, RuleActivation.create(rule1.getId()));
  98. assertThat(changes).hasSize(1);
  99. QProfileDto childProfile = createProfile(rule2);
  100. changes = activate(childProfile, RuleActivation.create(rule2.getId()));
  101. assertThat(changes).hasSize(1);
  102. expectedException.expect(BadRequestException.class);
  103. expectedException.expectMessage("Cannot set the profile");
  104. underTest.setParentAndCommit(db.getSession(), childProfile, parentProfile);
  105. }
  106. @Test
  107. public void set_then_unset_parent() {
  108. RuleDefinitionDto rule1 = createJavaRule();
  109. RuleDefinitionDto rule2 = createJavaRule();
  110. QProfileDto profile1 = createProfile(rule1);
  111. List<ActiveRuleChange> changes = activate(profile1, RuleActivation.create(rule1.getId()));
  112. assertThat(changes).hasSize(1);
  113. QProfileDto profile2 = createProfile(rule2);
  114. changes = activate(profile2, RuleActivation.create(rule2.getId()));
  115. assertThat(changes).hasSize(1);
  116. changes = underTest.setParentAndCommit(db.getSession(), profile2, profile1);
  117. assertThat(changes).hasSize(1);
  118. assertThatRuleIsActivated(profile2, rule1, changes, rule1.getSeverityString(), INHERITED, emptyMap());
  119. assertThatRuleIsActivated(profile2, rule2, null, rule2.getSeverityString(), null, emptyMap());
  120. changes = underTest.removeParentAndCommit(db.getSession(), profile2);
  121. assertThat(changes).hasSize(1);
  122. assertThatRuleIsActivated(profile2, rule2, null, rule2.getSeverityString(), null, emptyMap());
  123. assertThatRuleIsNotPresent(profile2, rule1);
  124. }
  125. @Test
  126. public void set_then_unset_parent_keep_overridden_rules() {
  127. RuleDefinitionDto rule1 = createJavaRule();
  128. RuleDefinitionDto rule2 = createJavaRule();
  129. QProfileDto profile1 = createProfile(rule1);
  130. List<ActiveRuleChange> changes = activate(profile1, RuleActivation.create(rule1.getId()));
  131. assertThat(changes).hasSize(1);
  132. QProfileDto profile2 = createProfile(rule2);
  133. changes = activate(profile2, RuleActivation.create(rule2.getId()));
  134. assertThat(changes).hasSize(1);
  135. changes = underTest.setParentAndCommit(db.getSession(), profile2, profile1);
  136. assertThat(changes).hasSize(1);
  137. assertThatRuleIsActivated(profile2, rule1, changes, rule1.getSeverityString(), INHERITED, emptyMap());
  138. assertThatRuleIsActivated(profile2, rule2, null, rule2.getSeverityString(), null, emptyMap());
  139. RuleActivation activation = RuleActivation.create(rule1.getId(), BLOCKER, null);
  140. changes = activate(profile2, activation);
  141. assertThat(changes).hasSize(1);
  142. assertThatRuleIsUpdated(profile2, rule1, BLOCKER, ActiveRuleInheritance.OVERRIDES, emptyMap());
  143. assertThatRuleIsActivated(profile2, rule2, null, rule2.getSeverityString(), null, emptyMap());
  144. changes = underTest.removeParentAndCommit(db.getSession(), profile2);
  145. assertThat(changes).hasSize(1);
  146. // Not testing changes here since severity is not set in changelog
  147. assertThatRuleIsActivated(profile2, rule1, null, BLOCKER, null, emptyMap());
  148. assertThatRuleIsActivated(profile2, rule2, null, rule2.getSeverityString(), null, emptyMap());
  149. }
  150. @Test
  151. public void activation_errors_are_ignored_when_setting_a_parent() {
  152. RuleDefinitionDto rule1 = createJavaRule();
  153. RuleDefinitionDto rule2 = createJavaRule();
  154. QProfileDto parentProfile = createProfile(rule1);
  155. activate(parentProfile, RuleActivation.create(rule1.getId()));
  156. activate(parentProfile, RuleActivation.create(rule2.getId()));
  157. rule1.setStatus(RuleStatus.REMOVED);
  158. db.rules().update(rule1);
  159. QProfileDto childProfile = createProfile(rule1);
  160. List<ActiveRuleChange> changes = underTest.setParentAndCommit(db.getSession(), childProfile, parentProfile);
  161. assertThatRuleIsNotPresent(childProfile, rule1);
  162. assertThatRuleIsActivated(childProfile, rule2, changes, rule2.getSeverityString(), INHERITED, emptyMap());
  163. }
  164. private List<ActiveRuleChange> activate(QProfileDto profile, RuleActivation activation) {
  165. return qProfileRules.activateAndCommit(db.getSession(), profile, singleton(activation));
  166. }
  167. private QProfileDto createProfile(RuleDefinitionDto rule) {
  168. return db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(rule.getLanguage()));
  169. }
  170. private QProfileDto createChildProfile(QProfileDto parent) {
  171. return db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p
  172. .setLanguage(parent.getLanguage())
  173. .setParentKee(parent.getKee())
  174. .setName("Child of " + parent.getName()));
  175. }
  176. private void assertThatRuleIsActivated(QProfileDto profile, RuleDefinitionDto rule, @Nullable List<ActiveRuleChange> changes,
  177. String expectedSeverity, @Nullable ActiveRuleInheritance expectedInheritance, Map<String, String> expectedParams) {
  178. OrgActiveRuleDto activeRule = db.getDbClient().activeRuleDao().selectByProfile(db.getSession(), profile)
  179. .stream()
  180. .filter(ar -> ar.getRuleKey().equals(rule.getKey()))
  181. .findFirst()
  182. .orElseThrow(IllegalStateException::new);
  183. assertThat(activeRule.getSeverityString()).isEqualTo(expectedSeverity);
  184. assertThat(activeRule.getInheritance()).isEqualTo(expectedInheritance != null ? expectedInheritance.name() : null);
  185. assertThat(activeRule.getCreatedAt()).isNotNull();
  186. assertThat(activeRule.getUpdatedAt()).isNotNull();
  187. List<ActiveRuleParamDto> params = db.getDbClient().activeRuleDao().selectParamsByActiveRuleId(db.getSession(), activeRule.getId());
  188. assertThat(params).hasSize(expectedParams.size());
  189. if (changes != null) {
  190. ActiveRuleChange change = changes.stream()
  191. .filter(c -> c.getActiveRule().getId().equals(activeRule.getId()))
  192. .findFirst().orElseThrow(IllegalStateException::new);
  193. assertThat(change.getInheritance()).isEqualTo(expectedInheritance);
  194. assertThat(change.getSeverity()).isEqualTo(expectedSeverity);
  195. assertThat(change.getType()).isEqualTo(ActiveRuleChange.Type.ACTIVATED);
  196. }
  197. }
  198. private void assertThatRuleIsNotPresent(QProfileDto profile, RuleDefinitionDto rule) {
  199. Optional<OrgActiveRuleDto> activeRule = db.getDbClient().activeRuleDao().selectByProfile(db.getSession(), profile)
  200. .stream()
  201. .filter(ar -> ar.getRuleKey().equals(rule.getKey()))
  202. .findFirst();
  203. assertThat(activeRule).isEmpty();
  204. }
  205. private void assertThatRuleIsUpdated(QProfileDto profile, RuleDefinitionDto rule,
  206. String expectedSeverity, @Nullable ActiveRuleInheritance expectedInheritance, Map<String, String> expectedParams) {
  207. OrgActiveRuleDto activeRule = db.getDbClient().activeRuleDao().selectByProfile(db.getSession(), profile)
  208. .stream()
  209. .filter(ar -> ar.getRuleKey().equals(rule.getKey()))
  210. .findFirst()
  211. .orElseThrow(IllegalStateException::new);
  212. assertThat(activeRule.getSeverityString()).isEqualTo(expectedSeverity);
  213. assertThat(activeRule.getInheritance()).isEqualTo(expectedInheritance != null ? expectedInheritance.name() : null);
  214. assertThat(activeRule.getCreatedAt()).isNotNull();
  215. assertThat(activeRule.getUpdatedAt()).isNotNull();
  216. List<ActiveRuleParamDto> params = db.getDbClient().activeRuleDao().selectParamsByActiveRuleId(db.getSession(), activeRule.getId());
  217. assertThat(params).hasSize(expectedParams.size());
  218. }
  219. private RuleDefinitionDto createRule() {
  220. return db.rules().insert(r -> r.setSeverity(Severity.MAJOR));
  221. }
  222. private RuleDefinitionDto createJavaRule() {
  223. return db.rules().insert(r -> r.setSeverity(Severity.MAJOR).setLanguage("java"));
  224. }
  225. }