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.

RegisterRulesTest.java 49KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202
  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.rule;
  21. import com.tngtech.java.junit.dataprovider.DataProvider;
  22. import com.tngtech.java.junit.dataprovider.DataProviderRunner;
  23. import com.tngtech.java.junit.dataprovider.UseDataProvider;
  24. import java.util.Arrays;
  25. import java.util.Date;
  26. import java.util.List;
  27. import java.util.Set;
  28. import java.util.function.Consumer;
  29. import java.util.stream.IntStream;
  30. import org.junit.Before;
  31. import org.junit.Test;
  32. import org.junit.rules.ExpectedException;
  33. import org.junit.runner.RunWith;
  34. import org.sonar.api.resources.Language;
  35. import org.sonar.api.resources.Languages;
  36. import org.sonar.api.rule.RuleKey;
  37. import org.sonar.api.rule.RuleScope;
  38. import org.sonar.api.rule.RuleStatus;
  39. import org.sonar.api.rules.RuleType;
  40. import org.sonar.api.server.debt.DebtRemediationFunction;
  41. import org.sonar.api.server.rule.RulesDefinition;
  42. import org.sonar.api.utils.DateUtils;
  43. import org.sonar.api.utils.System2;
  44. import org.sonar.api.utils.log.LogTester;
  45. import org.sonar.api.utils.log.LoggerLevel;
  46. import org.sonar.core.util.UuidFactory;
  47. import org.sonar.core.util.UuidFactoryFast;
  48. import org.sonar.db.DbClient;
  49. import org.sonar.db.DbSession;
  50. import org.sonar.db.DbTester;
  51. import org.sonar.db.organization.OrganizationDto;
  52. import org.sonar.db.rule.DeprecatedRuleKeyDto;
  53. import org.sonar.db.rule.RuleDefinitionDto;
  54. import org.sonar.db.rule.RuleDto;
  55. import org.sonar.db.rule.RuleDto.Scope;
  56. import org.sonar.db.rule.RuleParamDto;
  57. import org.sonar.db.rule.RuleRepositoryDto;
  58. import org.sonar.server.es.EsTester;
  59. import org.sonar.server.es.SearchIdResult;
  60. import org.sonar.server.es.SearchOptions;
  61. import org.sonar.server.organization.OrganizationFlags;
  62. import org.sonar.server.organization.TestOrganizationFlags;
  63. import org.sonar.server.plugins.ServerPluginRepository;
  64. import org.sonar.server.qualityprofile.QProfileRules;
  65. import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
  66. import org.sonar.server.rule.index.RuleIndex;
  67. import org.sonar.server.rule.index.RuleIndexDefinition;
  68. import org.sonar.server.rule.index.RuleIndexer;
  69. import org.sonar.server.rule.index.RuleQuery;
  70. import static com.google.common.collect.Sets.newHashSet;
  71. import static java.lang.String.valueOf;
  72. import static java.util.Collections.singletonList;
  73. import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
  74. import static org.assertj.core.api.Assertions.assertThat;
  75. import static org.mockito.ArgumentMatchers.any;
  76. import static org.mockito.Mockito.mock;
  77. import static org.mockito.Mockito.reset;
  78. import static org.mockito.Mockito.verify;
  79. import static org.mockito.Mockito.when;
  80. import static org.sonar.api.rule.RuleStatus.READY;
  81. import static org.sonar.api.rule.RuleStatus.REMOVED;
  82. import static org.sonar.api.rule.Severity.BLOCKER;
  83. import static org.sonar.api.rule.Severity.INFO;
  84. import static org.sonar.api.server.rule.RulesDefinition.NewRepository;
  85. import static org.sonar.api.server.rule.RulesDefinition.NewRule;
  86. @RunWith(DataProviderRunner.class)
  87. public class RegisterRulesTest {
  88. private static final String FAKE_PLUGIN_KEY = "unittest";
  89. private static final Date DATE1 = DateUtils.parseDateTime("2014-01-01T19:10:03+0100");
  90. private static final Date DATE2 = DateUtils.parseDateTime("2014-02-01T12:10:03+0100");
  91. private static final Date DATE3 = DateUtils.parseDateTime("2014-03-01T12:10:03+0100");
  92. private static final RuleKey EXTERNAL_RULE_KEY1 = RuleKey.of("external_eslint", "rule1");
  93. private static final RuleKey EXTERNAL_HOTSPOT_RULE_KEY = RuleKey.of("external_eslint", "hotspot");
  94. private static final RuleKey RULE_KEY1 = RuleKey.of("fake", "rule1");
  95. private static final RuleKey RULE_KEY2 = RuleKey.of("fake", "rule2");
  96. private static final RuleKey RULE_KEY3 = RuleKey.of("fake", "rule3");
  97. private static final RuleKey HOTSPOT_RULE_KEY = RuleKey.of("fake", "hotspot");
  98. private System2 system = mock(System2.class);
  99. @org.junit.Rule
  100. public ExpectedException expectedException = ExpectedException.none();
  101. @org.junit.Rule
  102. public DbTester db = DbTester.create(system);
  103. @org.junit.Rule
  104. public EsTester es = EsTester.create();
  105. @org.junit.Rule
  106. public LogTester logTester = new LogTester();
  107. private QProfileRules qProfileRules = mock(QProfileRules.class);
  108. private WebServerRuleFinder webServerRuleFinder = mock(WebServerRuleFinder.class);
  109. private DbClient dbClient = db.getDbClient();
  110. private RuleIndexer ruleIndexer;
  111. private ActiveRuleIndexer activeRuleIndexer;
  112. private RuleIndex ruleIndex;
  113. private OrganizationDto defaultOrganization;
  114. private OrganizationFlags organizationFlags = TestOrganizationFlags.standalone();
  115. private UuidFactory uuidFactory = UuidFactoryFast.getInstance();
  116. @Before
  117. public void before() {
  118. when(system.now()).thenReturn(DATE1.getTime());
  119. ruleIndexer = new RuleIndexer(es.client(), dbClient);
  120. ruleIndex = new RuleIndex(es.client(), system);
  121. activeRuleIndexer = new ActiveRuleIndexer(dbClient, es.client());
  122. defaultOrganization = db.getDefaultOrganization();
  123. }
  124. @Test
  125. public void insert_new_rules() {
  126. execute(new FakeRepositoryV1());
  127. // verify db
  128. assertThat(dbClient.ruleDao().selectAllDefinitions(db.getSession())).hasSize(3);
  129. RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), db.getDefaultOrganization(), RULE_KEY1);
  130. assertThat(rule1.getName()).isEqualTo("One");
  131. assertThat(rule1.getDescription()).isEqualTo("Description of One");
  132. assertThat(rule1.getSeverityString()).isEqualTo(BLOCKER);
  133. assertThat(rule1.getTags()).isEmpty();
  134. assertThat(rule1.getSystemTags()).containsOnly("tag1", "tag2", "tag3");
  135. assertThat(rule1.getConfigKey()).isEqualTo("config1");
  136. assertThat(rule1.getStatus()).isEqualTo(RuleStatus.BETA);
  137. assertThat(rule1.getCreatedAt()).isEqualTo(DATE1.getTime());
  138. assertThat(rule1.getScope()).isEqualTo(Scope.ALL);
  139. assertThat(rule1.getUpdatedAt()).isEqualTo(DATE1.getTime());
  140. assertThat(rule1.getDefRemediationFunction()).isEqualTo(DebtRemediationFunction.Type.LINEAR_OFFSET.name());
  141. assertThat(rule1.getDefRemediationGapMultiplier()).isEqualTo("5d");
  142. assertThat(rule1.getDefRemediationBaseEffort()).isEqualTo("10h");
  143. assertThat(rule1.getType()).isEqualTo(RuleType.CODE_SMELL.getDbConstant());
  144. assertThat(rule1.getPluginKey()).isEqualTo(FAKE_PLUGIN_KEY);
  145. assertThat(rule1.isExternal()).isFalse();
  146. assertThat(rule1.isAdHoc()).isFalse();
  147. RuleDto hotspotRule = dbClient.ruleDao().selectOrFailByKey(db.getSession(), db.getDefaultOrganization(), HOTSPOT_RULE_KEY);
  148. assertThat(hotspotRule.getName()).isEqualTo("Hotspot");
  149. assertThat(hotspotRule.getDescription()).isEqualTo("Minimal hotspot");
  150. assertThat(hotspotRule.getCreatedAt()).isEqualTo(DATE1.getTime());
  151. assertThat(hotspotRule.getUpdatedAt()).isEqualTo(DATE1.getTime());
  152. assertThat(hotspotRule.getType()).isEqualTo(RuleType.SECURITY_HOTSPOT.getDbConstant());
  153. assertThat(hotspotRule.getSecurityStandards()).containsExactly("cwe:1", "cwe:123", "cwe:863", "owaspTop10:a1", "owaspTop10:a3");
  154. List<RuleParamDto> params = dbClient.ruleDao().selectRuleParamsByRuleKey(db.getSession(), RULE_KEY1);
  155. assertThat(params).hasSize(2);
  156. RuleParamDto param = getParam(params, "param1");
  157. assertThat(param.getDescription()).isEqualTo("parameter one");
  158. assertThat(param.getDefaultValue()).isEqualTo("default1");
  159. // verify index
  160. RuleDto rule2 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), db.getDefaultOrganization(), RULE_KEY2);
  161. assertThat(ruleIndex.search(new RuleQuery(), new SearchOptions()).getIds()).containsOnly(rule1.getId(), rule2.getId(), hotspotRule.getId());
  162. // verify repositories
  163. assertThat(dbClient.ruleRepositoryDao().selectAll(db.getSession())).extracting(RuleRepositoryDto::getKey).containsOnly("fake");
  164. }
  165. @Test
  166. public void insert_new_external_rule() {
  167. execute(new ExternalRuleRepository());
  168. // verify db
  169. assertThat(dbClient.ruleDao().selectAllDefinitions(db.getSession())).hasSize(2);
  170. RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), db.getDefaultOrganization(), EXTERNAL_RULE_KEY1);
  171. assertThat(rule1.getName()).isEqualTo("One");
  172. assertThat(rule1.getDescription()).isEqualTo("Description of One");
  173. assertThat(rule1.getSeverityString()).isEqualTo(BLOCKER);
  174. assertThat(rule1.getTags()).isEmpty();
  175. assertThat(rule1.getSystemTags()).containsOnly("tag1", "tag2", "tag3");
  176. assertThat(rule1.getConfigKey()).isEqualTo("config1");
  177. assertThat(rule1.getStatus()).isEqualTo(RuleStatus.BETA);
  178. assertThat(rule1.getCreatedAt()).isEqualTo(DATE1.getTime());
  179. assertThat(rule1.getScope()).isEqualTo(Scope.ALL);
  180. assertThat(rule1.getUpdatedAt()).isEqualTo(DATE1.getTime());
  181. assertThat(rule1.getDefRemediationFunction()).isNull();
  182. assertThat(rule1.getDefRemediationGapMultiplier()).isNull();
  183. assertThat(rule1.getDefRemediationBaseEffort()).isNull();
  184. assertThat(rule1.getType()).isEqualTo(RuleType.CODE_SMELL.getDbConstant());
  185. assertThat(rule1.getPluginKey()).isEqualTo(FAKE_PLUGIN_KEY);
  186. assertThat(rule1.isExternal()).isTrue();
  187. assertThat(rule1.isAdHoc()).isFalse();
  188. RuleDto hotspotRule = dbClient.ruleDao().selectOrFailByKey(db.getSession(), db.getDefaultOrganization(), EXTERNAL_HOTSPOT_RULE_KEY);
  189. assertThat(hotspotRule.getName()).isEqualTo("Hotspot");
  190. assertThat(hotspotRule.getDescription()).isEqualTo("Minimal hotspot");
  191. assertThat(hotspotRule.getCreatedAt()).isEqualTo(DATE1.getTime());
  192. assertThat(hotspotRule.getUpdatedAt()).isEqualTo(DATE1.getTime());
  193. assertThat(hotspotRule.getType()).isEqualTo(RuleType.SECURITY_HOTSPOT.getDbConstant());
  194. assertThat(hotspotRule.getSecurityStandards()).containsExactly("cwe:1", "cwe:123", "cwe:863", "owaspTop10:a1", "owaspTop10:a3");
  195. }
  196. @Test
  197. public void insert_then_remove_rule() {
  198. String ruleKey = randomAlphanumeric(5);
  199. // register one rule
  200. execute(context -> {
  201. NewRepository repo = context.createRepository("fake", "java");
  202. repo.createRule(ruleKey)
  203. .setName(randomAlphanumeric(5))
  204. .setHtmlDescription(randomAlphanumeric(20));
  205. repo.done();
  206. });
  207. // verify db
  208. List<RuleDefinitionDto> rules = dbClient.ruleDao().selectAllDefinitions(db.getSession());
  209. assertThat(rules)
  210. .extracting(RuleDefinitionDto::getKey)
  211. .extracting(RuleKey::rule)
  212. .containsExactly(ruleKey);
  213. RuleDefinitionDto rule = rules.iterator().next();
  214. // verify index
  215. assertThat(ruleIndex.search(new RuleQuery(), new SearchOptions()).getIds())
  216. .containsExactly(rule.getId());
  217. // register no rule
  218. execute(context -> context.createRepository("fake", "java").done());
  219. // verify db
  220. assertThat(dbClient.ruleDao().selectAllDefinitions(db.getSession()))
  221. .extracting(RuleDefinitionDto::getKey)
  222. .extracting(RuleKey::rule)
  223. .containsExactly(ruleKey);
  224. assertThat(dbClient.ruleDao().selectAllDefinitions(db.getSession()))
  225. .extracting(RuleDefinitionDto::getStatus)
  226. .containsExactly(REMOVED);
  227. // verify index
  228. assertThat(ruleIndex.search(new RuleQuery(), new SearchOptions()).getIds())
  229. .isEmpty();
  230. }
  231. @Test
  232. public void mass_insert_then_remove_rule() {
  233. int numberOfRules = 5000;
  234. // register many rules
  235. execute(context -> {
  236. NewRepository repo = context.createRepository("fake", "java");
  237. IntStream.range(0, numberOfRules)
  238. .mapToObj(i -> "rule-" + i)
  239. .forEach(ruleKey -> repo.createRule(ruleKey)
  240. .setName(randomAlphanumeric(20))
  241. .setHtmlDescription(randomAlphanumeric(20)));
  242. repo.done();
  243. });
  244. // verify db
  245. assertThat(dbClient.ruleDao().selectAllDefinitions(db.getSession()))
  246. .hasSize(numberOfRules)
  247. .extracting(RuleDefinitionDto::getStatus)
  248. .containsOnly(READY);
  249. // verify index
  250. assertThat(es.countDocuments(RuleIndexDefinition.TYPE_RULE)).isEqualTo(numberOfRules);
  251. assertThat(ruleIndex.search(new RuleQuery(), new SearchOptions()).getIds())
  252. .isNotEmpty();
  253. // register no rule
  254. execute(context -> context.createRepository("fake", "java").done());
  255. // verify db
  256. assertThat(dbClient.ruleDao().selectAllDefinitions(db.getSession()))
  257. .hasSize(numberOfRules)
  258. .extracting(RuleDefinitionDto::getStatus)
  259. .containsOnly(REMOVED);
  260. // verify index (documents are still in the index, but all are removed)
  261. assertThat(es.countDocuments(RuleIndexDefinition.TYPE_RULE)).isEqualTo(numberOfRules);
  262. assertThat(ruleIndex.search(new RuleQuery(), new SearchOptions()).getIds())
  263. .isEmpty();
  264. }
  265. @Test
  266. public void delete_repositories_that_have_been_uninstalled() {
  267. RuleRepositoryDto repository = new RuleRepositoryDto("findbugs", "java", "Findbugs");
  268. DbSession dbSession = db.getSession();
  269. db.getDbClient().ruleRepositoryDao().insertOrUpdate(dbSession, singletonList(repository));
  270. dbSession.commit();
  271. execute(new FakeRepositoryV1());
  272. assertThat(db.getDbClient().ruleRepositoryDao().selectAll(dbSession)).extracting(RuleRepositoryDto::getKey).containsOnly("fake");
  273. }
  274. @Test
  275. public void update_and_remove_rules_on_changes() {
  276. execute(new FakeRepositoryV1());
  277. assertThat(dbClient.ruleDao().selectAllDefinitions(db.getSession())).hasSize(3);
  278. RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY1);
  279. RuleDto rule2 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY2);
  280. RuleDto hotspotRule = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, HOTSPOT_RULE_KEY);
  281. assertThat(es.getIds(RuleIndexDefinition.TYPE_RULE)).containsOnly(valueOf(rule1.getId()), valueOf(rule2.getId()), valueOf(hotspotRule.getId()));
  282. // user adds tags and sets markdown note
  283. rule1.setTags(newHashSet("usertag1", "usertag2"));
  284. rule1.setNoteData("user *note*");
  285. rule1.setNoteUserUuid("marius");
  286. dbClient.ruleDao().insertOrUpdate(db.getSession(), rule1.getMetadata());
  287. db.getSession().commit();
  288. when(system.now()).thenReturn(DATE2.getTime());
  289. execute(new FakeRepositoryV2());
  290. // rule1 has been updated
  291. rule1 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY1);
  292. assertThat(rule1.getName()).isEqualTo("One v2");
  293. assertThat(rule1.getDescription()).isEqualTo("Description of One v2");
  294. assertThat(rule1.getSeverityString()).isEqualTo(INFO);
  295. assertThat(rule1.getTags()).containsOnly("usertag1", "usertag2");
  296. assertThat(rule1.getSystemTags()).containsOnly("tag1", "tag4");
  297. assertThat(rule1.getConfigKey()).isEqualTo("config1 v2");
  298. assertThat(rule1.getNoteData()).isEqualTo("user *note*");
  299. assertThat(rule1.getNoteUserUuid()).isEqualTo("marius");
  300. assertThat(rule1.getStatus()).isEqualTo(READY);
  301. assertThat(rule1.getType()).isEqualTo(RuleType.BUG.getDbConstant());
  302. assertThat(rule1.getCreatedAt()).isEqualTo(DATE1.getTime());
  303. assertThat(rule1.getUpdatedAt()).isEqualTo(DATE2.getTime());
  304. List<RuleParamDto> params = dbClient.ruleDao().selectRuleParamsByRuleKey(db.getSession(), RULE_KEY1);
  305. assertThat(params).hasSize(2);
  306. RuleParamDto param = getParam(params, "param1");
  307. assertThat(param.getDescription()).isEqualTo("parameter one v2");
  308. assertThat(param.getDefaultValue()).isEqualTo("default1 v2");
  309. // rule2 has been removed -> status set to REMOVED but db row is not deleted
  310. rule2 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY2);
  311. assertThat(rule2.getStatus()).isEqualTo(REMOVED);
  312. assertThat(rule2.getUpdatedAt()).isEqualTo(DATE2.getTime());
  313. // rule3 has been created
  314. RuleDto rule3 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY3);
  315. assertThat(rule3).isNotNull();
  316. assertThat(rule3.getStatus()).isEqualTo(READY);
  317. // verify index
  318. assertThat(ruleIndex.search(new RuleQuery(), new SearchOptions()).getIds()).containsOnly(rule1.getId(), rule3.getId());
  319. // verify repositories
  320. assertThat(dbClient.ruleRepositoryDao().selectAll(db.getSession())).extracting(RuleRepositoryDto::getKey).containsOnly("fake");
  321. }
  322. @Test
  323. public void add_new_tag() {
  324. execute((RulesDefinition) context -> {
  325. NewRepository repo = context.createRepository("fake", "java");
  326. repo.createRule("rule1")
  327. .setName("Rule One")
  328. .setHtmlDescription("Description of Rule One")
  329. .setTags("tag1");
  330. repo.done();
  331. });
  332. OrganizationDto defaultOrganization = db.getDefaultOrganization();
  333. RuleDto rule = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY1);
  334. assertThat(rule.getSystemTags()).containsOnly("tag1");
  335. execute((RulesDefinition) context -> {
  336. NewRepository repo = context.createRepository("fake", "java");
  337. repo.createRule("rule1")
  338. .setName("Rule One")
  339. .setHtmlDescription("Description of Rule One")
  340. .setTags("tag1", "tag2");
  341. repo.done();
  342. });
  343. rule = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY1);
  344. assertThat(rule.getSystemTags()).containsOnly("tag1", "tag2");
  345. }
  346. @Test
  347. public void add_new_security_standards() {
  348. execute((RulesDefinition) context -> {
  349. NewRepository repo = context.createRepository("fake", "java");
  350. repo.createRule("rule1")
  351. .setName("Rule One")
  352. .setHtmlDescription("Description of Rule One")
  353. .addOwaspTop10(RulesDefinition.OwaspTop10.A1)
  354. .addCwe(123);
  355. repo.done();
  356. });
  357. OrganizationDto defaultOrganization = db.getDefaultOrganization();
  358. RuleDto rule = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY1);
  359. assertThat(rule.getSecurityStandards()).containsOnly("cwe:123", "owaspTop10:a1");
  360. execute((RulesDefinition) context -> {
  361. NewRepository repo = context.createRepository("fake", "java");
  362. repo.createRule("rule1")
  363. .setName("Rule One")
  364. .setHtmlDescription("Description of Rule One")
  365. .addOwaspTop10(RulesDefinition.OwaspTop10.A1, RulesDefinition.OwaspTop10.A3)
  366. .addCwe(1, 123, 863);
  367. repo.done();
  368. });
  369. rule = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY1);
  370. assertThat(rule.getSecurityStandards()).containsOnly("cwe:1", "cwe:123", "cwe:863", "owaspTop10:a1", "owaspTop10:a3");
  371. }
  372. @Test
  373. public void update_only_rule_name() {
  374. when(system.now()).thenReturn(DATE1.getTime());
  375. execute((RulesDefinition) context -> {
  376. NewRepository repo = context.createRepository("fake", "java");
  377. repo.createRule("rule")
  378. .setName("Name1")
  379. .setHtmlDescription("Description");
  380. repo.done();
  381. });
  382. when(system.now()).thenReturn(DATE2.getTime());
  383. execute((RulesDefinition) context -> {
  384. NewRepository repo = context.createRepository("fake", "java");
  385. repo.createRule("rule")
  386. .setName("Name2")
  387. .setHtmlDescription("Description");
  388. repo.done();
  389. });
  390. // rule1 has been updated
  391. RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RuleKey.of("fake", "rule"));
  392. assertThat(rule1.getName()).isEqualTo("Name2");
  393. assertThat(rule1.getDescription()).isEqualTo("Description");
  394. assertThat(ruleIndex.search(new RuleQuery().setQueryText("Name2"), new SearchOptions()).getTotal()).isEqualTo(1);
  395. assertThat(ruleIndex.search(new RuleQuery().setQueryText("Name1"), new SearchOptions()).getTotal()).isEqualTo(0);
  396. }
  397. @Test
  398. public void update_if_rule_key_renamed_and_deprecated_key_declared() {
  399. String ruleKey1 = "rule1";
  400. String ruleKey2 = "rule2";
  401. String repository = "fake";
  402. when(system.now()).thenReturn(DATE1.getTime());
  403. execute((RulesDefinition) context -> {
  404. RulesDefinition.NewRepository repo = context.createRepository(repository, "java");
  405. repo.createRule(ruleKey1)
  406. .setName("Name1")
  407. .setHtmlDescription("Description");
  408. repo.done();
  409. });
  410. RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RuleKey.of(repository, ruleKey1));
  411. SearchIdResult<Integer> searchRule1 = ruleIndex.search(new RuleQuery().setQueryText("Name1"), new SearchOptions());
  412. assertThat(searchRule1.getIds()).containsOnly(rule1.getId());
  413. assertThat(searchRule1.getTotal()).isEqualTo(1);
  414. when(system.now()).thenReturn(DATE2.getTime());
  415. execute((RulesDefinition) context -> {
  416. RulesDefinition.NewRepository repo = context.createRepository(repository, "java");
  417. repo.createRule(ruleKey2)
  418. .setName("Name2")
  419. .setHtmlDescription("Description")
  420. .addDeprecatedRuleKey(repository, ruleKey1);
  421. repo.done();
  422. });
  423. // rule2 is actually rule1
  424. RuleDto rule2 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RuleKey.of(repository, ruleKey2));
  425. assertThat(rule2.getId()).isEqualTo(rule1.getId());
  426. assertThat(rule2.getName()).isEqualTo("Name2");
  427. assertThat(rule2.getDescription()).isEqualTo(rule1.getDescription());
  428. SearchIdResult<Integer> searchRule2 = ruleIndex.search(new RuleQuery().setQueryText("Name2"), new SearchOptions());
  429. assertThat(searchRule2.getIds()).containsOnly(rule2.getId());
  430. assertThat(searchRule2.getTotal()).isEqualTo(1);
  431. assertThat(ruleIndex.search(new RuleQuery().setQueryText("Name1"), new SearchOptions()).getTotal()).isEqualTo(0);
  432. }
  433. @Test
  434. public void update_if_repository_changed_and_deprecated_key_declared() {
  435. String ruleKey = "rule";
  436. String repository1 = "fake1";
  437. String repository2 = "fake2";
  438. when(system.now()).thenReturn(DATE1.getTime());
  439. execute((RulesDefinition) context -> {
  440. RulesDefinition.NewRepository repo = context.createRepository(repository1, "java");
  441. repo.createRule(ruleKey)
  442. .setName("Name1")
  443. .setHtmlDescription("Description");
  444. repo.done();
  445. });
  446. RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RuleKey.of(repository1, ruleKey));
  447. SearchIdResult<Integer> searchRule1 = ruleIndex.search(new RuleQuery().setQueryText("Name1"), new SearchOptions());
  448. assertThat(searchRule1.getIds()).containsOnly(rule1.getId());
  449. assertThat(searchRule1.getTotal()).isEqualTo(1);
  450. when(system.now()).thenReturn(DATE2.getTime());
  451. execute((RulesDefinition) context -> {
  452. RulesDefinition.NewRepository repo = context.createRepository(repository2, "java");
  453. repo.createRule(ruleKey)
  454. .setName("Name2")
  455. .setHtmlDescription("Description")
  456. .addDeprecatedRuleKey(repository1, ruleKey);
  457. repo.done();
  458. });
  459. // rule2 is actually rule1
  460. RuleDto rule2 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RuleKey.of(repository2, ruleKey));
  461. assertThat(rule2.getId()).isEqualTo(rule1.getId());
  462. assertThat(rule2.getName()).isEqualTo("Name2");
  463. assertThat(rule2.getDescription()).isEqualTo(rule1.getDescription());
  464. SearchIdResult<Integer> searchRule2 = ruleIndex.search(new RuleQuery().setQueryText("Name2"), new SearchOptions());
  465. assertThat(searchRule2.getIds()).containsOnly(rule2.getId());
  466. assertThat(searchRule2.getTotal()).isEqualTo(1);
  467. assertThat(ruleIndex.search(new RuleQuery().setQueryText("Name1"), new SearchOptions()).getTotal()).isEqualTo(0);
  468. }
  469. @Test
  470. @UseDataProvider("allRenamingCases")
  471. public void update_if_only_renamed_and_deprecated_key_declared(String ruleKey1, String repo1, String ruleKey2, String repo2) {
  472. String name = "Name1";
  473. String description = "Description";
  474. when(system.now()).thenReturn(DATE1.getTime());
  475. execute((RulesDefinition) context -> {
  476. RulesDefinition.NewRepository repo = context.createRepository(repo1, "java");
  477. repo.createRule(ruleKey1)
  478. .setName(name)
  479. .setHtmlDescription(description);
  480. repo.done();
  481. });
  482. RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RuleKey.of(repo1, ruleKey1));
  483. assertThat(ruleIndex.search(new RuleQuery().setQueryText(name), new SearchOptions()).getIds())
  484. .containsOnly(rule1.getId());
  485. when(system.now()).thenReturn(DATE2.getTime());
  486. execute((RulesDefinition) context -> {
  487. RulesDefinition.NewRepository repo = context.createRepository(repo2, "java");
  488. repo.createRule(ruleKey2)
  489. .setName(name)
  490. .setHtmlDescription(description)
  491. .addDeprecatedRuleKey(repo1, ruleKey1);
  492. repo.done();
  493. });
  494. // rule2 is actually rule1
  495. RuleDto rule2 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RuleKey.of(repo2, ruleKey2));
  496. assertThat(rule2.getId()).isEqualTo(rule1.getId());
  497. assertThat(rule2.getName()).isEqualTo(rule1.getName());
  498. assertThat(rule2.getDescription()).isEqualTo(rule1.getDescription());
  499. assertThat(ruleIndex.search(new RuleQuery().setQueryText(name), new SearchOptions()).getIds())
  500. .containsOnly(rule2.getId());
  501. }
  502. @DataProvider
  503. public static Object[][] allRenamingCases() {
  504. return new Object[][] {
  505. {"repo1", "rule1", "repo1", "rule2"},
  506. {"repo1", "rule1", "repo2", "rule1"},
  507. {"repo1", "rule1", "repo2", "rule2"},
  508. };
  509. }
  510. @Test
  511. public void update_if_repository_and_key_changed_and_deprecated_key_declared_among_others() {
  512. String ruleKey1 = "rule1";
  513. String ruleKey2 = "rule2";
  514. String repository1 = "fake1";
  515. String repository2 = "fake2";
  516. when(system.now()).thenReturn(DATE1.getTime());
  517. execute((RulesDefinition) context -> {
  518. RulesDefinition.NewRepository repo = context.createRepository(repository1, "java");
  519. repo.createRule(ruleKey1)
  520. .setName("Name1")
  521. .setHtmlDescription("Description");
  522. repo.done();
  523. });
  524. RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RuleKey.of(repository1, ruleKey1));
  525. assertThat(ruleIndex.search(new RuleQuery().setQueryText("Name1"), new SearchOptions()).getIds())
  526. .containsOnly(rule1.getId());
  527. when(system.now()).thenReturn(DATE2.getTime());
  528. execute((RulesDefinition) context -> {
  529. RulesDefinition.NewRepository repo = context.createRepository(repository2, "java");
  530. repo.createRule(ruleKey2)
  531. .setName("Name2")
  532. .setHtmlDescription("Description")
  533. .addDeprecatedRuleKey("foo", "bar")
  534. .addDeprecatedRuleKey(repository1, ruleKey1)
  535. .addDeprecatedRuleKey("some", "noise");
  536. repo.done();
  537. });
  538. // rule2 is actually rule1
  539. RuleDto rule2 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RuleKey.of(repository2, ruleKey2));
  540. assertThat(rule2.getId()).isEqualTo(rule1.getId());
  541. assertThat(ruleIndex.search(new RuleQuery().setQueryText("Name2"), new SearchOptions()).getIds())
  542. .containsOnly(rule1.getId());
  543. }
  544. @Test
  545. public void update_only_rule_description() {
  546. when(system.now()).thenReturn(DATE1.getTime());
  547. execute((RulesDefinition) context -> {
  548. NewRepository repo = context.createRepository("fake", "java");
  549. repo.createRule("rule")
  550. .setName("Name")
  551. .setHtmlDescription("Desc1");
  552. repo.done();
  553. });
  554. when(system.now()).thenReturn(DATE2.getTime());
  555. execute((RulesDefinition) context -> {
  556. NewRepository repo = context.createRepository("fake", "java");
  557. repo.createRule("rule")
  558. .setName("Name")
  559. .setHtmlDescription("Desc2");
  560. repo.done();
  561. });
  562. // rule1 has been updated
  563. RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RuleKey.of("fake", "rule"));
  564. assertThat(rule1.getName()).isEqualTo("Name");
  565. assertThat(rule1.getDescription()).isEqualTo("Desc2");
  566. assertThat(ruleIndex.search(new RuleQuery().setQueryText("Desc2"), new SearchOptions()).getTotal()).isEqualTo(1);
  567. assertThat(ruleIndex.search(new RuleQuery().setQueryText("Desc1"), new SearchOptions()).getTotal()).isEqualTo(0);
  568. }
  569. @Test
  570. public void rule_previously_created_as_adhoc_becomes_none_adhoc() {
  571. RuleDefinitionDto rule = db.rules().insert(r -> r.setRepositoryKey("external_fake").setIsExternal(true).setIsAdHoc(true));
  572. when(system.now()).thenReturn(DATE2.getTime());
  573. execute((RulesDefinition) context -> {
  574. NewRepository repo = context.createExternalRepository("fake", rule.getLanguage());
  575. repo.createRule(rule.getRuleKey())
  576. .setName(rule.getName())
  577. .setHtmlDescription(rule.getDescription());
  578. repo.done();
  579. });
  580. RuleDto reloaded = dbClient.ruleDao().selectByKey(db.getSession(), defaultOrganization.getUuid(), rule.getKey()).get();
  581. assertThat(reloaded.isAdHoc()).isFalse();
  582. }
  583. @Test
  584. public void remove_no_more_defined_external_rule() {
  585. RuleDefinitionDto rule = db.rules().insert(r -> r.setRepositoryKey("external_fake")
  586. .setStatus(READY)
  587. .setIsExternal(true)
  588. .setIsAdHoc(false));
  589. execute();
  590. RuleDto reloaded = dbClient.ruleDao().selectByKey(db.getSession(), defaultOrganization.getUuid(), rule.getKey()).get();
  591. assertThat(reloaded.getStatus()).isEqualTo(REMOVED);
  592. }
  593. @Test
  594. public void do_not_remove_no_more_defined_ad_hoc_rule() {
  595. RuleDefinitionDto rule = db.rules().insert(r -> r.setRepositoryKey("external_fake")
  596. .setStatus(READY)
  597. .setIsExternal(true)
  598. .setIsAdHoc(true));
  599. execute();
  600. RuleDto reloaded = dbClient.ruleDao().selectByKey(db.getSession(), defaultOrganization.getUuid(), rule.getKey()).get();
  601. assertThat(reloaded.getStatus()).isEqualTo(READY);
  602. }
  603. @Test
  604. public void disable_then_enable_rule() {
  605. // Install rule
  606. when(system.now()).thenReturn(DATE1.getTime());
  607. execute(new FakeRepositoryV1());
  608. // Uninstall rule
  609. when(system.now()).thenReturn(DATE2.getTime());
  610. execute();
  611. RuleDto rule = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY1);
  612. assertThat(rule.getStatus()).isEqualTo(REMOVED);
  613. assertThat(ruleIndex.search(new RuleQuery().setKey(RULE_KEY1.toString()), new SearchOptions()).getTotal()).isEqualTo(0);
  614. // Re-install rule
  615. when(system.now()).thenReturn(DATE3.getTime());
  616. execute(new FakeRepositoryV1());
  617. rule = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY1);
  618. assertThat(rule.getStatus()).isEqualTo(RuleStatus.BETA);
  619. assertThat(ruleIndex.search(new RuleQuery().setKey(RULE_KEY1.toString()), new SearchOptions()).getTotal()).isEqualTo(1);
  620. }
  621. @Test
  622. public void do_not_update_rules_when_no_changes() {
  623. execute(new FakeRepositoryV1());
  624. assertThat(dbClient.ruleDao().selectAllDefinitions(db.getSession())).hasSize(3);
  625. when(system.now()).thenReturn(DATE2.getTime());
  626. execute(new FakeRepositoryV1());
  627. RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY1);
  628. assertThat(rule1.getCreatedAt()).isEqualTo(DATE1.getTime());
  629. assertThat(rule1.getUpdatedAt()).isEqualTo(DATE1.getTime());
  630. }
  631. @Test
  632. public void do_not_update_already_removed_rules() {
  633. execute(new FakeRepositoryV1());
  634. assertThat(dbClient.ruleDao().selectAllDefinitions(db.getSession())).hasSize(3);
  635. RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY1);
  636. RuleDto rule2 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY2);
  637. RuleDto hotspotRule = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, HOTSPOT_RULE_KEY);
  638. assertThat(es.getIds(RuleIndexDefinition.TYPE_RULE)).containsOnly(valueOf(rule1.getId()), valueOf(rule2.getId()), valueOf(hotspotRule.getId()));
  639. assertThat(rule2.getStatus()).isEqualTo(READY);
  640. when(system.now()).thenReturn(DATE2.getTime());
  641. execute(new FakeRepositoryV2());
  642. // On MySQL, need to update a rule otherwise rule2 will be seen as READY, but why ???
  643. dbClient.ruleDao().update(db.getSession(), rule1.getDefinition());
  644. db.getSession().commit();
  645. // rule2 is removed
  646. rule2 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY2);
  647. RuleDto rule3 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY3);
  648. assertThat(rule2.getStatus()).isEqualTo(REMOVED);
  649. assertThat(ruleIndex.search(new RuleQuery(), new SearchOptions()).getIds()).containsOnly(rule1.getId(), rule3.getId());
  650. when(system.now()).thenReturn(DATE3.getTime());
  651. execute(new FakeRepositoryV2());
  652. db.getSession().commit();
  653. // -> rule2 is still removed, but not update at DATE3
  654. rule2 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY2);
  655. assertThat(rule2.getStatus()).isEqualTo(REMOVED);
  656. assertThat(rule2.getUpdatedAt()).isEqualTo(DATE2.getTime());
  657. assertThat(ruleIndex.search(new RuleQuery(), new SearchOptions()).getIds()).containsOnly(rule1.getId(), rule3.getId());
  658. }
  659. @Test
  660. public void mass_insert() {
  661. execute(new BigRepository());
  662. assertThat(db.countRowsOfTable("rules")).isEqualTo(BigRepository.SIZE);
  663. assertThat(db.countRowsOfTable("rules_parameters")).isEqualTo(BigRepository.SIZE * 20);
  664. assertThat(es.getIds(RuleIndexDefinition.TYPE_RULE)).hasSize(BigRepository.SIZE);
  665. }
  666. @Test
  667. public void manage_repository_extensions() {
  668. execute(new FindbugsRepository(), new FbContribRepository());
  669. List<RuleDefinitionDto> rules = dbClient.ruleDao().selectAllDefinitions(db.getSession());
  670. assertThat(rules).hasSize(2);
  671. for (RuleDefinitionDto rule : rules) {
  672. assertThat(rule.getRepositoryKey()).isEqualTo("findbugs");
  673. }
  674. }
  675. @Test
  676. public void remove_system_tags_when_plugin_does_not_provide_any() {
  677. // Rule already exists in DB, with some system tags
  678. dbClient.ruleDao().insert(db.getSession(), new RuleDefinitionDto()
  679. .setRuleKey("rule1")
  680. .setRepositoryKey("findbugs")
  681. .setName("Rule One")
  682. .setScope(Scope.ALL)
  683. .setDescription("Rule one description")
  684. .setDescriptionFormat(RuleDto.Format.HTML)
  685. .setSystemTags(newHashSet("tag1", "tag2")));
  686. db.getSession().commit();
  687. // Synchronize rule without tag
  688. execute(new FindbugsRepository());
  689. List<RuleDefinitionDto> rules = dbClient.ruleDao().selectAllDefinitions(db.getSession());
  690. assertThat(rules).hasSize(1);
  691. RuleDefinitionDto result = rules.get(0);
  692. assertThat(result.getKey()).isEqualTo(RuleKey.of("findbugs", "rule1"));
  693. assertThat(result.getSystemTags()).isEmpty();
  694. }
  695. @Test
  696. public void ignore_template_rules_if_organizations_are_enabled() {
  697. organizationFlags.enable(db.getSession());
  698. execute(new RepositoryWithOneTemplateRule());
  699. List<RuleDefinitionDto> rules = dbClient.ruleDao().selectAllDefinitions(db.getSession());
  700. assertThat(rules).hasSize(0);
  701. }
  702. @Test
  703. public void log_ignored_template_rules_if_organizations_are_enabled() {
  704. organizationFlags.enable(db.getSession());
  705. execute(new RepositoryWithOneTemplateRule());
  706. assertThat(logTester.logs(LoggerLevel.INFO)).contains("Template rule test:rule1 will not be imported, because organizations are enabled.");
  707. }
  708. @Test
  709. public void rules_that_deprecate_previous_rule_must_be_recorded() {
  710. execute(context -> {
  711. NewRepository repo = context.createRepository("fake", "java");
  712. repo.createRule("rule1")
  713. .setName("One")
  714. .setHtmlDescription("Description of One")
  715. .setSeverity(BLOCKER)
  716. .setInternalKey("config1")
  717. .setTags("tag1", "tag2", "tag3")
  718. .setType(RuleType.CODE_SMELL)
  719. .setStatus(RuleStatus.BETA);
  720. repo.done();
  721. });
  722. execute(context -> {
  723. NewRepository repo = context.createRepository("fake", "java");
  724. repo.createRule("newKey")
  725. .setName("One")
  726. .setHtmlDescription("Description of One")
  727. .setSeverity(BLOCKER)
  728. .setInternalKey("config1")
  729. .setTags("tag1", "tag2", "tag3")
  730. .setType(RuleType.CODE_SMELL)
  731. .setStatus(RuleStatus.BETA)
  732. .addDeprecatedRuleKey("fake", "rule1")
  733. .addDeprecatedRuleKey("fake", "rule2");
  734. repo.done();
  735. });
  736. List<RuleDefinitionDto> rules = dbClient.ruleDao().selectAllDefinitions(db.getSession());
  737. Set<DeprecatedRuleKeyDto> deprecatedRuleKeys = dbClient.ruleDao().selectAllDeprecatedRuleKeys(db.getSession());
  738. assertThat(rules).hasSize(1);
  739. assertThat(deprecatedRuleKeys).hasSize(2);
  740. }
  741. @Test
  742. public void rules_that_remove_deprecated_key_must_remove_records() {
  743. execute(context -> {
  744. NewRepository repo = context.createRepository("fake", "java");
  745. repo.createRule("rule1")
  746. .setName("One")
  747. .setHtmlDescription("Description of One")
  748. .setSeverity(BLOCKER)
  749. .setInternalKey("config1")
  750. .setTags("tag1", "tag2", "tag3")
  751. .setType(RuleType.CODE_SMELL)
  752. .setStatus(RuleStatus.BETA);
  753. repo.done();
  754. });
  755. execute(context -> {
  756. NewRepository repo = context.createRepository("fake", "java");
  757. repo.createRule("newKey")
  758. .setName("One")
  759. .setHtmlDescription("Description of One")
  760. .setSeverity(BLOCKER)
  761. .setInternalKey("config1")
  762. .setTags("tag1", "tag2", "tag3")
  763. .setType(RuleType.CODE_SMELL)
  764. .setStatus(RuleStatus.BETA)
  765. .addDeprecatedRuleKey("fake", "rule1")
  766. .addDeprecatedRuleKey("fake", "rule2");
  767. repo.done();
  768. });
  769. assertThat(dbClient.ruleDao().selectAllDefinitions(db.getSession())).hasSize(1);
  770. Set<DeprecatedRuleKeyDto> deprecatedRuleKeys = dbClient.ruleDao().selectAllDeprecatedRuleKeys(db.getSession());
  771. assertThat(deprecatedRuleKeys).hasSize(2);
  772. execute(context -> {
  773. NewRepository repo = context.createRepository("fake", "java");
  774. repo.createRule("newKey")
  775. .setName("One")
  776. .setHtmlDescription("Description of One")
  777. .setSeverity(BLOCKER)
  778. .setInternalKey("config1")
  779. .setTags("tag1", "tag2", "tag3")
  780. .setType(RuleType.CODE_SMELL)
  781. .setStatus(RuleStatus.BETA);
  782. repo.done();
  783. });
  784. assertThat(dbClient.ruleDao().selectAllDefinitions(db.getSession())).hasSize(1);
  785. deprecatedRuleKeys = dbClient.ruleDao().selectAllDeprecatedRuleKeys(db.getSession());
  786. assertThat(deprecatedRuleKeys).hasSize(0);
  787. }
  788. @Test
  789. public void declaring_two_rules_with_same_deprecated_RuleKey_should_throw_ISE() {
  790. expectedException.expect(IllegalStateException.class);
  791. expectedException.expectMessage("The following deprecated rule keys are declared at least twice [fake:old]");
  792. execute(context -> {
  793. NewRepository repo = context.createRepository("fake", "java");
  794. repo.createRule("newKey1")
  795. .setName("One")
  796. .setHtmlDescription("Description of One")
  797. .setSeverity(BLOCKER)
  798. .setInternalKey("config1")
  799. .setTags("tag1", "tag2", "tag3")
  800. .setType(RuleType.CODE_SMELL)
  801. .addDeprecatedRuleKey("fake", "old")
  802. .setStatus(RuleStatus.BETA);
  803. repo.createRule("newKey2")
  804. .setName("One")
  805. .setHtmlDescription("Description of One")
  806. .setSeverity(BLOCKER)
  807. .setInternalKey("config1")
  808. .setTags("tag1", "tag2", "tag3")
  809. .setType(RuleType.CODE_SMELL)
  810. .addDeprecatedRuleKey("fake", "old")
  811. .setStatus(RuleStatus.BETA);
  812. repo.done();
  813. });
  814. }
  815. @Test
  816. public void declaring_a_rule_with_a_deprecated_RuleKey_still_used_should_throw_ISE() {
  817. expectedException.expect(IllegalStateException.class);
  818. expectedException.expectMessage("The following rule keys are declared both as deprecated and used key [fake:newKey1]");
  819. execute(context -> {
  820. NewRepository repo = context.createRepository("fake", "java");
  821. repo.createRule("newKey1")
  822. .setName("One")
  823. .setHtmlDescription("Description of One")
  824. .setSeverity(BLOCKER)
  825. .setInternalKey("config1")
  826. .setTags("tag1", "tag2", "tag3")
  827. .setType(RuleType.CODE_SMELL)
  828. .setStatus(RuleStatus.BETA);
  829. repo.createRule("newKey2")
  830. .setName("One")
  831. .setHtmlDescription("Description of One")
  832. .setSeverity(BLOCKER)
  833. .setInternalKey("config1")
  834. .setTags("tag1", "tag2", "tag3")
  835. .setType(RuleType.CODE_SMELL)
  836. .addDeprecatedRuleKey("fake", "newKey1")
  837. .setStatus(RuleStatus.BETA);
  838. repo.done();
  839. });
  840. }
  841. @Test
  842. public void updating_the_deprecated_to_a_new_ruleKey_should_throw_an_ISE() {
  843. // On this new rule add a deprecated key
  844. execute(context -> createRule(context, "javascript", "javascript", "s103",
  845. r -> r.addDeprecatedRuleKey("javascript", "linelength")));
  846. expectedException.expect(IllegalStateException.class);
  847. expectedException.expectMessage("An incorrect state of deprecated rule keys has been detected.\n " +
  848. "The deprecated rule key [javascript:linelength] was previously deprecated by [javascript:s103]. [javascript:s103] should be a deprecated key of [sonarjs:s103],");
  849. // This rule should have been moved to another repository
  850. execute(context -> createRule(context, "javascript", "sonarjs", "s103",
  851. r -> r.addDeprecatedRuleKey("javascript", "linelength")));
  852. }
  853. @Test
  854. public void declaring_a_rule_with_an_existing_RuleKey_still_used_should_throw_IAE() {
  855. expectedException.expect(IllegalArgumentException.class);
  856. expectedException.expectMessage("The rule 'newKey1' of repository 'fake' is declared several times");
  857. execute(context -> {
  858. NewRepository repo = context.createRepository("fake", "java");
  859. repo.createRule("newKey1")
  860. .setName("One")
  861. .setHtmlDescription("Description of One")
  862. .setSeverity(BLOCKER)
  863. .setInternalKey("config1")
  864. .setTags("tag1", "tag2", "tag3")
  865. .setType(RuleType.CODE_SMELL)
  866. .setStatus(RuleStatus.BETA);
  867. repo.createRule("newKey1")
  868. .setName("One")
  869. .setHtmlDescription("Description of One")
  870. .setSeverity(BLOCKER)
  871. .setInternalKey("config1")
  872. .setTags("tag1", "tag2", "tag3")
  873. .setType(RuleType.CODE_SMELL)
  874. .addDeprecatedRuleKey("fake", "newKey1")
  875. .setStatus(RuleStatus.BETA);
  876. repo.done();
  877. });
  878. }
  879. private void execute(RulesDefinition... defs) {
  880. ServerPluginRepository pluginRepository = mock(ServerPluginRepository.class);
  881. when(pluginRepository.getPluginKey(any(RulesDefinition.class))).thenReturn(FAKE_PLUGIN_KEY);
  882. RuleDefinitionsLoader loader = new RuleDefinitionsLoader(mock(CommonRuleDefinitionsImpl.class), pluginRepository,
  883. defs);
  884. Languages languages = mock(Languages.class);
  885. when(languages.get(any())).thenReturn(mock(Language.class));
  886. reset(webServerRuleFinder);
  887. RegisterRules task = new RegisterRules(loader, qProfileRules, dbClient, ruleIndexer, activeRuleIndexer,
  888. languages, system, organizationFlags, webServerRuleFinder, uuidFactory);
  889. task.start();
  890. // Execute a commit to refresh session state as the task is using its own session
  891. db.getSession().commit();
  892. verify(webServerRuleFinder).startCaching();
  893. }
  894. @SafeVarargs
  895. private final void createRule(RulesDefinition.Context context, String language, String repositoryKey, String ruleKey, Consumer<NewRule>... consumers) {
  896. NewRepository repo = context.createRepository(repositoryKey, language);
  897. NewRule newRule = repo.createRule(ruleKey)
  898. .setName(ruleKey)
  899. .setHtmlDescription("Description of One")
  900. .setSeverity(BLOCKER)
  901. .setType(RuleType.CODE_SMELL)
  902. .setStatus(RuleStatus.BETA);
  903. Arrays.stream(consumers).forEach(c -> c.accept(newRule));
  904. repo.done();
  905. }
  906. private RuleParamDto getParam(List<RuleParamDto> params, String key) {
  907. for (RuleParamDto param : params) {
  908. if (param.getName().equals(key)) {
  909. return param;
  910. }
  911. }
  912. return null;
  913. }
  914. static class FakeRepositoryV1 implements RulesDefinition {
  915. @Override
  916. public void define(Context context) {
  917. NewRepository repo = context.createRepository("fake", "java");
  918. NewRule rule1 = repo.createRule(RULE_KEY1.rule())
  919. .setName("One")
  920. .setHtmlDescription("Description of One")
  921. .setSeverity(BLOCKER)
  922. .setInternalKey("config1")
  923. .setTags("tag1", "tag2", "tag3")
  924. .setScope(RuleScope.ALL)
  925. .setType(RuleType.CODE_SMELL)
  926. .setStatus(RuleStatus.BETA)
  927. .setGapDescription("squid.S115.effortToFix");
  928. rule1.setDebtRemediationFunction(rule1.debtRemediationFunctions().linearWithOffset("5d", "10h"));
  929. rule1.createParam("param1").setDescription("parameter one").setDefaultValue("default1");
  930. rule1.createParam("param2").setDescription("parameter two").setDefaultValue("default2");
  931. repo.createRule(HOTSPOT_RULE_KEY.rule())
  932. .setName("Hotspot")
  933. .setHtmlDescription("Minimal hotspot")
  934. .setType(RuleType.SECURITY_HOTSPOT)
  935. .addOwaspTop10(OwaspTop10.A1, OwaspTop10.A3)
  936. .addCwe(1, 123, 863);
  937. repo.createRule(RULE_KEY2.rule())
  938. .setName("Two")
  939. .setHtmlDescription("Minimal rule");
  940. repo.done();
  941. }
  942. }
  943. /**
  944. * FakeRepositoryV1 with some changes
  945. */
  946. static class FakeRepositoryV2 implements RulesDefinition {
  947. @Override
  948. public void define(Context context) {
  949. NewRepository repo = context.createRepository("fake", "java");
  950. // almost all the attributes of rule1 are changed
  951. NewRule rule1 = repo.createRule(RULE_KEY1.rule())
  952. .setName("One v2")
  953. .setHtmlDescription("Description of One v2")
  954. .setSeverity(INFO)
  955. .setInternalKey("config1 v2")
  956. // tag2 and tag3 removed, tag4 added
  957. .setTags("tag1", "tag4")
  958. .setType(RuleType.BUG)
  959. .setStatus(READY)
  960. .setGapDescription("squid.S115.effortToFix.v2");
  961. rule1.setDebtRemediationFunction(rule1.debtRemediationFunctions().linearWithOffset("6d", "2h"));
  962. rule1.createParam("param1").setDescription("parameter one v2").setDefaultValue("default1 v2");
  963. rule1.createParam("param2").setDescription("parameter two v2").setDefaultValue("default2 v2");
  964. // rule2 is dropped, rule3 is new
  965. repo.createRule(RULE_KEY3.rule())
  966. .setName("Three")
  967. .setHtmlDescription("Rule Three");
  968. repo.done();
  969. }
  970. }
  971. static class ExternalRuleRepository implements RulesDefinition {
  972. @Override
  973. public void define(Context context) {
  974. NewRepository repo = context.createExternalRepository("eslint", "js");
  975. repo.createRule(RULE_KEY1.rule())
  976. .setName("One")
  977. .setHtmlDescription("Description of One")
  978. .setSeverity(BLOCKER)
  979. .setInternalKey("config1")
  980. .setTags("tag1", "tag2", "tag3")
  981. .setScope(RuleScope.ALL)
  982. .setType(RuleType.CODE_SMELL)
  983. .setStatus(RuleStatus.BETA);
  984. repo.createRule(EXTERNAL_HOTSPOT_RULE_KEY.rule())
  985. .setName("Hotspot")
  986. .setHtmlDescription("Minimal hotspot")
  987. .setType(RuleType.SECURITY_HOTSPOT)
  988. .addOwaspTop10(OwaspTop10.A1, OwaspTop10.A3)
  989. .addCwe(1, 123, 863);
  990. repo.done();
  991. }
  992. }
  993. static class BigRepository implements RulesDefinition {
  994. static final int SIZE = 500;
  995. @Override
  996. public void define(Context context) {
  997. NewRepository repo = context.createRepository("big", "java");
  998. for (int i = 0; i < SIZE; i++) {
  999. NewRule rule = repo.createRule("rule" + i)
  1000. .setName("name of " + i)
  1001. .setHtmlDescription("description of " + i);
  1002. for (int j = 0; j < 20; j++) {
  1003. rule.createParam("param" + j);
  1004. }
  1005. }
  1006. repo.done();
  1007. }
  1008. }
  1009. static class FindbugsRepository implements RulesDefinition {
  1010. @Override
  1011. public void define(Context context) {
  1012. NewRepository repo = context.createRepository("findbugs", "java");
  1013. repo.createRule("rule1")
  1014. .setName("Rule One")
  1015. .setHtmlDescription("Description of Rule One");
  1016. repo.done();
  1017. }
  1018. }
  1019. static class FbContribRepository implements RulesDefinition {
  1020. @Override
  1021. public void define(Context context) {
  1022. NewExtendedRepository repo = context.extendRepository("findbugs", "java");
  1023. repo.createRule("rule2")
  1024. .setName("Rule Two")
  1025. .setHtmlDescription("Description of Rule Two");
  1026. repo.done();
  1027. }
  1028. }
  1029. static class RepositoryWithOneTemplateRule implements RulesDefinition {
  1030. @Override
  1031. public void define(Context context) {
  1032. NewRepository repo = context.createRepository("test", "java");
  1033. repo.createRule("rule1")
  1034. .setName("Rule One")
  1035. .setHtmlDescription("Description of Rule One")
  1036. .setTemplate(true);
  1037. repo.done();
  1038. }
  1039. }
  1040. }