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.

QProfileBackuperImplTest.java 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  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 com.google.common.io.Resources;
  22. import java.io.Reader;
  23. import java.io.StringReader;
  24. import java.io.StringWriter;
  25. import java.util.ArrayList;
  26. import java.util.Collection;
  27. import java.util.List;
  28. import org.junit.Rule;
  29. import org.junit.Test;
  30. import org.junit.rules.ExpectedException;
  31. import org.sonar.api.rule.RuleKey;
  32. import org.sonar.api.utils.System2;
  33. import org.sonar.api.utils.internal.AlwaysIncreasingSystem2;
  34. import org.sonar.db.DbSession;
  35. import org.sonar.db.DbTester;
  36. import org.sonar.db.organization.OrganizationDto;
  37. import org.sonar.db.qualityprofile.ActiveRuleDto;
  38. import org.sonar.db.qualityprofile.ActiveRuleParamDto;
  39. import org.sonar.db.qualityprofile.QProfileDto;
  40. import org.sonar.db.qualityprofile.QualityProfileTesting;
  41. import org.sonar.db.rule.RuleDefinitionDto;
  42. import org.sonar.db.rule.RuleParamDto;
  43. import static java.nio.charset.StandardCharsets.UTF_8;
  44. import static org.assertj.core.api.Assertions.assertThat;
  45. import static org.junit.Assert.fail;
  46. import static org.junit.rules.ExpectedException.none;
  47. public class QProfileBackuperImplTest {
  48. private static final String EMPTY_BACKUP = "<?xml version='1.0' encoding='UTF-8'?>" +
  49. "<profile><name>foo</name>" +
  50. "<language>js</language>" +
  51. "<rules/>" +
  52. "</profile>";
  53. private System2 system2 = new AlwaysIncreasingSystem2();
  54. @Rule
  55. public ExpectedException expectedException = none();
  56. @Rule
  57. public DbTester db = DbTester.create(system2);
  58. private DummyReset reset = new DummyReset();
  59. private QProfileFactory profileFactory = new DummyProfileFactory();
  60. private QProfileBackuper underTest = new QProfileBackuperImpl(db.getDbClient(), reset, profileFactory);
  61. @Test
  62. public void backup_generates_xml_file() {
  63. RuleDefinitionDto rule = createRule();
  64. QProfileDto profile = createProfile(rule);
  65. ActiveRuleDto activeRule = activate(profile, rule);
  66. StringWriter writer = new StringWriter();
  67. underTest.backup(db.getSession(), profile, writer);
  68. assertThat(writer.toString()).isEqualTo("<?xml version='1.0' encoding='UTF-8'?>" +
  69. "<profile><name>" + profile.getName() + "</name>" +
  70. "<language>" + profile.getLanguage() + "</language>" +
  71. "<rules>" +
  72. "<rule>" +
  73. "<repositoryKey>" + rule.getRepositoryKey() + "</repositoryKey>" +
  74. "<key>" + rule.getRuleKey() + "</key>" +
  75. "<priority>" + activeRule.getSeverityString() + "</priority>" +
  76. "<parameters/>" +
  77. "</rule>" +
  78. "</rules>" +
  79. "</profile>");
  80. }
  81. @Test
  82. public void backup_rules_having_parameters() {
  83. RuleDefinitionDto rule = createRule();
  84. RuleParamDto param = db.rules().insertRuleParam(rule);
  85. QProfileDto profile = createProfile(rule);
  86. ActiveRuleDto activeRule = activate(profile, rule, param);
  87. StringWriter writer = new StringWriter();
  88. underTest.backup(db.getSession(), profile, writer);
  89. assertThat(writer.toString()).contains(
  90. "<rule>" +
  91. "<repositoryKey>" + rule.getRepositoryKey() + "</repositoryKey>" +
  92. "<key>" + rule.getRuleKey() + "</key>" +
  93. "<priority>" + activeRule.getSeverityString() + "</priority>" +
  94. "<parameters><parameter>" +
  95. "<key>" + param.getName() + "</key>" +
  96. "<value>20</value>" +
  97. "</parameter></parameters>" +
  98. "</rule>");
  99. }
  100. @Test
  101. public void backup_empty_profile() {
  102. RuleDefinitionDto rule = createRule();
  103. QProfileDto profile = createProfile(rule);
  104. StringWriter writer = new StringWriter();
  105. underTest.backup(db.getSession(), profile, writer);
  106. assertThat(writer.toString()).isEqualTo("<?xml version='1.0' encoding='UTF-8'?>" +
  107. "<profile><name>" + profile.getName() + "</name>" +
  108. "<language>" + profile.getLanguage() + "</language>" +
  109. "<rules/>" +
  110. "</profile>");
  111. }
  112. @Test
  113. public void restore_backup_on_the_profile_specified_in_backup() {
  114. OrganizationDto organization = db.organizations().insert();
  115. Reader backup = new StringReader(EMPTY_BACKUP);
  116. QProfileRestoreSummary summary = underTest.restore(db.getSession(), backup, organization, null);
  117. assertThat(summary.getProfile().getName()).isEqualTo("foo");
  118. assertThat(summary.getProfile().getLanguage()).isEqualTo("js");
  119. assertThat(reset.calledProfile.getKee()).isEqualTo(summary.getProfile().getKee());
  120. assertThat(reset.calledActivations).isEmpty();
  121. }
  122. @Test
  123. public void restore_backup_on_profile_having_different_name() {
  124. OrganizationDto organization = db.organizations().insert();
  125. Reader backup = new StringReader(EMPTY_BACKUP);
  126. QProfileRestoreSummary summary = underTest.restore(db.getSession(), backup, organization, "bar");
  127. assertThat(summary.getProfile().getName()).isEqualTo("bar");
  128. assertThat(summary.getProfile().getLanguage()).isEqualTo("js");
  129. assertThat(reset.calledProfile.getKee()).isEqualTo(summary.getProfile().getKee());
  130. assertThat(reset.calledActivations).isEmpty();
  131. }
  132. @Test
  133. public void restore_resets_the_activated_rules() {
  134. Integer ruleId = db.rules().insert(RuleKey.of("sonarjs", "s001")).getId();
  135. OrganizationDto organization = db.organizations().insert();
  136. Reader backup = new StringReader("<?xml version='1.0' encoding='UTF-8'?>" +
  137. "<profile><name>foo</name>" +
  138. "<language>js</language>" +
  139. "<rules>" +
  140. "<rule>" +
  141. "<repositoryKey>sonarjs</repositoryKey>" +
  142. "<key>s001</key>" +
  143. "<priority>BLOCKER</priority>" +
  144. "<parameters>" +
  145. "<parameter><key>bar</key><value>baz</value></parameter>" +
  146. "</parameters>" +
  147. "</rule>" +
  148. "</rules>" +
  149. "</profile>");
  150. underTest.restore(db.getSession(), backup, organization, null);
  151. assertThat(reset.calledActivations).hasSize(1);
  152. RuleActivation activation = reset.calledActivations.get(0);
  153. assertThat(activation.getSeverity()).isEqualTo("BLOCKER");
  154. assertThat(activation.getRuleId()).isEqualTo(ruleId);
  155. assertThat(activation.getParameter("bar")).isEqualTo("baz");
  156. }
  157. @Test
  158. public void fail_to_restore_if_bad_xml_format() {
  159. OrganizationDto organization = db.organizations().insert();
  160. try {
  161. underTest.restore(db.getSession(), new StringReader("<rules><rule></rules>"), organization, null);
  162. fail();
  163. } catch (IllegalArgumentException e) {
  164. assertThat(e).hasMessage("Backup XML is not valid. Root element must be <profile>.");
  165. assertThat(reset.calledProfile).isNull();
  166. }
  167. }
  168. @Test
  169. public void fail_to_restore_if_not_xml_backup() {
  170. OrganizationDto organization = db.organizations().insert();
  171. try {
  172. underTest.restore(db.getSession(), new StringReader("foo"), organization, null);
  173. fail();
  174. } catch (IllegalArgumentException e) {
  175. assertThat(reset.calledProfile).isNull();
  176. }
  177. }
  178. @Test
  179. public void fail_to_restore_if_xml_is_not_well_formed() {
  180. expectedException.expect(IllegalArgumentException.class);
  181. expectedException.expectMessage("Fail to restore Quality profile backup, XML document is not well formed");
  182. OrganizationDto organization = db.organizations().insert();
  183. String notWellFormedXml = "<?xml version='1.0' encoding='UTF-8'?><profile><name>\"profil\"</name><language>\"language\"</language><rules/></profile";
  184. underTest.restore(db.getSession(), new StringReader(notWellFormedXml), organization, null);
  185. }
  186. @Test
  187. public void fail_to_restore_if_duplicate_rule() throws Exception {
  188. OrganizationDto organization = db.organizations().insert();
  189. try {
  190. String xml = Resources.toString(getClass().getResource("QProfileBackuperMediumTest/duplicates-xml-backup.xml"), UTF_8);
  191. underTest.restore(db.getSession(), new StringReader(xml), organization, null);
  192. fail();
  193. } catch (IllegalArgumentException e) {
  194. assertThat(e).hasMessage("The quality profile cannot be restored as it contains duplicates for the following rules: xoo:x1, xoo:x2");
  195. assertThat(reset.calledProfile).isNull();
  196. }
  197. }
  198. @Test
  199. public void fail_to_restore_external_rule() {
  200. db.rules().insert(RuleKey.of("sonarjs", "s001"), r -> r.setIsExternal(true)).getId();
  201. OrganizationDto organization = db.organizations().insert();
  202. Reader backup = new StringReader("<?xml version='1.0' encoding='UTF-8'?>" +
  203. "<profile><name>foo</name>" +
  204. "<language>js</language>" +
  205. "<rules>" +
  206. "<rule>" +
  207. "<repositoryKey>sonarjs</repositoryKey>" +
  208. "<key>s001</key>" +
  209. "<priority>BLOCKER</priority>" +
  210. "<parameters>" +
  211. "<parameter><key>bar</key><value>baz</value></parameter>" +
  212. "</parameters>" +
  213. "</rule>" +
  214. "</rules>" +
  215. "</profile>");
  216. expectedException.expect(IllegalArgumentException.class);
  217. expectedException.expectMessage("The quality profile cannot be restored as it contains rules from external rule engines: sonarjs:s001");
  218. underTest.restore(db.getSession(), backup, organization, null);
  219. }
  220. private RuleDefinitionDto createRule() {
  221. return db.rules().insert();
  222. }
  223. private QProfileDto createProfile(RuleDefinitionDto rule) {
  224. return db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(rule.getLanguage()));
  225. }
  226. private ActiveRuleDto activate(QProfileDto profile, RuleDefinitionDto rule) {
  227. return db.qualityProfiles().activateRule(profile, rule);
  228. }
  229. private ActiveRuleDto activate(QProfileDto profile, RuleDefinitionDto rule, RuleParamDto param) {
  230. ActiveRuleDto activeRule = db.qualityProfiles().activateRule(profile, rule);
  231. ActiveRuleParamDto dto = ActiveRuleParamDto.createFor(param)
  232. .setValue("20")
  233. .setActiveRuleId(activeRule.getId());
  234. db.getDbClient().activeRuleDao().insertParam(db.getSession(), activeRule, dto);
  235. return activeRule;
  236. }
  237. private static class DummyReset implements QProfileReset {
  238. private QProfileDto calledProfile;
  239. private List<RuleActivation> calledActivations;
  240. @Override
  241. public BulkChangeResult reset(DbSession dbSession, QProfileDto profile, Collection<RuleActivation> activations) {
  242. this.calledProfile = profile;
  243. this.calledActivations = new ArrayList<>(activations);
  244. return new BulkChangeResult();
  245. }
  246. }
  247. private static class DummyProfileFactory implements QProfileFactory {
  248. @Override
  249. public QProfileDto getOrCreateCustom(DbSession dbSession, OrganizationDto organization, QProfileName key) {
  250. return QualityProfileTesting.newQualityProfileDto()
  251. .setOrganizationUuid(organization.getUuid())
  252. .setLanguage(key.getLanguage())
  253. .setName(key.getName());
  254. }
  255. @Override
  256. public QProfileDto checkAndCreateCustom(DbSession dbSession, OrganizationDto organization, QProfileName name) {
  257. throw new UnsupportedOperationException();
  258. }
  259. @Override
  260. public void delete(DbSession dbSession, Collection<QProfileDto> profiles) {
  261. throw new UnsupportedOperationException();
  262. }
  263. }
  264. }