]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-11212 Distinguish predefined and ad hoc external rules
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Tue, 4 Sep 2018 14:08:00 +0000 (16:08 +0200)
committerSonarTech <sonartech@sonarsource.com>
Mon, 24 Sep 2018 18:20:57 +0000 (20:20 +0200)
45 files changed:
server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java
server/sonar-db-core/src/main/resources/org/sonar/db/version/schema-h2.ddl
server/sonar-db-dao/src/main/java/org/sonar/db/rule/RuleDefinitionDto.java
server/sonar-db-dao/src/main/java/org/sonar/db/rule/RuleDto.java
server/sonar-db-dao/src/main/resources/org/sonar/db/rule/RuleMapper.xml
server/sonar-db-dao/src/test/java/org/sonar/db/rule/RuleDaoTest.java
server/sonar-db-dao/src/test/java/org/sonar/db/rule/RuleTesting.java
server/sonar-db-dao/src/test/resources/org/sonar/db/rule/RuleDaoTest/insert_parameter-result.xml [deleted file]
server/sonar-db-dao/src/test/resources/org/sonar/db/rule/RuleDaoTest/insert_parameter.xml [deleted file]
server/sonar-db-dao/src/test/resources/org/sonar/db/rule/RuleDaoTest/selectEnabled.xml [deleted file]
server/sonar-db-dao/src/test/resources/org/sonar/db/rule/RuleDaoTest/selectNonManual.xml [deleted file]
server/sonar-db-dao/src/test/resources/org/sonar/db/rule/RuleDaoTest/select_parameters_by_rule_key.xml [deleted file]
server/sonar-db-dao/src/test/resources/org/sonar/db/rule/RuleDaoTest/shared.xml [deleted file]
server/sonar-db-dao/src/test/resources/org/sonar/db/rule/RuleDaoTest/update.xml [deleted file]
server/sonar-db-dao/src/test/resources/org/sonar/db/rule/RuleDaoTest/update_parameter-result.xml [deleted file]
server/sonar-db-dao/src/test/resources/org/sonar/db/rule/RuleDaoTest/update_parameter.xml [deleted file]
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/MigrationConfigurationModule.java
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v74/AddIsAdHocToRules.java [new file with mode: 0644]
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v74/DbVersion74.java [new file with mode: 0644]
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v74/PopulateIsAdHocOnRules.java [new file with mode: 0644]
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v74/PopulateNullValuesOfIsExternalOnRules.java [new file with mode: 0644]
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v74/SetIsExternalAndIsAdHocNotNullableInRules.java [new file with mode: 0644]
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v74/package-info.java [new file with mode: 0644]
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/MigrationConfigurationModuleTest.java
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v74/AddIsAdHocToRulesTest.java [new file with mode: 0644]
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v74/DbVersion74Test.java [new file with mode: 0644]
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v74/PopulateIsAdHocOnRulesTest.java [new file with mode: 0644]
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v74/PopulateNullValuesOfIsExternalOnRulesTest.java [new file with mode: 0644]
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v74/SetIsExternalAndIsAdHocNotNullableInRulesTest.java [new file with mode: 0644]
server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v74/AddIsAdHocToRulesTest/rules.sql [new file with mode: 0644]
server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v74/PopulateIsAdHocOnRulesTest/rules.sql [new file with mode: 0644]
server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v74/PopulateNullValuesOfIsExternalOnRulesTest/rules.sql [new file with mode: 0644]
server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v74/SetIsExternalAndIsAdHocNotNullableInRulesTest/rules.sql [new file with mode: 0644]
server/sonar-server-common/src/test/java/org/sonar/server/rule/ExternalRuleCreatorTest.java
server/sonar-server-common/src/test/resources/org/sonar/server/issue/index/IssueIteratorFactoryTest/extract_directory_path.xml
server/sonar-server-common/src/test/resources/org/sonar/server/issue/index/IssueIteratorFactoryTest/extract_file_path.xml
server/sonar-server-common/src/test/resources/org/sonar/server/issue/index/IssueIteratorFactoryTest/many_projects.xml
server/sonar-server-common/src/test/resources/org/sonar/server/issue/index/IssueIteratorFactoryTest/one_issue.xml
server/sonar-server-common/src/test/resources/org/sonar/server/issue/index/IssueIteratorFactoryTest/shared.xml
server/sonar-server/src/main/java/org/sonar/server/rule/RegisterRules.java
server/sonar-server/src/main/java/org/sonar/server/rule/RuleCreator.java
server/sonar-server/src/test/java/org/sonar/server/batch/IssuesActionTest.java
server/sonar-server/src/test/java/org/sonar/server/rule/RegisterRulesTest.java
server/sonar-server/src/test/java/org/sonar/server/rule/RuleCreatorTest.java
server/sonar-server/src/test/resources/org/sonar/server/platform/BackendCleanupTest/shared.xml

index 81fe42adca69073d783a21f914a32423dabf6c54..369ef9a85786368ef7a7e687b69340d68d4657d4 100644 (file)
@@ -115,7 +115,7 @@ public class ComputeEngineContainerImplTest {
       );
       assertThat(picoContainer.getParent().getParent().getComponentAdapters()).hasSize(
         CONTAINER_ITSELF
-          + 17 // MigrationConfigurationModule
+          + 18 // MigrationConfigurationModule
           + 17 // level 2
       );
       assertThat(picoContainer.getParent().getParent().getParent().getComponentAdapters()).hasSize(
index 4e43f0178e491ec69c4fa3aaa4e0243c28ac8b6d..db1b8dfd21122e6d2430fd2840389fe8cd2e3311 100644 (file)
@@ -201,7 +201,8 @@ CREATE TABLE "RULES" (
   "DESCRIPTION_FORMAT" VARCHAR(20),
   "PRIORITY" INTEGER,
   "IS_TEMPLATE" BOOLEAN DEFAULT FALSE,
-  "IS_EXTERNAL" BOOLEAN,
+  "IS_EXTERNAL" BOOLEAN NOT NULL,
+  "IS_AD_HOC" BOOLEAN NOT NULL,
   "TEMPLATE_ID" INTEGER,
   "PLUGIN_CONFIG_KEY" VARCHAR(200),
   "NAME" VARCHAR(200),
index 9eeaccf681a85a22e5e209fba083f85ceca285b2..4d96f20ae2332e9fa9d7f33abbe8177a5f277815 100644 (file)
@@ -47,7 +47,19 @@ public class RuleDefinitionDto {
   private String configKey;
   private Integer severity;
   private boolean isTemplate;
+
+  /**
+   * This flag specify that this is an external rule, meaning that generated issues from this rule will be provided by the analyzer without being activated on a quality profile.
+   */
   private boolean isExternal;
+
+  /**
+   * When an external rule is defined as ad hoc, it means that it's not defined using {@link org.sonar.api.server.rule.RulesDefinition.Context#createExternalRepository(String, String)}.
+   * As the opposite, an external rule not being defined as ad hoc is declared by using {@link org.sonar.api.server.rule.RulesDefinition.Context#createExternalRepository(String, String)}.
+   * This flag is only used for external rules (it can only be set to true for when {@link #isExternal()} is true)
+   */
+  private boolean isAdHoc;
+
   private String language;
   private Integer templateId;
   private String defRemediationFunction;
@@ -73,8 +85,11 @@ public class RuleDefinitionDto {
     return key;
   }
 
-  void setKey(RuleKey key) {
+  RuleDefinitionDto setKey(RuleKey key) {
     this.key = key;
+    setRepositoryKey(key.repository());
+    setRuleKey(key.rule());
+    return this;
   }
 
   public Integer getId() {
@@ -187,7 +202,6 @@ public class RuleDefinitionDto {
     return this;
   }
 
-
   public boolean isExternal() {
     return isExternal;
   }
@@ -197,6 +211,15 @@ public class RuleDefinitionDto {
     return this;
   }
 
+  public boolean isAdHoc() {
+    return isAdHoc;
+  }
+
+  public RuleDefinitionDto setIsAdHoc(boolean isAdHoc) {
+    this.isAdHoc = isAdHoc;
+    return this;
+  }
+
   @CheckForNull
   public String getLanguage() {
     return language;
index 6fe07bcfb6e5d1f004d0266dc4e50c68f0c2bba4..843c5733b66707aaab802ecb698e810c11c254b7 100644 (file)
@@ -59,9 +59,6 @@ public class RuleDto {
   }
 
   public RuleKey getKey() {
-    if (definition.getKey() == null) {
-      definition.setKey(RuleKey.of(getRepositoryKey(), getRuleKey()));
-    }
     return definition.getKey();
   }
 
@@ -186,6 +183,15 @@ public class RuleDto {
     return this;
   }
 
+  public boolean isAdHoc() {
+    return definition.isAdHoc();
+  }
+
+  public RuleDto setIsAdhoc(boolean isAdHoc) {
+    definition.setIsAdHoc(isAdHoc);
+    return this;
+  }
+
   public boolean isTemplate() {
     return definition.isTemplate();
   }
index 12957844f6b408013cbf3290e73b32cb48b58d6b..2150cf25df40ba5978b4f31aaa78ae5787a8b98b 100644 (file)
@@ -15,6 +15,7 @@
     r.priority as "severity",
     r.is_template as "isTemplate",
     r.is_external as "isExternal",
+    r.is_ad_hoc as "isAdHoc",
     r.language as "language",
     r.template_id as "templateId",
     r.def_remediation_function as "defRemediationFunction",
       priority,
       is_template,
       is_external,
+      is_ad_hoc,
       language,
       template_id,
       def_remediation_function,
       #{severity,jdbcType=INTEGER},
       #{isTemplate,jdbcType=BOOLEAN},
       #{isExternal,jdbcType=BOOLEAN},
+      #{isAdHoc,jdbcType=BOOLEAN},
       #{language,jdbcType=VARCHAR},
       #{templateId,jdbcType=INTEGER},
       #{defRemediationFunction,jdbcType=VARCHAR},
       priority=#{severity,jdbcType=INTEGER},
       is_template=#{isTemplate,jdbcType=BOOLEAN},
       is_external=#{isExternal,jdbcType=BOOLEAN},
+      is_ad_hoc=#{isAdHoc,jdbcType=BOOLEAN},
       language=#{language,jdbcType=VARCHAR},
       template_id=#{templateId,jdbcType=INTEGER},
       def_remediation_function=#{defRemediationFunction,jdbcType=VARCHAR},
index 8020ec5766313dafc98bd5d1b461914b6574e3ff..399dda82f172fe0ca65da5aa0e1cc71f3eff5f5e 100644 (file)
@@ -19,7 +19,6 @@
  */
 package org.sonar.db.rule;
 
-import com.google.common.collect.Iterables;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -49,7 +48,6 @@ import org.sonar.db.organization.OrganizationDto;
 import org.sonar.db.organization.OrganizationTesting;
 import org.sonar.db.rule.RuleDto.Scope;
 
-import static com.google.common.collect.ImmutableSet.of;
 import static com.google.common.collect.Sets.newHashSet;
 import static java.util.Arrays.asList;
 import static java.util.Collections.emptyList;
@@ -57,10 +55,13 @@ import static java.util.Collections.singletonList;
 import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.tuple;
+import static org.sonar.api.rule.RuleStatus.REMOVED;
+import static org.sonar.db.rule.RuleTesting.newRuleMetadata;
 
 public class RuleDaoTest {
 
   private static final String ORGANIZATION_UUID = "org-1";
+  private static final int UNKNOWN_RULE_ID = 1_234_567_890;
 
   @Rule
   public ExpectedException thrown = ExpectedException.none();
@@ -79,7 +80,7 @@ public class RuleDaoTest {
   public void selectByKey() {
     RuleDefinitionDto ruleDefinition = db.rules().insert();
     OrganizationDto organization = db.organizations().insert();
-    RuleMetadataDto metadata = newRuleMetadata(organization, "1");
+    RuleMetadataDto metadata = newRuleMetadata(ruleDefinition, organization);
     db.rules().insertRule(ruleDefinition, metadata);
 
     assertThat(underTest.selectByKey(db.getSession(), organization, RuleKey.of("foo", "bar")))
@@ -110,10 +111,10 @@ public class RuleDaoTest {
   public void selectByKey_returns_metadata_of_specified_organization() {
     RuleDefinitionDto ruleDefinition = db.rules().insert();
     OrganizationDto organization1 = db.organizations().insert();
-    RuleMetadataDto expectedOrg1 = newRuleMetadata(organization1, "1");
+    RuleMetadataDto expectedOrg1 = newRuleMetadata(ruleDefinition, organization1);
     db.rules().insertRule(ruleDefinition, expectedOrg1);
     OrganizationDto organization2 = db.organizations().insert();
-    RuleMetadataDto expectedOrg2 = newRuleMetadata(organization2, "2");
+    RuleMetadataDto expectedOrg2 = newRuleMetadata(ruleDefinition, organization2);
     db.rules().insertRule(ruleDefinition, expectedOrg2);
 
     RuleDto rule = underTest.selectByKey(db.getSession(), organization1, ruleDefinition.getKey()).get();
@@ -124,20 +125,19 @@ public class RuleDaoTest {
 
   @Test
   public void selectDefinitionByKey() {
-    db.prepareDbUnit(getClass(), "shared.xml");
+    RuleDefinitionDto rule = db.rules().insert();
 
     assertThat(underTest.selectDefinitionByKey(db.getSession(), RuleKey.of("NOT", "FOUND")).isPresent()).isFalse();
 
-    Optional<RuleDefinitionDto> rule = underTest.selectDefinitionByKey(db.getSession(), RuleKey.of("java", "S001"));
-    assertThat(rule.isPresent()).isTrue();
-    assertThat(rule.get().getId()).isEqualTo(1);
+    Optional<RuleDefinitionDto> reloaded = underTest.selectDefinitionByKey(db.getSession(), rule.getKey());
+    assertThat(reloaded.isPresent()).isTrue();
   }
 
   @Test
   public void selectById() {
     RuleDefinitionDto ruleDefinition = db.rules().insert();
     OrganizationDto organization = db.organizations().insert();
-    RuleMetadataDto metadata = newRuleMetadata(organization, "1");
+    RuleMetadataDto metadata = newRuleMetadata(ruleDefinition, organization);
     RuleDto expected = db.rules().insertRule(ruleDefinition, metadata);
 
     assertThat(underTest.selectById(expected.getId() + 500, organization.getUuid(), db.getSession()))
@@ -168,10 +168,10 @@ public class RuleDaoTest {
   public void selectById_returns_metadata_of_specified_organization() {
     RuleDefinitionDto ruleDefinition = db.rules().insert();
     OrganizationDto organization1 = db.organizations().insert();
-    RuleMetadataDto expectedOrg1 = newRuleMetadata(organization1, "1");
+    RuleMetadataDto expectedOrg1 = newRuleMetadata(ruleDefinition, organization1);
     db.rules().insertRule(ruleDefinition, expectedOrg1);
     OrganizationDto organization2 = db.organizations().insert();
-    RuleMetadataDto expectedOrg2 = newRuleMetadata(organization2, "2");
+    RuleMetadataDto expectedOrg2 = newRuleMetadata(ruleDefinition, organization2);
     db.rules().insertRule(ruleDefinition, expectedOrg2);
 
     RuleDto rule = underTest.selectById(ruleDefinition.getId(), organization1.getUuid(), db.getSession()).get();
@@ -182,81 +182,84 @@ public class RuleDaoTest {
 
   @Test
   public void selectDefinitionById() {
-    db.prepareDbUnit(getClass(), "shared.xml");
+    RuleDefinitionDto rule = db.rules().insert();
 
-    assertThat(underTest.selectDefinitionById(55l, db.getSession())).isEmpty();
-    Optional<RuleDefinitionDto> ruleDtoOptional = underTest.selectDefinitionById(1l, db.getSession());
+    assertThat(underTest.selectDefinitionById(1_234_567L, db.getSession())).isEmpty();
+    Optional<RuleDefinitionDto> ruleDtoOptional = underTest.selectDefinitionById(rule.getId(), db.getSession());
     assertThat(ruleDtoOptional).isPresent();
-    assertThat(ruleDtoOptional.get().getId()).isEqualTo(1);
   }
 
   @Test
   public void selectByIds() {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    String organizationUuid = "org-1";
-
-    assertThat(underTest.selectByIds(db.getSession(), organizationUuid, asList(1))).hasSize(1);
-    assertThat(underTest.selectByIds(db.getSession(), organizationUuid, asList(1, 2))).hasSize(2);
-    assertThat(underTest.selectByIds(db.getSession(), organizationUuid, asList(1, 2, 3))).hasSize(2);
-
-    assertThat(underTest.selectByIds(db.getSession(), organizationUuid, asList(123))).isEmpty();
+    OrganizationDto organization = db.organizations().insert();
+    RuleDefinitionDto rule1 = db.rules().insert();
+    db.rules().insertOrUpdateMetadata(rule1, organization);
+    RuleDefinitionDto rule2 = db.rules().insert();
+    db.rules().insertOrUpdateMetadata(rule2, organization);
+    RuleDefinitionDto removedRule = db.rules().insert(r -> r.setStatus(REMOVED));
+    db.rules().insertOrUpdateMetadata(removedRule, organization);
+
+    assertThat(underTest.selectByIds(db.getSession(), organization.getUuid(), singletonList(rule1.getId()))).hasSize(1);
+    assertThat(underTest.selectByIds(db.getSession(), organization.getUuid(), asList(rule1.getId(), rule2.getId()))).hasSize(2);
+    assertThat(underTest.selectByIds(db.getSession(), organization.getUuid(), asList(rule1.getId(), rule2.getId(), UNKNOWN_RULE_ID))).hasSize(2);
+    assertThat(underTest.selectByIds(db.getSession(), organization.getUuid(), asList(rule1.getId(), rule2.getId(), removedRule.getId()))).hasSize(3);
+    assertThat(underTest.selectByIds(db.getSession(), organization.getUuid(), singletonList(UNKNOWN_RULE_ID))).isEmpty();
   }
 
   @Test
   public void selectByIds_populates_organizationUuid_even_when_organization_has_no_metadata() {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    String organizationUuid = "org-1";
+    OrganizationDto organization = db.organizations().insert();
+    RuleDefinitionDto rule1 = db.rules().insert();
+    RuleDefinitionDto rule2 = db.rules().insert();
 
-    assertThat(underTest.selectByIds(db.getSession(), organizationUuid, asList(1, 2)))
+    assertThat(underTest.selectByIds(db.getSession(), organization.getUuid(), asList(rule1.getId(), rule2.getId())))
       .extracting(RuleDto::getOrganizationUuid)
-      .containsExactly(organizationUuid, organizationUuid);
+      .containsExactly(organization.getUuid(), organization.getUuid());
   }
 
   @Test
   public void selectDefinitionByIds() {
-    db.prepareDbUnit(getClass(), "shared.xml");
+    RuleDefinitionDto rule1 = db.rules().insert();
+    RuleDefinitionDto rule2 = db.rules().insert();
 
-    assertThat(underTest.selectDefinitionByIds(db.getSession(), asList(1))).hasSize(1);
-    assertThat(underTest.selectDefinitionByIds(db.getSession(), asList(1, 2))).hasSize(2);
-    assertThat(underTest.selectDefinitionByIds(db.getSession(), asList(1, 2, 3))).hasSize(2);
+    assertThat(underTest.selectDefinitionByIds(db.getSession(), singletonList(rule1.getId()))).hasSize(1);
+    assertThat(underTest.selectDefinitionByIds(db.getSession(), asList(rule1.getId(), rule2.getId()))).hasSize(2);
+    assertThat(underTest.selectDefinitionByIds(db.getSession(), asList(rule1.getId(), rule2.getId(), UNKNOWN_RULE_ID))).hasSize(2);
 
-    assertThat(underTest.selectDefinitionByIds(db.getSession(), asList(123))).isEmpty();
+    assertThat(underTest.selectDefinitionByIds(db.getSession(), singletonList(UNKNOWN_RULE_ID))).isEmpty();
   }
 
   @Test
   public void selectOrFailByKey() {
-    db.prepareDbUnit(getClass(), "shared.xml");
+    OrganizationDto organization = db.organizations().insert();
+    RuleDefinitionDto rule1 = db.rules().insert();
+    RuleDefinitionDto rule2 = db.rules().insert();
 
-    OrganizationDto organization = OrganizationTesting.newOrganizationDto().setUuid("org-1");
-    RuleDto rule = underTest.selectOrFailByKey(db.getSession(), organization, RuleKey.of("java", "S001"));
-    assertThat(rule.getId()).isEqualTo(1);
+    RuleDto rule = underTest.selectOrFailByKey(db.getSession(), organization, rule1.getKey());
+    assertThat(rule.getId()).isEqualTo(rule1.getId());
   }
 
   @Test
   public void selectOrFailByKey_fails_if_rule_not_found() {
-    db.prepareDbUnit(getClass(), "shared.xml");
+    OrganizationDto organization = db.organizations().insert();
 
     thrown.expect(RowNotFoundException.class);
     thrown.expectMessage("Rule with key 'NOT:FOUND' does not exist");
 
-    OrganizationDto organization = OrganizationTesting.newOrganizationDto().setUuid("org-1");
     underTest.selectOrFailByKey(db.getSession(), organization, RuleKey.of("NOT", "FOUND"));
   }
 
   @Test
   public void selectOrFailByKey_populates_organizationUuid_even_when_organization_has_no_metadata() {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    String organizationUuid = "org-1";
+    OrganizationDto organization = db.organizations().insert();
+    RuleDefinitionDto rule = db.rules().insert();
 
-    OrganizationDto organization = OrganizationTesting.newOrganizationDto().setUuid(organizationUuid);
-    assertThat(underTest.selectOrFailByKey(db.getSession(), organization, RuleKey.of("java", "S001")).getOrganizationUuid())
-      .isEqualTo(organizationUuid);
+    assertThat(underTest.selectOrFailByKey(db.getSession(), organization, rule.getKey()).getOrganizationUuid())
+      .isEqualTo(organization.getUuid());
   }
 
   @Test
   public void selectOrFailDefinitionByKey_fails_if_rule_not_found() {
-    db.prepareDbUnit(getClass(), "shared.xml");
-
     thrown.expect(RowNotFoundException.class);
     thrown.expectMessage("Rule with key 'NOT:FOUND' does not exist");
 
@@ -265,37 +268,40 @@ public class RuleDaoTest {
 
   @Test
   public void selectByKeys() {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    String organizationUuid = "org-1";
+    OrganizationDto organization = db.organizations().insert();
+    RuleDefinitionDto rule1 = db.rules().insert();
+    db.rules().insertOrUpdateMetadata(rule1, organization);
+    RuleDefinitionDto rule2 = db.rules().insert();
+    db.rules().insertOrUpdateMetadata(rule2, organization);
 
-    assertThat(underTest.selectByKeys(db.getSession(), organizationUuid, Collections.emptyList())).isEmpty();
-    assertThat(underTest.selectByKeys(db.getSession(), organizationUuid, asList(RuleKey.of("NOT", "FOUND")))).isEmpty();
+    assertThat(underTest.selectByKeys(db.getSession(), organization.getUuid(), Collections.emptyList())).isEmpty();
+    assertThat(underTest.selectByKeys(db.getSession(), organization.getUuid(), asList(RuleKey.of("NOT", "FOUND")))).isEmpty();
 
-    List<RuleDto> rules = underTest.selectByKeys(db.getSession(), organizationUuid, asList(RuleKey.of("java", "S001"), RuleKey.of("java", "OTHER")));
+    List<RuleDto> rules = underTest.selectByKeys(db.getSession(), organization.getUuid(), asList(rule1.getKey(), RuleKey.of("java", "OTHER")));
     assertThat(rules).hasSize(1);
-    assertThat(rules.get(0).getId()).isEqualTo(1);
+    assertThat(rules.get(0).getId()).isEqualTo(rule1.getId());
   }
 
   @Test
   public void selectByKeys_populates_organizationUuid_even_when_organization_has_no_metadata() {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    String organizationUuid = "org-1";
+    OrganizationDto organization = db.organizations().insert();
+    RuleDefinitionDto rule = db.rules().insert();
 
-    assertThat(underTest.selectByKeys(db.getSession(), organizationUuid, asList(RuleKey.of("java", "S001"), RuleKey.of("java", "OTHER"))))
+    assertThat(underTest.selectByKeys(db.getSession(), organization.getUuid(), singletonList(rule.getKey())))
       .extracting(RuleDto::getOrganizationUuid)
-      .containsExactly(organizationUuid);
+      .containsExactly(organization.getUuid());
   }
 
   @Test
   public void selectDefinitionByKeys() {
-    db.prepareDbUnit(getClass(), "shared.xml");
+    RuleDefinitionDto rule = db.rules().insert();
 
     assertThat(underTest.selectDefinitionByKeys(db.getSession(), Collections.emptyList())).isEmpty();
     assertThat(underTest.selectDefinitionByKeys(db.getSession(), asList(RuleKey.of("NOT", "FOUND")))).isEmpty();
 
-    List<RuleDefinitionDto> rules = underTest.selectDefinitionByKeys(db.getSession(), asList(RuleKey.of("java", "S001"), RuleKey.of("java", "OTHER")));
+    List<RuleDefinitionDto> rules = underTest.selectDefinitionByKeys(db.getSession(), asList(rule.getKey(), RuleKey.of("java", "OTHER")));
     assertThat(rules).hasSize(1);
-    assertThat(rules.get(0).getId()).isEqualTo(1);
+    assertThat(rules.get(0).getId()).isEqualTo(rule.getId());
   }
 
   @Test
@@ -340,7 +346,7 @@ public class RuleDaoTest {
   public void selectAll_returns_metadata_of_specified_organization() {
     RuleDefinitionDto ruleDefinition = db.rules().insert();
     OrganizationDto organization = db.organizations().insert();
-    RuleMetadataDto expected = newRuleMetadata(organization, "1");
+    RuleMetadataDto expected = newRuleMetadata(ruleDefinition, organization);
     db.rules().insertRule(ruleDefinition, expected);
 
     List<RuleDto> rules = underTest.selectAll(db.getSession(), organization.getUuid());
@@ -372,8 +378,6 @@ public class RuleDaoTest {
     assertThat(actual.getSystemTags()).isEqualTo(expected.getSystemTags());
     assertThat(actual.getSecurityStandards()).isEqualTo(expected.getSecurityStandards());
     assertThat(actual.getType()).isEqualTo(expected.getType());
-    assertThat(actual.getCreatedAt()).isEqualTo(expected.getCreatedAt());
-    assertThat(actual.getUpdatedAt()).isEqualTo(expected.getUpdatedAt());
   }
 
   private static void verifyMetadata(RuleMetadataDto metadata, RuleDefinitionDto ruleDefinition, RuleMetadataDto expected) {
@@ -385,8 +389,10 @@ public class RuleDaoTest {
     assertThat(metadata.getNoteData()).isEqualTo(expected.getNoteData());
     assertThat(metadata.getNoteCreatedAt()).isEqualTo(expected.getNoteCreatedAt());
     assertThat(metadata.getNoteUpdatedAt()).isEqualTo(expected.getNoteUpdatedAt());
-    assertThat(metadata.getCreatedAt()).isEqualTo(ruleDefinition.getCreatedAt());
-    assertThat(metadata.getUpdatedAt()).isEqualTo(ruleDefinition.getUpdatedAt());
+    assertThat(metadata.getAdHocName()).isEqualTo(expected.getAdHocName());
+    assertThat(metadata.getAdHocDescription()).isEqualTo(expected.getAdHocDescription());
+    assertThat(metadata.getAdHocSeverity()).isEqualTo(expected.getAdHocSeverity());
+    assertThat(metadata.getAdHocType()).isEqualTo(expected.getAdHocType());
   }
 
   private static void verifyNoMetadata(RuleMetadataDto metadata, RuleDefinitionDto ruleDefinition, OrganizationDto organization) {
@@ -398,37 +404,27 @@ public class RuleDaoTest {
     assertThat(metadata.getNoteData()).isNull();
     assertThat(metadata.getNoteCreatedAt()).isNull();
     assertThat(metadata.getNoteUpdatedAt()).isNull();
-    assertThat(metadata.getCreatedAt()).isEqualTo(ruleDefinition.getCreatedAt());
-    assertThat(metadata.getUpdatedAt()).isEqualTo(ruleDefinition.getUpdatedAt());
-  }
-
-  private static RuleMetadataDto newRuleMetadata(OrganizationDto organization, String seed) {
-    String noteData = seed + randomAlphanumeric(7);
-    return new RuleMetadataDto()
-      .setOrganizationUuid(organization.getUuid())
-      .setRemediationBaseEffort(seed + randomAlphanumeric(2))
-      .setRemediationFunction(seed + randomAlphanumeric(3))
-      .setRemediationGapMultiplier(seed + randomAlphanumeric(4))
-      .setTags(of(seed + randomAlphanumeric(5), seed + randomAlphanumeric(6)))
-      .setNoteData(noteData)
-      .setNoteCreatedAt(noteData.hashCode() + 50L)
-      .setNoteUpdatedAt(noteData.hashCode() + 1_999L)
-      .setCreatedAt(seed.hashCode() + 8889L)
-      .setUpdatedAt(seed.hashCode() + 10_333L);
+    assertThat(metadata.getAdHocName()).isNull();
+    assertThat(metadata.getAdHocDescription()).isNull();
+    assertThat(metadata.getAdHocSeverity()).isNull();
+    assertThat(metadata.getAdHocType()).isNull();
   }
 
   @Test
   public void selectAllDefinitions() {
-    db.prepareDbUnit(getClass(), "shared.xml");
+    RuleDefinitionDto rule1 = db.rules().insert();
+    RuleDefinitionDto rule2 = db.rules().insert();
+    RuleDefinitionDto removedRule = db.rules().insert(r -> r.setStatus(REMOVED));
 
     List<RuleDefinitionDto> ruleDtos = underTest.selectAllDefinitions(db.getSession());
 
-    assertThat(ruleDtos).extracting("id").containsOnly(1, 2, 10);
+    assertThat(ruleDtos).extracting(RuleDefinitionDto::getId).containsOnly(rule1.getId(), rule2.getId(), removedRule.getId());
   }
 
   @Test
   public void selectEnabled_with_ResultHandler() {
-    db.prepareDbUnit(getClass(), "selectEnabled.xml");
+    RuleDefinitionDto rule = db.rules().insert();
+    RuleDefinitionDto removedRule = db.rules().insert(r -> r.setStatus(REMOVED));
 
     final List<RuleDefinitionDto> rules = new ArrayList<>();
     ResultHandler<RuleDefinitionDto> resultHandler = resultContext -> rules.add(resultContext.getResultObject());
@@ -436,39 +432,35 @@ public class RuleDaoTest {
 
     assertThat(rules.size()).isEqualTo(1);
     RuleDefinitionDto ruleDto = rules.get(0);
-    assertThat(ruleDto.getId()).isEqualTo(1);
-    assertThat(ruleDto.getName()).isEqualTo("Avoid Null");
-    assertThat(ruleDto.getDescription()).isEqualTo("Should avoid NULL");
-    assertThat(ruleDto.getDescriptionFormat()).isEqualTo(RuleDto.Format.HTML);
-    assertThat(ruleDto.getStatus()).isEqualTo(RuleStatus.READY);
-    assertThat(ruleDto.getRepositoryKey()).isEqualTo("checkstyle");
-    assertThat(ruleDto.getDefRemediationFunction()).isEqualTo("LINEAR_OFFSET");
-    assertThat(ruleDto.getDefRemediationGapMultiplier()).isEqualTo("5d");
-    assertThat(ruleDto.getDefRemediationBaseEffort()).isEqualTo("10h");
-    assertThat(ruleDto.getGapDescription()).isEqualTo("squid.S115.effortToFix");
+    assertThat(ruleDto.getId()).isEqualTo(rule.getId());
   }
 
   @Test
   public void select_by_query() {
-    db.prepareDbUnit(getClass(), "shared.xml");
-
-    String organizationUuid = "org-1";
-    assertThat(underTest.selectByQuery(db.getSession(), organizationUuid, RuleQuery.create())).hasSize(2);
-    assertThat(underTest.selectByQuery(db.getSession(), organizationUuid, RuleQuery.create().withKey("S001"))).hasSize(1);
-    assertThat(underTest.selectByQuery(db.getSession(), organizationUuid, RuleQuery.create().withConfigKey("S1"))).hasSize(1);
-    assertThat(underTest.selectByQuery(db.getSession(), organizationUuid, RuleQuery.create().withRepositoryKey("java"))).hasSize(2);
-    assertThat(underTest.selectByQuery(db.getSession(), organizationUuid,
+    OrganizationDto organization = db.organizations().insert();
+    RuleDefinitionDto rule1 = db.rules().insert(r -> r.setKey(RuleKey.of("java", "S001")).setConfigKey("S1"));
+    db.rules().insertOrUpdateMetadata(rule1, organization);
+    RuleDefinitionDto rule2 = db.rules().insert(r -> r.setKey(RuleKey.of("java", "S002")));
+    db.rules().insertOrUpdateMetadata(rule2, organization);
+    RuleDefinitionDto removedRule = db.rules().insert(r -> r.setStatus(REMOVED));
+
+    assertThat(underTest.selectByQuery(db.getSession(), organization.getUuid(), RuleQuery.create())).hasSize(2);
+    assertThat(underTest.selectByQuery(db.getSession(), organization.getUuid(), RuleQuery.create().withKey("S001"))).hasSize(1);
+    assertThat(underTest.selectByQuery(db.getSession(), organization.getUuid(), RuleQuery.create().withConfigKey("S1"))).hasSize(1);
+    assertThat(underTest.selectByQuery(db.getSession(), organization.getUuid(), RuleQuery.create().withRepositoryKey("java"))).hasSize(2);
+    assertThat(underTest.selectByQuery(db.getSession(), organization.getUuid(),
       RuleQuery.create().withKey("S001").withConfigKey("S1").withRepositoryKey("java"))).hasSize(1);
   }
 
   @Test
   public void select_by_query_populates_organizationUuid_even_when_organization_has_no_metadata() {
-    db.prepareDbUnit(getClass(), "shared.xml");
-    String organizationUuid = "org-1";
+    OrganizationDto organization = db.organizations().insert();
+    RuleDefinitionDto rule1 = db.rules().insert();
+    RuleDefinitionDto rule2 = db.rules().insert();
 
-    assertThat(underTest.selectByQuery(db.getSession(), organizationUuid, RuleQuery.create()))
+    assertThat(underTest.selectByQuery(db.getSession(), organization.getUuid(), RuleQuery.create()))
       .extracting(RuleDto::getOrganizationUuid)
-      .containsExactly(organizationUuid, organizationUuid);
+      .containsExactly(organization.getUuid(), organization.getUuid());
   }
 
   @Test
@@ -484,6 +476,7 @@ public class RuleDaoTest {
       .setSeverity(Severity.INFO)
       .setIsTemplate(true)
       .setIsExternal(true)
+      .setIsAdHoc(true)
       .setLanguage("dart")
       .setTemplateId(3)
       .setDefRemediationFunction(DebtRemediationFunction.Type.LINEAR_OFFSET.toString())
@@ -512,6 +505,7 @@ public class RuleDaoTest {
     assertThat(ruleDto.getLanguage()).isEqualTo("dart");
     assertThat(ruleDto.isTemplate()).isTrue();
     assertThat(ruleDto.isExternal()).isTrue();
+    assertThat(ruleDto.isAdHoc()).isTrue();
     assertThat(ruleDto.getTemplateId()).isEqualTo(3);
     assertThat(ruleDto.getDefRemediationFunction()).isEqualTo("LINEAR_OFFSET");
     assertThat(ruleDto.getDefRemediationGapMultiplier()).isEqualTo("5d");
@@ -527,10 +521,9 @@ public class RuleDaoTest {
 
   @Test
   public void update_RuleDefinitionDto() {
-    db.prepareDbUnit(getClass(), "update.xml");
-
+    RuleDefinitionDto rule = db.rules().insert();
     RuleDefinitionDto ruleToUpdate = new RuleDefinitionDto()
-      .setId(1)
+      .setId(rule.getId())
       .setRuleKey("NewRuleKey")
       .setRepositoryKey("plugin")
       .setName("new name")
@@ -540,6 +533,8 @@ public class RuleDaoTest {
       .setConfigKey("NewConfigKey")
       .setSeverity(Severity.INFO)
       .setIsTemplate(true)
+      .setIsExternal(true)
+      .setIsAdHoc(true)
       .setLanguage("dart")
       .setTemplateId(3)
       .setDefRemediationFunction(DebtRemediationFunction.Type.LINEAR_OFFSET.toString())
@@ -566,7 +561,8 @@ public class RuleDaoTest {
     assertThat(ruleDto.getSeverity()).isEqualTo(0);
     assertThat(ruleDto.getLanguage()).isEqualTo("dart");
     assertThat(ruleDto.isTemplate()).isTrue();
-    assertThat(ruleDto.isExternal()).isFalse();
+    assertThat(ruleDto.isExternal()).isTrue();
+    assertThat(ruleDto.isAdHoc()).isTrue();
     assertThat(ruleDto.getTemplateId()).isEqualTo(3);
     assertThat(ruleDto.getDefRemediationFunction()).isEqualTo("LINEAR_OFFSET");
     assertThat(ruleDto.getDefRemediationGapMultiplier()).isEqualTo("5d");
@@ -576,17 +572,17 @@ public class RuleDaoTest {
     assertThat(ruleDto.getSecurityStandards()).containsOnly("owaspTop10:a1", "cwe:123");
     assertThat(ruleDto.getScope()).isEqualTo(Scope.ALL);
     assertThat(ruleDto.getType()).isEqualTo(RuleType.BUG.getDbConstant());
-    assertThat(ruleDto.getCreatedAt()).isEqualTo(1_500_000_000_000L);
+    assertThat(ruleDto.getCreatedAt()).isEqualTo(rule.getCreatedAt());
     assertThat(ruleDto.getUpdatedAt()).isEqualTo(2_000_000_000_000L);
   }
 
   @Test
   public void update_RuleMetadataDto_inserts_row_in_RULE_METADATA_if_not_exists_yet() {
-    db.prepareDbUnit(getClass(), "update.xml");
+    RuleDefinitionDto rule = db.rules().insert();
     String organizationUuid = "org-1";
 
     RuleMetadataDto metadataToUpdate = new RuleMetadataDto()
-      .setRuleId(1)
+      .setRuleId(rule.getId())
       .setOrganizationUuid(organizationUuid)
       .setNoteData("My note")
       .setNoteUserUuid("admin")
@@ -596,6 +592,10 @@ public class RuleDaoTest {
       .setRemediationGapMultiplier("1h")
       .setRemediationBaseEffort("5min")
       .setTags(newHashSet("tag1", "tag2"))
+      .setAdHocName("ad hoc name")
+      .setAdHocDescription("ad hoc desc")
+      .setAdHocSeverity(Severity.BLOCKER)
+      .setAdHocType(RuleType.CODE_SMELL)
       .setCreatedAt(3_500_000_000_000L)
       .setUpdatedAt(4_000_000_000_000L);
 
@@ -603,49 +603,43 @@ public class RuleDaoTest {
     db.getSession().commit();
 
     OrganizationDto organization = OrganizationTesting.newOrganizationDto().setUuid(organizationUuid);
-    RuleDto ruleDto = underTest.selectOrFailByKey(db.getSession(), organization, RuleKey.of("checkstyle", "AvoidNull"));
-    assertThat(ruleDto.getName()).isEqualTo("Avoid Null");
-    assertThat(ruleDto.getDescription()).isEqualTo("Should avoid NULL");
-    assertThat(ruleDto.getDescriptionFormat()).isNull();
-    assertThat(ruleDto.getStatus()).isEqualTo(RuleStatus.READY);
-    assertThat(ruleDto.getRuleKey()).isEqualTo("AvoidNull");
-    assertThat(ruleDto.getRepositoryKey()).isEqualTo("checkstyle");
-    assertThat(ruleDto.getConfigKey()).isEqualTo("AvoidNull");
-    assertThat(ruleDto.getSeverity()).isEqualTo(2);
-    assertThat(ruleDto.getLanguage()).isEqualTo("golo");
-    assertThat(ruleDto.isTemplate()).isFalse();
-    assertThat(ruleDto.getTemplateId()).isNull();
+    RuleDto ruleDto = underTest.selectOrFailByKey(db.getSession(), organization, rule.getKey());
     assertThat(ruleDto.getNoteData()).isEqualTo("My note");
     assertThat(ruleDto.getNoteUserUuid()).isEqualTo("admin");
     assertThat(ruleDto.getNoteCreatedAt()).isNotNull();
     assertThat(ruleDto.getNoteUpdatedAt()).isNotNull();
     assertThat(ruleDto.getRemediationFunction()).isEqualTo("LINEAR");
-    assertThat(ruleDto.getDefRemediationFunction()).isNull();
     assertThat(ruleDto.getRemediationGapMultiplier()).isEqualTo("1h");
-    assertThat(ruleDto.getDefRemediationGapMultiplier()).isNull();
     assertThat(ruleDto.getRemediationBaseEffort()).isEqualTo("5min");
-    assertThat(ruleDto.getDefRemediationBaseEffort()).isNull();
-    assertThat(ruleDto.getGapDescription()).isNull();
     assertThat(ruleDto.getTags()).containsOnly("tag1", "tag2");
-    assertThat(ruleDto.getSystemTags()).isEmpty();
+    assertThat(ruleDto.getAdHocName()).isEqualTo("ad hoc name");
+    assertThat(ruleDto.getAdHocDescription()).isEqualTo("ad hoc desc");
+    assertThat(ruleDto.getAdHocSeverity()).isEqualTo(Severity.BLOCKER);
+    assertThat(ruleDto.getAdHocType()).isEqualTo(RuleType.CODE_SMELL.getDbConstant());
     assertThat(ruleDto.getSecurityStandards()).isEmpty();
-    assertThat(ruleDto.getType()).isEqualTo(0);
     assertThat(ruleDto.getCreatedAt()).isEqualTo(3_500_000_000_000L);
     assertThat(ruleDto.getUpdatedAt()).isEqualTo(4_000_000_000_000L);
+    // Info from rule definition
+    assertThat(ruleDto.getDefRemediationFunction()).isEqualTo(rule.getDefRemediationFunction());
+    assertThat(ruleDto.getDefRemediationGapMultiplier()).isEqualTo(rule.getDefRemediationGapMultiplier());
+    assertThat(ruleDto.getDefRemediationBaseEffort()).isEqualTo(rule.getDefRemediationBaseEffort());
+    assertThat(ruleDto.getGapDescription()).isEqualTo(rule.getGapDescription());
+    assertThat(ruleDto.getSystemTags()).containsAll(rule.getSystemTags());
+    assertThat(ruleDto.getType()).isEqualTo(rule.getType());
   }
 
   @Test
   public void update_RuleMetadataDto_updates_row_in_RULE_METADATA_if_already_exists() {
-    db.prepareDbUnit(getClass(), "update.xml");
+    RuleDefinitionDto rule = db.rules().insert();
     String organizationUuid = "org-1";
     OrganizationDto organization = OrganizationTesting.newOrganizationDto().setUuid(organizationUuid);
     RuleMetadataDto metadataV1 = new RuleMetadataDto()
-      .setRuleId(1)
+      .setRuleId(rule.getId())
       .setOrganizationUuid(organizationUuid)
       .setCreatedAt(3_500_000_000_000L)
       .setUpdatedAt(4_000_000_000_000L);
     RuleMetadataDto metadataV2 = new RuleMetadataDto()
-      .setRuleId(1)
+      .setRuleId(rule.getId())
       .setOrganizationUuid(organizationUuid)
       .setNoteData("My note")
       .setNoteUserUuid("admin")
@@ -655,6 +649,10 @@ public class RuleDaoTest {
       .setRemediationGapMultiplier("1h")
       .setRemediationBaseEffort("5min")
       .setTags(newHashSet("tag1", "tag2"))
+      .setAdHocName("ad hoc name")
+      .setAdHocDescription("ad hoc desc")
+      .setAdHocSeverity(Severity.BLOCKER)
+      .setAdHocType(RuleType.CODE_SMELL)
       .setCreatedAt(6_500_000_000_000L)
       .setUpdatedAt(7_000_000_000_000L);
 
@@ -662,90 +660,69 @@ public class RuleDaoTest {
     db.commit();
 
     assertThat(db.countRowsOfTable("RULES_METADATA")).isEqualTo(1);
-    RuleDto ruleDto = underTest.selectOrFailByKey(db.getSession(), organization, RuleKey.of("checkstyle", "AvoidNull"));
-    assertThat(ruleDto.getName()).isEqualTo("Avoid Null");
-    assertThat(ruleDto.getDescription()).isEqualTo("Should avoid NULL");
-    assertThat(ruleDto.getDescriptionFormat()).isNull();
-    assertThat(ruleDto.getStatus()).isEqualTo(RuleStatus.READY);
-    assertThat(ruleDto.getRuleKey()).isEqualTo("AvoidNull");
-    assertThat(ruleDto.getRepositoryKey()).isEqualTo("checkstyle");
-    assertThat(ruleDto.getConfigKey()).isEqualTo("AvoidNull");
-    assertThat(ruleDto.getSeverity()).isEqualTo(2);
-    assertThat(ruleDto.getLanguage()).isEqualTo("golo");
-    assertThat(ruleDto.isTemplate()).isFalse();
-    assertThat(ruleDto.getTemplateId()).isNull();
+    RuleDto ruleDto = underTest.selectOrFailByKey(db.getSession(), organization, rule.getKey());
     assertThat(ruleDto.getNoteData()).isNull();
     assertThat(ruleDto.getNoteUserUuid()).isNull();
     assertThat(ruleDto.getNoteCreatedAt()).isNull();
     assertThat(ruleDto.getNoteUpdatedAt()).isNull();
     assertThat(ruleDto.getRemediationFunction()).isNull();
-    assertThat(ruleDto.getDefRemediationFunction()).isNull();
     assertThat(ruleDto.getRemediationGapMultiplier()).isNull();
-    assertThat(ruleDto.getDefRemediationGapMultiplier()).isNull();
     assertThat(ruleDto.getRemediationBaseEffort()).isNull();
-    assertThat(ruleDto.getDefRemediationBaseEffort()).isNull();
-    assertThat(ruleDto.getGapDescription()).isNull();
     assertThat(ruleDto.getTags()).isEmpty();
-    assertThat(ruleDto.getSystemTags()).isEmpty();
+    assertThat(ruleDto.getAdHocName()).isNull();
+    assertThat(ruleDto.getAdHocDescription()).isNull();
+    assertThat(ruleDto.getAdHocSeverity()).isNull();
+    assertThat(ruleDto.getAdHocType()).isNull();
     assertThat(ruleDto.getSecurityStandards()).isEmpty();
-    assertThat(ruleDto.getType()).isEqualTo(0);
     assertThat(ruleDto.getCreatedAt()).isEqualTo(3_500_000_000_000L);
     assertThat(ruleDto.getUpdatedAt()).isEqualTo(4_000_000_000_000L);
 
     underTest.insertOrUpdate(db.getSession(), metadataV2);
     db.commit();
 
-    ruleDto = underTest.selectOrFailByKey(db.getSession(), organization, RuleKey.of("checkstyle", "AvoidNull"));
-    assertThat(ruleDto.getName()).isEqualTo("Avoid Null");
-    assertThat(ruleDto.getDescription()).isEqualTo("Should avoid NULL");
-    assertThat(ruleDto.getDescriptionFormat()).isNull();
-    assertThat(ruleDto.getStatus()).isEqualTo(RuleStatus.READY);
-    assertThat(ruleDto.getRuleKey()).isEqualTo("AvoidNull");
-    assertThat(ruleDto.getRepositoryKey()).isEqualTo("checkstyle");
-    assertThat(ruleDto.getConfigKey()).isEqualTo("AvoidNull");
-    assertThat(ruleDto.getSeverity()).isEqualTo(2);
-    assertThat(ruleDto.getLanguage()).isEqualTo("golo");
-    assertThat(ruleDto.isTemplate()).isFalse();
-    assertThat(ruleDto.getTemplateId()).isNull();
+    ruleDto = underTest.selectOrFailByKey(db.getSession(), organization, rule.getKey());
     assertThat(ruleDto.getNoteData()).isEqualTo("My note");
     assertThat(ruleDto.getNoteUserUuid()).isEqualTo("admin");
     assertThat(ruleDto.getNoteCreatedAt()).isNotNull();
     assertThat(ruleDto.getNoteUpdatedAt()).isNotNull();
     assertThat(ruleDto.getRemediationFunction()).isEqualTo("LINEAR");
-    assertThat(ruleDto.getDefRemediationFunction()).isNull();
     assertThat(ruleDto.getRemediationGapMultiplier()).isEqualTo("1h");
-    assertThat(ruleDto.getDefRemediationGapMultiplier()).isNull();
     assertThat(ruleDto.getRemediationBaseEffort()).isEqualTo("5min");
-    assertThat(ruleDto.getDefRemediationBaseEffort()).isNull();
-    assertThat(ruleDto.getGapDescription()).isNull();
     assertThat(ruleDto.getTags()).containsOnly("tag1", "tag2");
-    assertThat(ruleDto.getSystemTags()).isEmpty();
+    assertThat(ruleDto.getAdHocName()).isEqualTo("ad hoc name");
+    assertThat(ruleDto.getAdHocDescription()).isEqualTo("ad hoc desc");
+    assertThat(ruleDto.getAdHocSeverity()).isEqualTo(Severity.BLOCKER);
+    assertThat(ruleDto.getAdHocType()).isEqualTo(RuleType.CODE_SMELL.getDbConstant());
     assertThat(ruleDto.getSecurityStandards()).isEmpty();
-    assertThat(ruleDto.getType()).isEqualTo(0);
     assertThat(ruleDto.getCreatedAt()).isEqualTo(3_500_000_000_000L);
     assertThat(ruleDto.getUpdatedAt()).isEqualTo(7_000_000_000_000L);
   }
 
   @Test
   public void select_parameters_by_rule_key() {
-    db.prepareDbUnit(getClass(), "select_parameters_by_rule_key.xml");
-    List<RuleParamDto> ruleDtos = underTest.selectRuleParamsByRuleKey(db.getSession(), RuleKey.of("checkstyle", "AvoidNull"));
+    RuleDefinitionDto rule = db.rules().insert();
+    RuleParamDto ruleParam = db.rules().insertRuleParam(rule);
+
+    List<RuleParamDto> ruleDtos = underTest.selectRuleParamsByRuleKey(db.getSession(), rule.getKey());
 
     assertThat(ruleDtos.size()).isEqualTo(1);
     RuleParamDto ruleDto = ruleDtos.get(0);
-    assertThat(ruleDto.getId()).isEqualTo(1);
-    assertThat(ruleDto.getName()).isEqualTo("myParameter");
-    assertThat(ruleDto.getDescription()).isEqualTo("My Parameter");
-    assertThat(ruleDto.getType()).isEqualTo("plop");
-    assertThat(ruleDto.getRuleId()).isEqualTo(1);
+    assertThat(ruleDto.getId()).isEqualTo(ruleParam.getId());
+    assertThat(ruleDto.getName()).isEqualTo(ruleParam.getName());
+    assertThat(ruleDto.getDescription()).isEqualTo(ruleParam.getDescription());
+    assertThat(ruleDto.getType()).isEqualTo(ruleParam.getType());
+    assertThat(ruleDto.getRuleId()).isEqualTo(rule.getId());
   }
 
   @Test
   public void select_parameters_by_rule_keys() {
-    db.prepareDbUnit(getClass(), "select_parameters_by_rule_key.xml");
+    RuleDefinitionDto rule1 = db.rules().insert();
+    db.rules().insertRuleParam(rule1);
+    RuleDefinitionDto rule2 = db.rules().insert();
+    db.rules().insertRuleParam(rule2);
 
     assertThat(underTest.selectRuleParamsByRuleKeys(db.getSession(),
-      Arrays.asList(RuleKey.of("checkstyle", "AvoidNull"), RuleKey.of("unused", "Unused")))).hasSize(2);
+      Arrays.asList(rule1.getKey(), rule2.getKey()))).hasSize(2);
 
     assertThat(underTest.selectRuleParamsByRuleKeys(db.getSession(),
       singletonList(RuleKey.of("unknown", "Unknown")))).isEmpty();
@@ -792,35 +769,36 @@ public class RuleDaoTest {
 
   @Test
   public void update_parameter() {
-    db.prepareDbUnit(getClass(), "update_parameter.xml");
-
-    RuleDefinitionDto rule1 = underTest.selectOrFailDefinitionByKey(db.getSession(), RuleKey.of("checkstyle", "AvoidNull"));
+    RuleDefinitionDto rule = db.rules().insert();
+    RuleParamDto ruleParam = db.rules().insertRuleParam(rule);
 
-    List<RuleParamDto> params = underTest.selectRuleParamsByRuleKey(db.getSession(), rule1.getKey());
+    List<RuleParamDto> params = underTest.selectRuleParamsByRuleKey(db.getSession(), rule.getKey());
     assertThat(params).hasSize(1);
-
-    RuleParamDto param = Iterables.getFirst(params, null);
-    param
+    RuleParamDto param = new RuleParamDto()
+      .setId(ruleParam.getId())
+      .setRuleId(rule.getId())
+      // Name will not be updated
       .setName("format")
       .setType("STRING")
       .setDefaultValue("^[a-z]+(\\.[a-z][a-z0-9]*)*$")
       .setDescription("Regular expression used to check the package names against.");
 
-    underTest.updateRuleParam(db.getSession(), rule1, param);
-    db.getSession().commit();
+    underTest.updateRuleParam(db.getSession(), rule, param);
 
-    db.assertDbUnit(getClass(), "update_parameter-result.xml", "rules_parameters");
+    assertThat(underTest.selectRuleParamsByRuleKey(db.getSession(), rule.getKey()))
+      .extracting(RuleParamDto::getName, RuleParamDto::getType, RuleParamDto::getDefaultValue, RuleParamDto::getDescription)
+      .containsExactlyInAnyOrder(tuple(ruleParam.getName(), "STRING", "^[a-z]+(\\.[a-z][a-z0-9]*)*$", "Regular expression used to check the package names against."));
   }
 
   @Test
   public void delete_parameter() {
-    db.prepareDbUnit(getClass(), "select_parameters_by_rule_key.xml");
-    assertThat(underTest.selectRuleParamsByRuleKey(db.getSession(), RuleKey.of("checkstyle", "AvoidNull"))).hasSize(1);
+    RuleDefinitionDto rule = db.rules().insert();
+    RuleParamDto ruleParam = db.rules().insertRuleParam(rule);
+    assertThat(underTest.selectRuleParamsByRuleKey(db.getSession(), rule.getKey())).hasSize(1);
 
-    underTest.deleteRuleParam(db.getSession(), 1);
-    db.getSession().commit();
+    underTest.deleteRuleParam(db.getSession(), ruleParam.getId());
 
-    assertThat(underTest.selectRuleParamsByRuleKey(db.getSession(), RuleKey.of("checkstyle", "AvoidNull"))).isEmpty();
+    assertThat(underTest.selectRuleParamsByRuleKey(db.getSession(), rule.getKey())).isEmpty();
   }
 
   @Test
@@ -867,7 +845,6 @@ public class RuleDaoTest {
 
     RuleForIndexingDto secondRule = it.next();
     assertThat(secondRule.isExternal()).isTrue();
-
   }
 
   @Test
index 2828c0e8ce21540b7c7f66b093fba3f413736af6..6c725b665421c4d1bf351bd6c3966f4b46f34c8d 100644 (file)
@@ -78,6 +78,8 @@ public class RuleTesting {
       .setConfigKey("configKey_" + randomAlphanumeric(5))
       .setSeverity(Severity.ALL.get(nextInt(Severity.ALL.size())))
       .setIsTemplate(false)
+      .setIsExternal(false)
+      .setIsAdHoc(false)
       .setSystemTags(newHashSet("tag_" + randomAlphanumeric(5), "tag_" + randomAlphanumeric(5)))
       .setLanguage("lang_" + randomAlphanumeric(3))
       .setGapDescription("gapDescription_" + randomAlphanumeric(5))
diff --git a/server/sonar-db-dao/src/test/resources/org/sonar/db/rule/RuleDaoTest/insert_parameter-result.xml b/server/sonar-db-dao/src/test/resources/org/sonar/db/rule/RuleDaoTest/insert_parameter-result.xml
deleted file mode 100644 (file)
index 36b0c88..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-<dataset>
-  <rules system_tags="[null]"
-         id="1"
-         plugin_rule_key="NewRuleKey"
-         plugin_name="plugin"
-         name="new name"
-         description="new description"
-         status="DEPRECATED"
-         plugin_config_key="NewConfigKey"
-         priority="0"
-         is_template="[true]"
-         language="dart"
-         template_id="3"
-         def_remediation_function="linear_offset"
-         def_remediation_gap_mult="5d"
-         def_remediation_base_effort="10h"
-         gap_description="squid.S115.effortToFix"
-         created_at="[null]"
-         updated_at="[null]"
-  />
-  <rules_parameters id="1"
-                    rule_id="1"
-                    name="max"
-                    param_type="INTEGER"
-                    default_value="30"
-                    description="My Parameter"/>
-</dataset>
diff --git a/server/sonar-db-dao/src/test/resources/org/sonar/db/rule/RuleDaoTest/insert_parameter.xml b/server/sonar-db-dao/src/test/resources/org/sonar/db/rule/RuleDaoTest/insert_parameter.xml
deleted file mode 100644 (file)
index 8c39a2d..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-<dataset>
-  <rules system_tags="[null]"
-         id="1"
-         plugin_rule_key="NewRuleKey"
-         plugin_name="plugin"
-         name="new name"
-         description="new description"
-         status="DEPRECATED"
-         plugin_config_key="NewConfigKey"
-         priority="0"
-         is_template="[true]"
-         language="dart"
-         template_id="3"
-         def_remediation_function="linear_offset"
-         def_remediation_gap_mult="5d"
-         def_remediation_base_effort="10h"
-         gap_description="squid.S115.effortToFix"
-         scope="MAIN"
-         created_at="[null]"
-         updated_at="[null]"
-  />
-</dataset>
diff --git a/server/sonar-db-dao/src/test/resources/org/sonar/db/rule/RuleDaoTest/selectEnabled.xml b/server/sonar-db-dao/src/test/resources/org/sonar/db/rule/RuleDaoTest/selectEnabled.xml
deleted file mode 100644 (file)
index 593a6a4..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-<dataset>
-
-  <rules system_tags="[null]"
-         id="1"
-         plugin_rule_key="AvoidNull"
-         plugin_name="checkstyle"
-         name="Avoid Null"
-         description="Should avoid NULL"
-         description_format="HTML"
-         status="READY"
-         def_remediation_function="LINEAR_OFFSET"
-         def_remediation_gap_mult="5d"
-         def_remediation_base_effort="10h"
-         gap_description="squid.S115.effortToFix"
-         scope="MAIN"
-         created_at="1500000000000"
-         updated_at="1600000000000"
-  />
-
-  <rules system_tags="[null]"
-         id="2"
-         plugin_rule_key="AvoidNull"
-         plugin_name="squid"
-         name="Avoid Null"
-         description="Should avoid NULL"
-         description_format="HTML"
-         status="REMOVED"
-         def_remediation_function="[null]"
-         def_remediation_gap_mult="[null]"
-         def_remediation_base_effort="[null]"
-         scope="MAIN"
-         gap_description="[null]"
-         created_at="1500000000000"
-         updated_at="1600000000000"
-  />
-
-</dataset>
diff --git a/server/sonar-db-dao/src/test/resources/org/sonar/db/rule/RuleDaoTest/selectNonManual.xml b/server/sonar-db-dao/src/test/resources/org/sonar/db/rule/RuleDaoTest/selectNonManual.xml
deleted file mode 100644 (file)
index faebb44..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-<dataset>
-
-  <rules system_tags="[null]"
-         id="1"
-         plugin_rule_key="AvoidNull"
-         plugin_name="checkstyle"
-         name="Avoid Null"
-         description="Should avoid NULL"
-         status="READY"
-         description_format="HTML"
-         scope="MAIN"
-         created_at="1500000000000"
-         updated_at="1600000000000"/>
-  <rules system_tags="[null]"
-         id="2"
-         plugin_rule_key="AvoidNull"
-         plugin_name="manual"
-         name="Manual Rule"
-         description="Should not appear"
-         status="READY"
-         description_format="HTML"
-         scope="MAIN"
-         created_at="1500000000000"
-         updated_at="1600000000000"/>
-
-</dataset>
diff --git a/server/sonar-db-dao/src/test/resources/org/sonar/db/rule/RuleDaoTest/select_parameters_by_rule_key.xml b/server/sonar-db-dao/src/test/resources/org/sonar/db/rule/RuleDaoTest/select_parameters_by_rule_key.xml
deleted file mode 100644 (file)
index 49b9773..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-<dataset>
-
-  <rules system_tags="[null]"
-         id="1"
-         plugin_rule_key="AvoidNull"
-         plugin_name="checkstyle"
-         name="Avoid Null"
-         description="Should avoid NULL"
-         status="READY"
-         scope="MAIN"
-         created_at="1500000000000"
-         updated_at="1600000000000"/>
-  <rules_parameters id="1"
-                    rule_id="1"
-                    name="myParameter"
-                    param_type="plop"
-                    default_value="plouf"
-                    description="My Parameter"/>
-
-  <rules system_tags="[null]"
-         id="2"
-         plugin_rule_key="Unused"
-         plugin_name="unused"
-         name="Unused Rule"
-         description="Not used"
-         status="REMOVED"
-         scope="MAIN"
-         created_at="1500000000000"
-         updated_at="1600000000000"/>
-  <rules_parameters id="2"
-                    rule_id="2"
-                    name="otherParam"
-                    param_type="plop"
-                    default_value="plouf"
-                    description="Other Parameter"/>
-
-</dataset>
diff --git a/server/sonar-db-dao/src/test/resources/org/sonar/db/rule/RuleDaoTest/shared.xml b/server/sonar-db-dao/src/test/resources/org/sonar/db/rule/RuleDaoTest/shared.xml
deleted file mode 100644 (file)
index 5014ce5..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-<dataset>
-
-  <rules id="1"
-         name="Null Pointer"
-         plugin_rule_key="S001"
-         plugin_config_key="S1"
-         plugin_name="java"
-         description="[null]"
-         priority="4"
-         status="READY"
-         is_template="[false]"
-         template_id="[null]"
-         system_tags="cwe"
-         created_at="1500000000000"
-         updated_at="1600000000000"
-         scope="ALL"
-  />
-
-  <rules id="2"
-         name="Slow"
-         plugin_rule_key="S002"
-         plugin_config_key="S2"
-         plugin_name="java"
-         description="[null]"
-         priority="4"
-         status="BETA"
-         is_template="[false]"
-         template_id="[null]"
-         system_tags="[null]"
-         created_at="1500000000000"
-         updated_at="1600000000000"
-         scope="ALL"
-  />
-
-  <rules id="10"
-         name="Removed"
-         plugin_rule_key="S003"
-         plugin_config_key="S3"
-         plugin_name="java"
-         description="[null]"
-         priority="4"
-         status="REMOVED"
-         is_template="[false]"
-         template_id="[null]"
-         system_tags="[null]"
-         created_at="1500000000000"
-         updated_at="1600000000000"
-         scope="ALL"
-  />
-
-</dataset>
diff --git a/server/sonar-db-dao/src/test/resources/org/sonar/db/rule/RuleDaoTest/update.xml b/server/sonar-db-dao/src/test/resources/org/sonar/db/rule/RuleDaoTest/update.xml
deleted file mode 100644 (file)
index b0050d1..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-<dataset>
-
-  <rules system_tags="[null]"
-         id="1"
-         plugin_rule_key="AvoidNull"
-         plugin_name="checkstyle"
-         name="Avoid Null"
-         description="Should avoid NULL"
-         status="READY"
-         plugin_config_key="AvoidNull"
-         priority="2"
-         is_template="[false]"
-         scope="MAIN"
-         language="golo"
-         created_at="1500000000000"
-         updated_at="1600000000000"/>
-
-</dataset>
diff --git a/server/sonar-db-dao/src/test/resources/org/sonar/db/rule/RuleDaoTest/update_parameter-result.xml b/server/sonar-db-dao/src/test/resources/org/sonar/db/rule/RuleDaoTest/update_parameter-result.xml
deleted file mode 100644 (file)
index bb3801d..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-<dataset>
-  <rules system_tags="[null]"
-         id="1"
-         plugin_rule_key="AvoidNull"
-         plugin_name="checkstyle"
-         name="Avoid Null"
-         description="Should avoid NULL"
-         status="READY"
-         scope="MAIN"
-         created_at="1500000000000"
-         updated_at="1600000000000"/>
-
-  <rules_parameters id="1"
-                    rule_id="1"
-                    name="max"
-                    param_type="STRING"
-                    default_value="^[a-z]+(\.[a-z][a-z0-9]*)*$"
-                    description="Regular expression used to check the package names against."/>
-</dataset>
diff --git a/server/sonar-db-dao/src/test/resources/org/sonar/db/rule/RuleDaoTest/update_parameter.xml b/server/sonar-db-dao/src/test/resources/org/sonar/db/rule/RuleDaoTest/update_parameter.xml
deleted file mode 100644 (file)
index 484f86c..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-<dataset>
-  <rules system_tags="[null]"
-         id="1"
-         plugin_rule_key="AvoidNull"
-         plugin_name="checkstyle"
-         name="Avoid Null"
-         description="Should avoid NULL"
-         status="READY"
-         scope="MAIN"
-         created_at="1500000000000"
-         updated_at="1600000000000"/>
-
-  <rules_parameters id="1"
-                    rule_id="1"
-                    name="max"
-                    param_type="INTEGER"
-                    default_value="30"
-                    description="My Parameter"/>
-</dataset>
index 0e4b55a68e0fd9f1d213d72f87073cfec1669ea0..f5ffda01c3d6b5794d60d2f940cc3498477710ea 100644 (file)
@@ -37,6 +37,7 @@ import org.sonar.server.platform.db.migration.version.v70.DbVersion70;
 import org.sonar.server.platform.db.migration.version.v71.DbVersion71;
 import org.sonar.server.platform.db.migration.version.v72.DbVersion72;
 import org.sonar.server.platform.db.migration.version.v73.DbVersion73;
+import org.sonar.server.platform.db.migration.version.v74.DbVersion74;
 
 public class MigrationConfigurationModule extends Module {
   @Override
@@ -57,6 +58,7 @@ public class MigrationConfigurationModule extends Module {
       DbVersion71.class,
       DbVersion72.class,
       DbVersion73.class,
+      DbVersion74.class,
 
       // migration steps
       MigrationStepRegistryImpl.class,
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v74/AddIsAdHocToRules.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v74/AddIsAdHocToRules.java
new file mode 100644 (file)
index 0000000..ff1e16d
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.platform.db.migration.version.v74;
+
+import java.sql.SQLException;
+import org.sonar.db.Database;
+import org.sonar.server.platform.db.migration.SupportsBlueGreen;
+import org.sonar.server.platform.db.migration.sql.AddColumnsBuilder;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+import static org.sonar.server.platform.db.migration.def.BooleanColumnDef.newBooleanColumnDefBuilder;
+
+@SupportsBlueGreen
+public class AddIsAdHocToRules extends DdlChange {
+
+  public AddIsAdHocToRules(Database db) {
+    super(db);
+  }
+
+  @Override
+  public void execute(Context context) throws SQLException {
+    context.execute(new AddColumnsBuilder(getDialect(), "rules")
+      .addColumn(newBooleanColumnDefBuilder()
+        .setColumnName("is_ad_hoc")
+        .setIsNullable(true)
+        .build())
+      .build());
+  }
+
+}
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v74/DbVersion74.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v74/DbVersion74.java
new file mode 100644 (file)
index 0000000..569a5ac
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.platform.db.migration.version.v74;
+
+import org.sonar.server.platform.db.migration.step.MigrationStepRegistry;
+import org.sonar.server.platform.db.migration.version.DbVersion;
+
+public class DbVersion74 implements DbVersion {
+
+  @Override
+  public void addSteps(MigrationStepRegistry registry) {
+    registry
+      .add(2300, "Populate null values of IS_EXTERNAL in RULES", PopulateNullValuesOfIsExternalOnRules.class)
+      .add(2301, "Add IS_ADHOC column to RULES table", AddIsAdHocToRules.class)
+      .add(2302, "Populate IS_AD_HOC in RULES", PopulateIsAdHocOnRules.class)
+      .add(2303, "Set IS_EXTERNAL and IS_AD_HOC not nullable in RULES", SetIsExternalAndIsAdHocNotNullableInRules.class)
+    ;
+  }
+}
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v74/PopulateIsAdHocOnRules.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v74/PopulateIsAdHocOnRules.java
new file mode 100644 (file)
index 0000000..716b597
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.platform.db.migration.version.v74;
+
+import java.sql.SQLException;
+import org.sonar.api.utils.System2;
+import org.sonar.db.Database;
+import org.sonar.server.platform.db.migration.SupportsBlueGreen;
+import org.sonar.server.platform.db.migration.step.DataChange;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
+
+@SupportsBlueGreen
+public class PopulateIsAdHocOnRules extends DataChange {
+
+  private final System2 system2;
+
+  public PopulateIsAdHocOnRules(Database db, System2 system2) {
+    super(db);
+    this.system2 = system2;
+  }
+
+  @Override
+  protected void execute(Context context) throws SQLException {
+    long now = system2.now();
+    MassUpdate massUpdate = context.prepareMassUpdate().rowPluralName("rules");
+    massUpdate.select("SELECT r.id, r.is_external FROM rules r WHERE r.is_ad_hoc IS NULL");
+    massUpdate.update("UPDATE rules SET is_ad_hoc=?, updated_at=? WHERE id=?");
+    massUpdate.execute((row, update) -> {
+      int id = row.getInt(1);
+      update.setBoolean(1, row.getBoolean(2));
+      update.setLong(2, now);
+      update.setInt(3, id);
+      return true;
+    });
+  }
+
+}
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v74/PopulateNullValuesOfIsExternalOnRules.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v74/PopulateNullValuesOfIsExternalOnRules.java
new file mode 100644 (file)
index 0000000..120a7c0
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.platform.db.migration.version.v74;
+
+import java.sql.SQLException;
+import org.sonar.api.utils.System2;
+import org.sonar.db.Database;
+import org.sonar.server.platform.db.migration.SupportsBlueGreen;
+import org.sonar.server.platform.db.migration.step.DataChange;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
+
+@SupportsBlueGreen
+public class PopulateNullValuesOfIsExternalOnRules extends DataChange {
+
+  private final System2 system2;
+
+  public PopulateNullValuesOfIsExternalOnRules(Database db, System2 system2) {
+    super(db);
+    this.system2 = system2;
+  }
+
+  @Override
+  protected void execute(Context context) throws SQLException {
+    long now = system2.now();
+    MassUpdate massUpdate = context.prepareMassUpdate().rowPluralName("rules");
+    massUpdate.select("SELECT r.id FROM rules r WHERE r.is_external IS NULL");
+    massUpdate.update("UPDATE rules SET is_external=?, updated_at=? WHERE id=?");
+    massUpdate.execute((row, update) -> {
+      int id = row.getInt(1);
+      update.setBoolean(1, false);
+      update.setLong(2, now);
+      update.setInt(3, id);
+      return true;
+    });
+  }
+
+}
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v74/SetIsExternalAndIsAdHocNotNullableInRules.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v74/SetIsExternalAndIsAdHocNotNullableInRules.java
new file mode 100644 (file)
index 0000000..2c72852
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.platform.db.migration.version.v74;
+
+import java.sql.SQLException;
+import org.sonar.db.Database;
+import org.sonar.server.platform.db.migration.SupportsBlueGreen;
+import org.sonar.server.platform.db.migration.sql.AlterColumnsBuilder;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+import static org.sonar.server.platform.db.migration.def.BooleanColumnDef.newBooleanColumnDefBuilder;
+
+@SupportsBlueGreen
+public class SetIsExternalAndIsAdHocNotNullableInRules extends DdlChange {
+
+  public SetIsExternalAndIsAdHocNotNullableInRules(Database db) {
+    super(db);
+  }
+
+  @Override
+  public void execute(Context context) throws SQLException {
+    context.execute(new AlterColumnsBuilder(getDialect(), "rules")
+      .updateColumn(newBooleanColumnDefBuilder()
+        .setColumnName("is_external")
+        .setIsNullable(false)
+        .build())
+      .updateColumn(newBooleanColumnDefBuilder()
+        .setColumnName("is_ad_hoc")
+        .setIsNullable(false)
+        .build())
+      .build());
+  }
+}
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v74/package-info.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v74/package-info.java
new file mode 100644 (file)
index 0000000..d57baa7
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program 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.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.server.platform.db.migration.version.v74;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
index 5ff4a49cd981b9741029535f274c09f17d5a5a50..f0d5c74a350a1475632e4fc9ce64515656d39e37 100644 (file)
@@ -37,7 +37,7 @@ public class MigrationConfigurationModuleTest {
     assertThat(container.getPicoContainer().getComponentAdapters())
       .hasSize(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER
         // DbVersion classes
-        + 14
+        + 15
         // Others
         + 3);
   }
diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v74/AddIsAdHocToRulesTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v74/AddIsAdHocToRulesTest.java
new file mode 100644 (file)
index 0000000..2b30280
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.platform.db.migration.version.v74;
+
+import java.sql.SQLException;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.db.CoreDbTester;
+
+import static java.sql.Types.BOOLEAN;
+
+public class AddIsAdHocToRulesTest {
+  @Rule
+  public final CoreDbTester db = CoreDbTester.createForSchema(AddIsAdHocToRulesTest.class, "rules.sql");
+
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+
+  private AddIsAdHocToRules underTest = new AddIsAdHocToRules(db.database());
+
+  @Test
+  public void column_is_added_to_table() throws SQLException {
+    underTest.execute();
+
+    db.assertColumnDefinition("rules", "is_ad_hoc", BOOLEAN, null, true);
+  }
+
+  @Test
+  public void migration_is_not_reentrant() throws SQLException {
+    underTest.execute();
+
+    expectedException.expect(IllegalStateException.class);
+
+    underTest.execute();
+  }
+
+}
diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v74/DbVersion74Test.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v74/DbVersion74Test.java
new file mode 100644 (file)
index 0000000..2806298
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.platform.db.migration.version.v74;
+
+import org.junit.Test;
+
+import static org.sonar.server.platform.db.migration.version.DbVersionTestUtils.verifyMigrationCount;
+import static org.sonar.server.platform.db.migration.version.DbVersionTestUtils.verifyMinimumMigrationNumber;
+
+public class DbVersion74Test {
+
+  private DbVersion74 underTest = new DbVersion74();
+
+  @Test
+  public void migrationNumber_starts_at_2300() {
+    verifyMinimumMigrationNumber(underTest, 2300);
+  }
+
+  @Test
+  public void verify_migration_count() {
+    verifyMigrationCount(underTest, 4);
+  }
+}
diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v74/PopulateIsAdHocOnRulesTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v74/PopulateIsAdHocOnRulesTest.java
new file mode 100644 (file)
index 0000000..f8616e3
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.platform.db.migration.version.v74;
+
+import java.sql.SQLException;
+import java.util.stream.Collectors;
+import javax.annotation.Nullable;
+import org.assertj.core.groups.Tuple;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.utils.System2;
+import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.db.CoreDbTester;
+
+import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.tuple;
+
+public class PopulateIsAdHocOnRulesTest {
+
+  private final static long PAST = 10_000_000_000L;
+  private final static long NOW = 50_000_000_000L;
+
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+  @Rule
+  public CoreDbTester db = CoreDbTester.createForSchema(PopulateIsAdHocOnRulesTest.class, "rules.sql");
+
+  private System2 system2 = new TestSystem2().setNow(NOW);
+
+  private PopulateIsAdHocOnRules underTest = new PopulateIsAdHocOnRules(db.database(), system2);
+
+  @Test
+  public void set_is_ad_hoc_to_true_on_external_rules() throws SQLException {
+    insertRule(1, true, null);
+    insertRule(2, true, null);
+
+    underTest.execute();
+
+    assertRules(
+      tuple(1L, true, true, NOW),
+      tuple(2L, true, true, NOW));
+  }
+
+  @Test
+  public void set_is_ad_hoc_to_false_on_none_external_rules() throws SQLException {
+    insertRule(1, false, null);
+    insertRule(2, false, null);
+
+    underTest.execute();
+
+    assertRules(
+      tuple(1L, false, false, NOW),
+      tuple(2L, false, false, NOW));
+  }
+
+  @Test
+  public void does_nothing_when_is_ad_hoc_is_already_set() throws SQLException {
+    insertRule(1, true, true);
+    insertRule(2, false, false);
+
+    underTest.execute();
+
+    assertRules(
+      tuple(1L, true, true, PAST),
+      tuple(2L, false, false, PAST));
+  }
+
+  @Test
+  public void migration_is_re_entrant() throws SQLException {
+    insertRule(1, true, null);
+    insertRule(2, false, null);
+
+    underTest.execute();
+    underTest.execute();
+
+    assertRules(
+      tuple(1L, true, true, NOW),
+      tuple(2L, false, false, NOW));
+  }
+
+  private void assertRules(Tuple... expectedTuples) {
+    assertThat(db.select("SELECT ID, IS_EXTERNAL, IS_AD_HOC, UPDATED_AT FROM RULES")
+      .stream()
+      .map(row -> new Tuple(row.get("ID"), row.get("IS_EXTERNAL"), row.get("IS_AD_HOC"), row.get("UPDATED_AT")))
+      .collect(Collectors.toList()))
+        .containsExactlyInAnyOrder(expectedTuples);
+  }
+
+  private void insertRule(int id, boolean isEternal, @Nullable Boolean isAdHoc) {
+    db.executeInsert("RULES",
+      "ID", id,
+      "IS_EXTERNAL", isEternal,
+      "IS_AD_HOC", isAdHoc,
+      "PLUGIN_RULE_KEY", randomAlphanumeric(3),
+      "PLUGIN_NAME", randomAlphanumeric(3),
+      "SCOPE", "MAIN",
+      "CREATED_AT", PAST,
+      "UPDATED_AT", PAST);
+  }
+
+}
diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v74/PopulateNullValuesOfIsExternalOnRulesTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v74/PopulateNullValuesOfIsExternalOnRulesTest.java
new file mode 100644 (file)
index 0000000..963f74a
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.platform.db.migration.version.v74;
+
+import java.sql.SQLException;
+import java.util.stream.Collectors;
+import javax.annotation.Nullable;
+import org.assertj.core.groups.Tuple;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.utils.System2;
+import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.db.CoreDbTester;
+
+import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.tuple;
+
+public class PopulateNullValuesOfIsExternalOnRulesTest {
+
+  private final static long PAST = 10_000_000_000L;
+  private final static long NOW = 50_000_000_000L;
+
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+  @Rule
+  public CoreDbTester db = CoreDbTester.createForSchema(PopulateNullValuesOfIsExternalOnRulesTest.class, "rules.sql");
+
+  private System2 system2 = new TestSystem2().setNow(NOW);
+
+  private PopulateNullValuesOfIsExternalOnRules underTest = new PopulateNullValuesOfIsExternalOnRules(db.database(), system2);
+
+  @Test
+  public void set_is_external_to_false() throws SQLException {
+    insertRule(1, null);
+    insertRule(2, null);
+
+    underTest.execute();
+
+    assertRules(
+      tuple(1L, false, NOW),
+      tuple(2L, false, NOW));
+  }
+
+  @Test
+  public void does_nothing_when_is_external_is_already_set() throws SQLException {
+    insertRule(1, true);
+    insertRule(2, false);
+
+    underTest.execute();
+
+    assertRules(
+      tuple(1L, true, PAST),
+      tuple(2L, false, PAST));
+  }
+
+  @Test
+  public void migration_is_re_entrant() throws SQLException {
+    insertRule(1, null);
+
+    underTest.execute();
+    underTest.execute();
+
+    assertRules(
+      tuple(1L, false, NOW));
+  }
+
+  private void assertRules(Tuple... expectedTuples) {
+    assertThat(db.select("SELECT ID, IS_EXTERNAL, UPDATED_AT FROM RULES")
+      .stream()
+      .map(row -> new Tuple(row.get("ID"), row.get("IS_EXTERNAL"), row.get("UPDATED_AT")))
+      .collect(Collectors.toList()))
+        .containsExactlyInAnyOrder(expectedTuples);
+  }
+
+  private void insertRule(int id, @Nullable Boolean isEternal) {
+    db.executeInsert("RULES",
+      "ID", id,
+      "IS_EXTERNAL", isEternal,
+      "PLUGIN_RULE_KEY", randomAlphanumeric(3),
+      "PLUGIN_NAME", randomAlphanumeric(3),
+      "SCOPE", "MAIN",
+      "CREATED_AT", PAST,
+      "UPDATED_AT", PAST);
+  }
+
+}
diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v74/SetIsExternalAndIsAdHocNotNullableInRulesTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v74/SetIsExternalAndIsAdHocNotNullableInRulesTest.java
new file mode 100644 (file)
index 0000000..62b6183
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.platform.db.migration.version.v74;
+
+import java.sql.SQLException;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.db.CoreDbTester;
+
+import static java.sql.Types.BOOLEAN;
+
+public class SetIsExternalAndIsAdHocNotNullableInRulesTest {
+  @Rule
+  public final CoreDbTester db = CoreDbTester.createForSchema(SetIsExternalAndIsAdHocNotNullableInRulesTest.class, "rules.sql");
+
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+
+  private SetIsExternalAndIsAdHocNotNullableInRules underTest = new SetIsExternalAndIsAdHocNotNullableInRules(db.database());
+
+  @Test
+  public void columns_are_updated() throws SQLException {
+    underTest.execute();
+
+    db.assertColumnDefinition("rules", "is_external", BOOLEAN, null, false);
+    db.assertColumnDefinition("rules", "is_ad_hoc", BOOLEAN, null, false);
+  }
+
+  @Test
+  public void migration_is_reentrant() throws SQLException {
+    underTest.execute();
+
+    underTest.execute();
+  }
+
+}
diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v74/AddIsAdHocToRulesTest/rules.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v74/AddIsAdHocToRulesTest/rules.sql
new file mode 100644 (file)
index 0000000..19fd984
--- /dev/null
@@ -0,0 +1,27 @@
+CREATE TABLE "RULES" (
+  "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+  "PLUGIN_KEY" VARCHAR(200),
+  "PLUGIN_RULE_KEY" VARCHAR(200) NOT NULL,
+  "PLUGIN_NAME" VARCHAR(255) NOT NULL,
+  "DESCRIPTION" VARCHAR(16777215),
+  "DESCRIPTION_FORMAT" VARCHAR(20),
+  "PRIORITY" INTEGER,
+  "IS_TEMPLATE" BOOLEAN DEFAULT FALSE,
+  "IS_EXTERNAL" BOOLEAN,
+  "TEMPLATE_ID" INTEGER,
+  "PLUGIN_CONFIG_KEY" VARCHAR(200),
+  "NAME" VARCHAR(200),
+  "STATUS" VARCHAR(40),
+  "LANGUAGE" VARCHAR(20),
+  "SCOPE" VARCHAR(20) NOT NULL,
+  "DEF_REMEDIATION_FUNCTION" VARCHAR(20),
+  "DEF_REMEDIATION_GAP_MULT" VARCHAR(20),
+  "DEF_REMEDIATION_BASE_EFFORT" VARCHAR(20),
+  "GAP_DESCRIPTION" VARCHAR(4000),
+  "SYSTEM_TAGS" VARCHAR(4000),
+  "SECURITY_STANDARDS" VARCHAR(4000),
+  "RULE_TYPE" TINYINT,
+  "CREATED_AT" BIGINT,
+  "UPDATED_AT" BIGINT
+);
+CREATE UNIQUE INDEX "RULES_REPO_KEY" ON "RULES" ("PLUGIN_NAME", "PLUGIN_RULE_KEY");
\ No newline at end of file
diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v74/PopulateIsAdHocOnRulesTest/rules.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v74/PopulateIsAdHocOnRulesTest/rules.sql
new file mode 100644 (file)
index 0000000..2179b79
--- /dev/null
@@ -0,0 +1,28 @@
+CREATE TABLE "RULES" (
+  "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+  "PLUGIN_KEY" VARCHAR(200),
+  "PLUGIN_RULE_KEY" VARCHAR(200) NOT NULL,
+  "PLUGIN_NAME" VARCHAR(255) NOT NULL,
+  "DESCRIPTION" VARCHAR(16777215),
+  "DESCRIPTION_FORMAT" VARCHAR(20),
+  "PRIORITY" INTEGER,
+  "IS_TEMPLATE" BOOLEAN DEFAULT FALSE,
+  "IS_EXTERNAL" BOOLEAN,
+  "IS_AD_HOC" BOOLEAN,
+  "TEMPLATE_ID" INTEGER,
+  "PLUGIN_CONFIG_KEY" VARCHAR(200),
+  "NAME" VARCHAR(200),
+  "STATUS" VARCHAR(40),
+  "LANGUAGE" VARCHAR(20),
+  "SCOPE" VARCHAR(20) NOT NULL,
+  "DEF_REMEDIATION_FUNCTION" VARCHAR(20),
+  "DEF_REMEDIATION_GAP_MULT" VARCHAR(20),
+  "DEF_REMEDIATION_BASE_EFFORT" VARCHAR(20),
+  "GAP_DESCRIPTION" VARCHAR(4000),
+  "SYSTEM_TAGS" VARCHAR(4000),
+  "SECURITY_STANDARDS" VARCHAR(4000),
+  "RULE_TYPE" TINYINT,
+  "CREATED_AT" BIGINT,
+  "UPDATED_AT" BIGINT
+);
+CREATE UNIQUE INDEX "RULES_REPO_KEY" ON "RULES" ("PLUGIN_NAME", "PLUGIN_RULE_KEY");
\ No newline at end of file
diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v74/PopulateNullValuesOfIsExternalOnRulesTest/rules.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v74/PopulateNullValuesOfIsExternalOnRulesTest/rules.sql
new file mode 100644 (file)
index 0000000..19fd984
--- /dev/null
@@ -0,0 +1,27 @@
+CREATE TABLE "RULES" (
+  "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+  "PLUGIN_KEY" VARCHAR(200),
+  "PLUGIN_RULE_KEY" VARCHAR(200) NOT NULL,
+  "PLUGIN_NAME" VARCHAR(255) NOT NULL,
+  "DESCRIPTION" VARCHAR(16777215),
+  "DESCRIPTION_FORMAT" VARCHAR(20),
+  "PRIORITY" INTEGER,
+  "IS_TEMPLATE" BOOLEAN DEFAULT FALSE,
+  "IS_EXTERNAL" BOOLEAN,
+  "TEMPLATE_ID" INTEGER,
+  "PLUGIN_CONFIG_KEY" VARCHAR(200),
+  "NAME" VARCHAR(200),
+  "STATUS" VARCHAR(40),
+  "LANGUAGE" VARCHAR(20),
+  "SCOPE" VARCHAR(20) NOT NULL,
+  "DEF_REMEDIATION_FUNCTION" VARCHAR(20),
+  "DEF_REMEDIATION_GAP_MULT" VARCHAR(20),
+  "DEF_REMEDIATION_BASE_EFFORT" VARCHAR(20),
+  "GAP_DESCRIPTION" VARCHAR(4000),
+  "SYSTEM_TAGS" VARCHAR(4000),
+  "SECURITY_STANDARDS" VARCHAR(4000),
+  "RULE_TYPE" TINYINT,
+  "CREATED_AT" BIGINT,
+  "UPDATED_AT" BIGINT
+);
+CREATE UNIQUE INDEX "RULES_REPO_KEY" ON "RULES" ("PLUGIN_NAME", "PLUGIN_RULE_KEY");
\ No newline at end of file
diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v74/SetIsExternalAndIsAdHocNotNullableInRulesTest/rules.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v74/SetIsExternalAndIsAdHocNotNullableInRulesTest/rules.sql
new file mode 100644 (file)
index 0000000..2179b79
--- /dev/null
@@ -0,0 +1,28 @@
+CREATE TABLE "RULES" (
+  "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+  "PLUGIN_KEY" VARCHAR(200),
+  "PLUGIN_RULE_KEY" VARCHAR(200) NOT NULL,
+  "PLUGIN_NAME" VARCHAR(255) NOT NULL,
+  "DESCRIPTION" VARCHAR(16777215),
+  "DESCRIPTION_FORMAT" VARCHAR(20),
+  "PRIORITY" INTEGER,
+  "IS_TEMPLATE" BOOLEAN DEFAULT FALSE,
+  "IS_EXTERNAL" BOOLEAN,
+  "IS_AD_HOC" BOOLEAN,
+  "TEMPLATE_ID" INTEGER,
+  "PLUGIN_CONFIG_KEY" VARCHAR(200),
+  "NAME" VARCHAR(200),
+  "STATUS" VARCHAR(40),
+  "LANGUAGE" VARCHAR(20),
+  "SCOPE" VARCHAR(20) NOT NULL,
+  "DEF_REMEDIATION_FUNCTION" VARCHAR(20),
+  "DEF_REMEDIATION_GAP_MULT" VARCHAR(20),
+  "DEF_REMEDIATION_BASE_EFFORT" VARCHAR(20),
+  "GAP_DESCRIPTION" VARCHAR(4000),
+  "SYSTEM_TAGS" VARCHAR(4000),
+  "SECURITY_STANDARDS" VARCHAR(4000),
+  "RULE_TYPE" TINYINT,
+  "CREATED_AT" BIGINT,
+  "UPDATED_AT" BIGINT
+);
+CREATE UNIQUE INDEX "RULES_REPO_KEY" ON "RULES" ("PLUGIN_NAME", "PLUGIN_RULE_KEY");
\ No newline at end of file
index 32b9d329e79b7ccd47094b75fc566d9e17228466..59d4d28fcfefe11d29b41357d80c204c589ea881 100644 (file)
@@ -54,6 +54,7 @@ public class ExternalRuleCreatorTest {
 
     assertThat(rule1).isNotNull();
     assertThat(rule1.isExternal()).isTrue();
+    assertThat(rule1.isAdHoc()).isTrue();
     assertThat(rule1.getId()).isGreaterThan(0);
     assertThat(rule1.getKey()).isEqualTo(ruleKey);
     assertThat(rule1.getPluginKey()).isEqualTo("eslint");
index 5af7683e24730e14e78fe4fb662076b0568986c9..d257bf0cd0587068055533d22547d605db548fed 100644 (file)
@@ -5,7 +5,10 @@
          plugin_rule_key="AvoidCycles"
          plugin_config_key="[null]"
          plugin_name="squid"
-         scope="MAIN"/>
+         scope="MAIN"
+         is_external="[false]"
+         is_ad_hoc="[false]"
+  />
 
   <projects organization_uuid="org1"
             uuid="PROJECT"
index bd3b3d209ad0626f2b9785a82e2fcb20eb1678e1..eb58f9b90ce5cef99bf94599ba5065fbe791e7df 100644 (file)
@@ -5,7 +5,10 @@
          plugin_rule_key="AvoidCycles"
          plugin_config_key="[null]"
          plugin_name="squid"
-         scope="MAIN"/>
+         scope="MAIN"
+         is_external="[false]"
+         is_ad_hoc="[false]"
+  />
 
   <projects organization_uuid="org1"
             uuid="PROJECT"
index d7ab806a6208e3d6c43085d4d54a1e2ba1efb4d3..928529f177e239fc2c37ba0f0a821ec660ad1b21 100644 (file)
@@ -5,7 +5,10 @@
          plugin_rule_key="AvoidCycles"
          plugin_config_key="[null]"
          plugin_name="squid"
-         scope="MAIN"/>
+         scope="MAIN"
+         is_external="[false]"
+         is_ad_hoc="[false]"
+  />
 
   <!-- Project 1 -->
   <projects organization_uuid="org1"
index 01ce4b7f5a39d47e8673d67c5e799461d9ae4fef..8508e2eee2eae5d405a20802fe2e8e3bcb1bacff 100644 (file)
@@ -5,7 +5,10 @@
          plugin_rule_key="AvoidCycles"
          plugin_config_key="[null]"
          plugin_name="squid"
-         scope="MAIN"/>
+         scope="MAIN"
+         is_external="[false]"
+         is_ad_hoc="[false]"
+  />
 
   <projects organization_uuid="org1"
             uuid="PROJECT1"
index f1f43e28ddf82f7335fcc84f5b5e86cb8aae6de2..36631ed943040ed8de5df753695e89358a83462c 100644 (file)
@@ -5,7 +5,10 @@
          plugin_rule_key="AvoidCycles"
          plugin_config_key="[null]"
          plugin_name="squid"
-         scope="MAIN"/>
+         scope="MAIN"
+         is_external="[false]"
+         is_ad_hoc="[false]"
+  />
 
   <projects organization_uuid="org1"
             uuid="PROJECT1"
index 8301738e75e64a44c6ae5f96abe4fd5586b7d39b..620d5c6da7cb617cef3d6b96798da6f4fd9f5f93 100644 (file)
@@ -398,6 +398,7 @@ public class RegisterRules implements Startable {
       .setType(RuleType.valueOf(ruleDef.type().name()))
       .setScope(toDtoScope(ruleDef.scope()))
       .setIsExternal(ruleDef.repository().isExternal())
+      .setIsAdHoc(false)
       .setCreatedAt(system2.now())
       .setUpdatedAt(system2.now());
     if (ruleDef.htmlDescription() != null) {
@@ -476,6 +477,10 @@ public class RegisterRules implements Startable {
       dto.setType(type);
       changed = true;
     }
+    if (dto.isAdHoc()) {
+      dto.setIsAdHoc(false);
+      changed = true;
+    }
     return changed;
   }
 
@@ -654,7 +659,7 @@ public class RegisterRules implements Startable {
     recorder.getRemaining().forEach(rule -> {
       if (rule.isCustomRule()) {
         customRules.add(rule);
-      } else if (!rule.isExternal() && rule.getStatus() != RuleStatus.REMOVED) {
+      } else if (!rule.isAdHoc() && rule.getStatus() != RuleStatus.REMOVED) {
         removeRule(dbSession, recorder, rule);
       }
     });
index 78b157c4eb099b0955d66c902b5aa482648948fb..d5c423a5072f4d1cef1700f82729fb3b466776be 100644 (file)
@@ -171,6 +171,8 @@ public class RuleCreator {
       .setScope(templateRuleDto.getScope())
       .setSystemTags(templateRuleDto.getSystemTags())
       .setSecurityStandards(templateRuleDto.getSecurityStandards())
+      .setIsExternal(false)
+      .setIsAdHoc(false)
       .setCreatedAt(system2.now())
       .setUpdatedAt(system2.now());
     dbClient.ruleDao().insert(dbSession, ruleDefinition);
index 35961c13d98d28512cbcb6c60e8065833a9b4070..c64953012ee08b6e02bd428ac05b7281b76b37c4 100644 (file)
@@ -182,7 +182,7 @@ public class IssuesActionTest {
     IssueDto issueFromExteralruleOnFile = db.issues().insert(external, project, file, i -> i.setKee("ON_FILE_FROM_EXTERNAL").setType(randomRuleTypeExceptHotspot()));
     
     RuleDefinitionDto migrated = db.rules().insert();
-    db.executeUpdateSql("update rules set is_external = NULL where rules.id = ?", migrated.getId());
+    db.executeUpdateSql("update rules set is_external=? where rules.id = ?", false, migrated.getId());
     IssueDto issueFromMigratedRule = db.issues().insert(migrated, project, file, i -> i.setKee("MIGRATED").setType(randomRuleTypeExceptHotspot()));
 
     addPermissionTo(project);
index 270d5d4e3ae972711df9d755ce9e44eb93ddd49f..c80a87ce15b2847d2500fdc93f9ecefdb4fbca60 100644 (file)
@@ -79,6 +79,8 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
+import static org.sonar.api.rule.RuleStatus.READY;
+import static org.sonar.api.rule.RuleStatus.REMOVED;
 import static org.sonar.api.rule.Severity.BLOCKER;
 import static org.sonar.api.rule.Severity.INFO;
 import static org.sonar.api.server.rule.RulesDefinition.NewRepository;
@@ -105,7 +107,7 @@ public class RegisterRulesTest {
   @org.junit.Rule
   public ExpectedException expectedException = ExpectedException.none();
   @org.junit.Rule
-  public DbTester dbTester = DbTester.create(system);
+  public DbTester db = DbTester.create(system);
   @org.junit.Rule
   public EsTester es = EsTester.create();
   @org.junit.Rule
@@ -113,7 +115,7 @@ public class RegisterRulesTest {
 
   private QProfileRules qProfileRules = mock(QProfileRules.class);
   private WebServerRuleFinder webServerRuleFinder = mock(WebServerRuleFinder.class);
-  private DbClient dbClient = dbTester.getDbClient();
+  private DbClient dbClient = db.getDbClient();
   private RuleIndexer ruleIndexer;
   private ActiveRuleIndexer activeRuleIndexer;
   private RuleIndex ruleIndex;
@@ -127,7 +129,7 @@ public class RegisterRulesTest {
     ruleIndexer = new RuleIndexer(es.client(), dbClient);
     ruleIndex = new RuleIndex(es.client(), system);
     activeRuleIndexer = new ActiveRuleIndexer(dbClient, es.client());
-    defaultOrganization = dbTester.getDefaultOrganization();
+    defaultOrganization = db.getDefaultOrganization();
   }
 
   @Test
@@ -135,8 +137,8 @@ public class RegisterRulesTest {
     execute(new FakeRepositoryV1());
 
     // verify db
-    assertThat(dbClient.ruleDao().selectAllDefinitions(dbTester.getSession())).hasSize(3);
-    RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(dbTester.getSession(), dbTester.getDefaultOrganization(), RULE_KEY1);
+    assertThat(dbClient.ruleDao().selectAllDefinitions(db.getSession())).hasSize(3);
+    RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), db.getDefaultOrganization(), RULE_KEY1);
     assertThat(rule1.getName()).isEqualTo("One");
     assertThat(rule1.getDescription()).isEqualTo("Description of One");
     assertThat(rule1.getSeverityString()).isEqualTo(BLOCKER);
@@ -153,8 +155,9 @@ public class RegisterRulesTest {
     assertThat(rule1.getType()).isEqualTo(RuleType.CODE_SMELL.getDbConstant());
     assertThat(rule1.getPluginKey()).isEqualTo(FAKE_PLUGIN_KEY);
     assertThat(rule1.isExternal()).isFalse();
+    assertThat(rule1.isAdHoc()).isFalse();
 
-    RuleDto hotspotRule = dbClient.ruleDao().selectOrFailByKey(dbTester.getSession(), dbTester.getDefaultOrganization(), HOTSPOT_RULE_KEY);
+    RuleDto hotspotRule = dbClient.ruleDao().selectOrFailByKey(db.getSession(), db.getDefaultOrganization(), HOTSPOT_RULE_KEY);
     assertThat(hotspotRule.getName()).isEqualTo("Hotspot");
     assertThat(hotspotRule.getDescription()).isEqualTo("Minimal hotspot");
     assertThat(hotspotRule.getCreatedAt()).isEqualTo(DATE1.getTime());
@@ -162,18 +165,18 @@ public class RegisterRulesTest {
     assertThat(hotspotRule.getType()).isEqualTo(RuleType.SECURITY_HOTSPOT.getDbConstant());
     assertThat(hotspotRule.getSecurityStandards()).containsExactly("cwe:1", "cwe:123", "cwe:863", "owaspTop10:a1", "owaspTop10:a3");
 
-    List<RuleParamDto> params = dbClient.ruleDao().selectRuleParamsByRuleKey(dbTester.getSession(), RULE_KEY1);
+    List<RuleParamDto> params = dbClient.ruleDao().selectRuleParamsByRuleKey(db.getSession(), RULE_KEY1);
     assertThat(params).hasSize(2);
     RuleParamDto param = getParam(params, "param1");
     assertThat(param.getDescription()).isEqualTo("parameter one");
     assertThat(param.getDefaultValue()).isEqualTo("default1");
 
     // verify index
-    RuleDto rule2 = dbClient.ruleDao().selectOrFailByKey(dbTester.getSession(), dbTester.getDefaultOrganization(), RULE_KEY2);
+    RuleDto rule2 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), db.getDefaultOrganization(), RULE_KEY2);
     assertThat(ruleIndex.search(new RuleQuery(), new SearchOptions()).getIds()).containsOnly(rule1.getId(), rule2.getId(), hotspotRule.getId());
 
     // verify repositories
-    assertThat(dbClient.ruleRepositoryDao().selectAll(dbTester.getSession())).extracting(RuleRepositoryDto::getKey).containsOnly("fake");
+    assertThat(dbClient.ruleRepositoryDao().selectAll(db.getSession())).extracting(RuleRepositoryDto::getKey).containsOnly("fake");
   }
 
   @Test
@@ -181,8 +184,8 @@ public class RegisterRulesTest {
     execute(new ExternalRuleRepository());
 
     // verify db
-    assertThat(dbClient.ruleDao().selectAllDefinitions(dbTester.getSession())).hasSize(2);
-    RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(dbTester.getSession(), dbTester.getDefaultOrganization(), EXTERNAL_RULE_KEY1);
+    assertThat(dbClient.ruleDao().selectAllDefinitions(db.getSession())).hasSize(2);
+    RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), db.getDefaultOrganization(), EXTERNAL_RULE_KEY1);
     assertThat(rule1.getName()).isEqualTo("One");
     assertThat(rule1.getDescription()).isEqualTo("Description of One");
     assertThat(rule1.getSeverityString()).isEqualTo(BLOCKER);
@@ -199,8 +202,9 @@ public class RegisterRulesTest {
     assertThat(rule1.getType()).isEqualTo(RuleType.CODE_SMELL.getDbConstant());
     assertThat(rule1.getPluginKey()).isEqualTo(FAKE_PLUGIN_KEY);
     assertThat(rule1.isExternal()).isTrue();
+    assertThat(rule1.isAdHoc()).isFalse();
 
-    RuleDto hotspotRule = dbClient.ruleDao().selectOrFailByKey(dbTester.getSession(), dbTester.getDefaultOrganization(), EXTERNAL_HOTSPOT_RULE_KEY);
+    RuleDto hotspotRule = dbClient.ruleDao().selectOrFailByKey(db.getSession(), db.getDefaultOrganization(), EXTERNAL_HOTSPOT_RULE_KEY);
     assertThat(hotspotRule.getName()).isEqualTo("Hotspot");
     assertThat(hotspotRule.getDescription()).isEqualTo("Minimal hotspot");
     assertThat(hotspotRule.getCreatedAt()).isEqualTo(DATE1.getTime());
@@ -223,7 +227,7 @@ public class RegisterRulesTest {
     });
 
     // verify db
-    List<RuleDefinitionDto> rules = dbClient.ruleDao().selectAllDefinitions(dbTester.getSession());
+    List<RuleDefinitionDto> rules = dbClient.ruleDao().selectAllDefinitions(db.getSession());
     assertThat(rules)
       .extracting(RuleDefinitionDto::getKey)
       .extracting(RuleKey::rule)
@@ -238,13 +242,13 @@ public class RegisterRulesTest {
     execute(context -> context.createRepository("fake", "java").done());
 
     // verify db
-    assertThat(dbClient.ruleDao().selectAllDefinitions(dbTester.getSession()))
+    assertThat(dbClient.ruleDao().selectAllDefinitions(db.getSession()))
       .extracting(RuleDefinitionDto::getKey)
       .extracting(RuleKey::rule)
       .containsExactly(ruleKey);
-    assertThat(dbClient.ruleDao().selectAllDefinitions(dbTester.getSession()))
+    assertThat(dbClient.ruleDao().selectAllDefinitions(db.getSession()))
       .extracting(RuleDefinitionDto::getStatus)
-      .containsExactly(RuleStatus.REMOVED);
+      .containsExactly(REMOVED);
 
     // verify index
     assertThat(ruleIndex.search(new RuleQuery(), new SearchOptions()).getIds())
@@ -267,10 +271,10 @@ public class RegisterRulesTest {
     });
 
     // verify db
-    assertThat(dbClient.ruleDao().selectAllDefinitions(dbTester.getSession()))
+    assertThat(dbClient.ruleDao().selectAllDefinitions(db.getSession()))
       .hasSize(numberOfRules)
       .extracting(RuleDefinitionDto::getStatus)
-      .containsOnly(RuleStatus.READY);
+      .containsOnly(READY);
 
     // verify index
     assertThat(es.countDocuments(RuleIndexDefinition.INDEX_TYPE_RULE)).isEqualTo(numberOfRules);
@@ -281,10 +285,10 @@ public class RegisterRulesTest {
     execute(context -> context.createRepository("fake", "java").done());
 
     // verify db
-    assertThat(dbClient.ruleDao().selectAllDefinitions(dbTester.getSession()))
+    assertThat(dbClient.ruleDao().selectAllDefinitions(db.getSession()))
       .hasSize(numberOfRules)
       .extracting(RuleDefinitionDto::getStatus)
-      .containsOnly(RuleStatus.REMOVED);
+      .containsOnly(REMOVED);
 
     // verify index (documents are still in the index, but all are removed)
     assertThat(es.countDocuments(RuleIndexDefinition.INDEX_TYPE_RULE)).isEqualTo(numberOfRules);
@@ -295,36 +299,36 @@ public class RegisterRulesTest {
   @Test
   public void delete_repositories_that_have_been_uninstalled() {
     RuleRepositoryDto repository = new RuleRepositoryDto("findbugs", "java", "Findbugs");
-    DbSession dbSession = dbTester.getSession();
-    dbTester.getDbClient().ruleRepositoryDao().insertOrUpdate(dbSession, singletonList(repository));
+    DbSession dbSession = db.getSession();
+    db.getDbClient().ruleRepositoryDao().insertOrUpdate(dbSession, singletonList(repository));
     dbSession.commit();
 
     execute(new FakeRepositoryV1());
 
-    assertThat(dbTester.getDbClient().ruleRepositoryDao().selectAll(dbSession)).extracting(RuleRepositoryDto::getKey).containsOnly("fake");
+    assertThat(db.getDbClient().ruleRepositoryDao().selectAll(dbSession)).extracting(RuleRepositoryDto::getKey).containsOnly("fake");
   }
 
   @Test
   public void update_and_remove_rules_on_changes() {
     execute(new FakeRepositoryV1());
-    assertThat(dbClient.ruleDao().selectAllDefinitions(dbTester.getSession())).hasSize(3);
-    RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(dbTester.getSession(), defaultOrganization, RULE_KEY1);
-    RuleDto rule2 = dbClient.ruleDao().selectOrFailByKey(dbTester.getSession(), defaultOrganization, RULE_KEY2);
-    RuleDto hotspotRule = dbClient.ruleDao().selectOrFailByKey(dbTester.getSession(), defaultOrganization, HOTSPOT_RULE_KEY);
+    assertThat(dbClient.ruleDao().selectAllDefinitions(db.getSession())).hasSize(3);
+    RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY1);
+    RuleDto rule2 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY2);
+    RuleDto hotspotRule = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, HOTSPOT_RULE_KEY);
     assertThat(es.getIds(RuleIndexDefinition.INDEX_TYPE_RULE)).containsOnly(valueOf(rule1.getId()), valueOf(rule2.getId()), valueOf(hotspotRule.getId()));
 
     // user adds tags and sets markdown note
     rule1.setTags(newHashSet("usertag1", "usertag2"));
     rule1.setNoteData("user *note*");
     rule1.setNoteUserUuid("marius");
-    dbClient.ruleDao().insertOrUpdate(dbTester.getSession(), rule1.getMetadata());
-    dbTester.getSession().commit();
+    dbClient.ruleDao().insertOrUpdate(db.getSession(), rule1.getMetadata());
+    db.getSession().commit();
 
     when(system.now()).thenReturn(DATE2.getTime());
     execute(new FakeRepositoryV2());
 
     // rule1 has been updated
-    rule1 = dbClient.ruleDao().selectOrFailByKey(dbTester.getSession(), defaultOrganization, RULE_KEY1);
+    rule1 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY1);
     assertThat(rule1.getName()).isEqualTo("One v2");
     assertThat(rule1.getDescription()).isEqualTo("Description of One v2");
     assertThat(rule1.getSeverityString()).isEqualTo(INFO);
@@ -333,33 +337,33 @@ public class RegisterRulesTest {
     assertThat(rule1.getConfigKey()).isEqualTo("config1 v2");
     assertThat(rule1.getNoteData()).isEqualTo("user *note*");
     assertThat(rule1.getNoteUserUuid()).isEqualTo("marius");
-    assertThat(rule1.getStatus()).isEqualTo(RuleStatus.READY);
+    assertThat(rule1.getStatus()).isEqualTo(READY);
     assertThat(rule1.getType()).isEqualTo(RuleType.BUG.getDbConstant());
     assertThat(rule1.getCreatedAt()).isEqualTo(DATE1.getTime());
     assertThat(rule1.getUpdatedAt()).isEqualTo(DATE2.getTime());
     // TODO check remediation function
 
-    List<RuleParamDto> params = dbClient.ruleDao().selectRuleParamsByRuleKey(dbTester.getSession(), RULE_KEY1);
+    List<RuleParamDto> params = dbClient.ruleDao().selectRuleParamsByRuleKey(db.getSession(), RULE_KEY1);
     assertThat(params).hasSize(2);
     RuleParamDto param = getParam(params, "param1");
     assertThat(param.getDescription()).isEqualTo("parameter one v2");
     assertThat(param.getDefaultValue()).isEqualTo("default1 v2");
 
     // rule2 has been removed -> status set to REMOVED but db row is not deleted
-    rule2 = dbClient.ruleDao().selectOrFailByKey(dbTester.getSession(), defaultOrganization, RULE_KEY2);
-    assertThat(rule2.getStatus()).isEqualTo(RuleStatus.REMOVED);
+    rule2 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY2);
+    assertThat(rule2.getStatus()).isEqualTo(REMOVED);
     assertThat(rule2.getUpdatedAt()).isEqualTo(DATE2.getTime());
 
     // rule3 has been created
-    RuleDto rule3 = dbClient.ruleDao().selectOrFailByKey(dbTester.getSession(), defaultOrganization, RULE_KEY3);
+    RuleDto rule3 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY3);
     assertThat(rule3).isNotNull();
-    assertThat(rule3.getStatus()).isEqualTo(RuleStatus.READY);
+    assertThat(rule3.getStatus()).isEqualTo(READY);
 
     // verify index
     assertThat(ruleIndex.search(new RuleQuery(), new SearchOptions()).getIds()).containsOnly(rule1.getId(), rule3.getId());
 
     // verify repositories
-    assertThat(dbClient.ruleRepositoryDao().selectAll(dbTester.getSession())).extracting(RuleRepositoryDto::getKey).containsOnly("fake");
+    assertThat(dbClient.ruleRepositoryDao().selectAll(db.getSession())).extracting(RuleRepositoryDto::getKey).containsOnly("fake");
   }
 
   @Test
@@ -373,8 +377,8 @@ public class RegisterRulesTest {
       repo.done();
     });
 
-    OrganizationDto defaultOrganization = dbTester.getDefaultOrganization();
-    RuleDto rule = dbClient.ruleDao().selectOrFailByKey(dbTester.getSession(), defaultOrganization, RULE_KEY1);
+    OrganizationDto defaultOrganization = db.getDefaultOrganization();
+    RuleDto rule = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY1);
     assertThat(rule.getSystemTags()).containsOnly("tag1");
 
     execute((RulesDefinition) context -> {
@@ -386,7 +390,7 @@ public class RegisterRulesTest {
       repo.done();
     });
 
-    rule = dbClient.ruleDao().selectOrFailByKey(dbTester.getSession(), defaultOrganization, RULE_KEY1);
+    rule = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY1);
     assertThat(rule.getSystemTags()).containsOnly("tag1", "tag2");
   }
 
@@ -402,8 +406,8 @@ public class RegisterRulesTest {
       repo.done();
     });
 
-    OrganizationDto defaultOrganization = dbTester.getDefaultOrganization();
-    RuleDto rule = dbClient.ruleDao().selectOrFailByKey(dbTester.getSession(), defaultOrganization, RULE_KEY1);
+    OrganizationDto defaultOrganization = db.getDefaultOrganization();
+    RuleDto rule = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY1);
     assertThat(rule.getSecurityStandards()).containsOnly("cwe:123", "owaspTop10:a1");
 
     execute((RulesDefinition) context -> {
@@ -416,7 +420,7 @@ public class RegisterRulesTest {
       repo.done();
     });
 
-    rule = dbClient.ruleDao().selectOrFailByKey(dbTester.getSession(), defaultOrganization, RULE_KEY1);
+    rule = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY1);
     assertThat(rule.getSecurityStandards()).containsOnly("cwe:1", "cwe:123", "cwe:863", "owaspTop10:a1", "owaspTop10:a3");
   }
 
@@ -441,7 +445,7 @@ public class RegisterRulesTest {
     });
 
     // rule1 has been updated
-    RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(dbTester.getSession(), defaultOrganization, RuleKey.of("fake", "rule"));
+    RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RuleKey.of("fake", "rule"));
     assertThat(rule1.getName()).isEqualTo("Name2");
     assertThat(rule1.getDescription()).isEqualTo("Description");
 
@@ -464,7 +468,7 @@ public class RegisterRulesTest {
       repo.done();
     });
 
-    RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(dbTester.getSession(), defaultOrganization, RuleKey.of(repository, ruleKey1));
+    RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RuleKey.of(repository, ruleKey1));
     SearchIdResult<Integer> searchRule1 = ruleIndex.search(new RuleQuery().setQueryText("Name1"), new SearchOptions());
     assertThat(searchRule1.getIds()).containsOnly(rule1.getId());
     assertThat(searchRule1.getTotal()).isEqualTo(1);
@@ -480,7 +484,7 @@ public class RegisterRulesTest {
     });
 
     // rule2 is actually rule1
-    RuleDto rule2 = dbClient.ruleDao().selectOrFailByKey(dbTester.getSession(), defaultOrganization, RuleKey.of(repository, ruleKey2));
+    RuleDto rule2 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RuleKey.of(repository, ruleKey2));
     assertThat(rule2.getId()).isEqualTo(rule1.getId());
     assertThat(rule2.getName()).isEqualTo("Name2");
     assertThat(rule2.getDescription()).isEqualTo(rule1.getDescription());
@@ -506,7 +510,7 @@ public class RegisterRulesTest {
       repo.done();
     });
 
-    RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(dbTester.getSession(), defaultOrganization, RuleKey.of(repository1, ruleKey));
+    RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RuleKey.of(repository1, ruleKey));
     SearchIdResult<Integer> searchRule1 = ruleIndex.search(new RuleQuery().setQueryText("Name1"), new SearchOptions());
     assertThat(searchRule1.getIds()).containsOnly(rule1.getId());
     assertThat(searchRule1.getTotal()).isEqualTo(1);
@@ -522,7 +526,7 @@ public class RegisterRulesTest {
     });
 
     // rule2 is actually rule1
-    RuleDto rule2 = dbClient.ruleDao().selectOrFailByKey(dbTester.getSession(), defaultOrganization, RuleKey.of(repository2, ruleKey));
+    RuleDto rule2 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RuleKey.of(repository2, ruleKey));
     assertThat(rule2.getId()).isEqualTo(rule1.getId());
     assertThat(rule2.getName()).isEqualTo("Name2");
     assertThat(rule2.getDescription()).isEqualTo(rule1.getDescription());
@@ -547,7 +551,7 @@ public class RegisterRulesTest {
       repo.done();
     });
 
-    RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(dbTester.getSession(), defaultOrganization, RuleKey.of(repo1, ruleKey1));
+    RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RuleKey.of(repo1, ruleKey1));
     assertThat(ruleIndex.search(new RuleQuery().setQueryText(name), new SearchOptions()).getIds())
       .containsOnly(rule1.getId());
 
@@ -562,7 +566,7 @@ public class RegisterRulesTest {
     });
 
     // rule2 is actually rule1
-    RuleDto rule2 = dbClient.ruleDao().selectOrFailByKey(dbTester.getSession(), defaultOrganization, RuleKey.of(repo2, ruleKey2));
+    RuleDto rule2 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RuleKey.of(repo2, ruleKey2));
     assertThat(rule2.getId()).isEqualTo(rule1.getId());
     assertThat(rule2.getName()).isEqualTo(rule1.getName());
     assertThat(rule2.getDescription()).isEqualTo(rule1.getDescription());
@@ -596,7 +600,7 @@ public class RegisterRulesTest {
       repo.done();
     });
 
-    RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(dbTester.getSession(), defaultOrganization, RuleKey.of(repository1, ruleKey1));
+    RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RuleKey.of(repository1, ruleKey1));
     assertThat(ruleIndex.search(new RuleQuery().setQueryText("Name1"), new SearchOptions()).getIds())
       .containsOnly(rule1.getId());
 
@@ -613,7 +617,7 @@ public class RegisterRulesTest {
     });
 
     // rule2 is actually rule1
-    RuleDto rule2 = dbClient.ruleDao().selectOrFailByKey(dbTester.getSession(), defaultOrganization, RuleKey.of(repository2, ruleKey2));
+    RuleDto rule2 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RuleKey.of(repository2, ruleKey2));
     assertThat(rule2.getId()).isEqualTo(rule1.getId());
 
     assertThat(ruleIndex.search(new RuleQuery().setQueryText("Name2"), new SearchOptions()).getIds())
@@ -641,7 +645,7 @@ public class RegisterRulesTest {
     });
 
     // rule1 has been updated
-    RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(dbTester.getSession(), defaultOrganization, RuleKey.of("fake", "rule"));
+    RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RuleKey.of("fake", "rule"));
     assertThat(rule1.getName()).isEqualTo("Name");
     assertThat(rule1.getDescription()).isEqualTo("Desc2");
 
@@ -649,6 +653,48 @@ public class RegisterRulesTest {
     assertThat(ruleIndex.search(new RuleQuery().setQueryText("Desc1"), new SearchOptions()).getTotal()).isEqualTo(0);
   }
 
+  @Test
+  public void rule_previously_created_as_adhoc_becomes_none_adhoc() {
+    RuleDefinitionDto rule = db.rules().insert(r -> r.setRepositoryKey("external_fake").setIsExternal(true).setIsAdHoc(true));
+    when(system.now()).thenReturn(DATE2.getTime());
+    execute((RulesDefinition) context -> {
+      NewRepository repo = context.createExternalRepository("fake", rule.getLanguage());
+      repo.createRule(rule.getRuleKey())
+        .setName(rule.getName())
+        .setHtmlDescription(rule.getDescription());
+      repo.done();
+    });
+
+    RuleDto reloaded = dbClient.ruleDao().selectByKey(db.getSession(), defaultOrganization, rule.getKey()).get();
+    assertThat(reloaded.isAdHoc()).isFalse();
+  }
+
+  @Test
+  public void remove_no_more_defined_external_rule() {
+    RuleDefinitionDto rule = db.rules().insert(r -> r.setRepositoryKey("external_fake")
+      .setStatus(READY)
+      .setIsExternal(true)
+      .setIsAdHoc(false));
+
+    execute();
+
+    RuleDto reloaded = dbClient.ruleDao().selectByKey(db.getSession(), defaultOrganization, rule.getKey()).get();
+    assertThat(reloaded.getStatus()).isEqualTo(REMOVED);
+  }
+
+  @Test
+  public void do_not_remove_no_more_defined_ad_hoc_rule() {
+    RuleDefinitionDto rule = db.rules().insert(r -> r.setRepositoryKey("external_fake")
+      .setStatus(READY)
+      .setIsExternal(true)
+      .setIsAdHoc(true));
+
+    execute();
+
+    RuleDto reloaded = dbClient.ruleDao().selectByKey(db.getSession(), defaultOrganization, rule.getKey()).get();
+    assertThat(reloaded.getStatus()).isEqualTo(READY);
+  }
+
   @Test
   public void disable_then_enable_rule() {
     // Install rule
@@ -659,15 +705,15 @@ public class RegisterRulesTest {
     when(system.now()).thenReturn(DATE2.getTime());
     execute();
 
-    RuleDto rule = dbClient.ruleDao().selectOrFailByKey(dbTester.getSession(), defaultOrganization, RULE_KEY1);
-    assertThat(rule.getStatus()).isEqualTo(RuleStatus.REMOVED);
+    RuleDto rule = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY1);
+    assertThat(rule.getStatus()).isEqualTo(REMOVED);
     assertThat(ruleIndex.search(new RuleQuery().setKey(RULE_KEY1.toString()), new SearchOptions()).getTotal()).isEqualTo(0);
 
     // Re-install rule
     when(system.now()).thenReturn(DATE3.getTime());
     execute(new FakeRepositoryV1());
 
-    rule = dbClient.ruleDao().selectOrFailByKey(dbTester.getSession(), defaultOrganization, RULE_KEY1);
+    rule = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY1);
     assertThat(rule.getStatus()).isEqualTo(RuleStatus.BETA);
     assertThat(ruleIndex.search(new RuleQuery().setKey(RULE_KEY1.toString()), new SearchOptions()).getTotal()).isEqualTo(1);
   }
@@ -675,12 +721,12 @@ public class RegisterRulesTest {
   @Test
   public void do_not_update_rules_when_no_changes() {
     execute(new FakeRepositoryV1());
-    assertThat(dbClient.ruleDao().selectAllDefinitions(dbTester.getSession())).hasSize(3);
+    assertThat(dbClient.ruleDao().selectAllDefinitions(db.getSession())).hasSize(3);
 
     when(system.now()).thenReturn(DATE2.getTime());
     execute(new FakeRepositoryV1());
 
-    RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(dbTester.getSession(), defaultOrganization, RULE_KEY1);
+    RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY1);
     assertThat(rule1.getCreatedAt()).isEqualTo(DATE1.getTime());
     assertThat(rule1.getUpdatedAt()).isEqualTo(DATE1.getTime());
   }
@@ -688,36 +734,36 @@ public class RegisterRulesTest {
   @Test
   public void do_not_update_already_removed_rules() {
     execute(new FakeRepositoryV1());
-    assertThat(dbClient.ruleDao().selectAllDefinitions(dbTester.getSession())).hasSize(3);
+    assertThat(dbClient.ruleDao().selectAllDefinitions(db.getSession())).hasSize(3);
 
-    RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(dbTester.getSession(), defaultOrganization, RULE_KEY1);
-    RuleDto rule2 = dbClient.ruleDao().selectOrFailByKey(dbTester.getSession(), defaultOrganization, RULE_KEY2);
-    RuleDto hotspotRule = dbClient.ruleDao().selectOrFailByKey(dbTester.getSession(), defaultOrganization, HOTSPOT_RULE_KEY);
+    RuleDto rule1 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY1);
+    RuleDto rule2 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY2);
+    RuleDto hotspotRule = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, HOTSPOT_RULE_KEY);
     assertThat(es.getIds(RuleIndexDefinition.INDEX_TYPE_RULE)).containsOnly(valueOf(rule1.getId()), valueOf(rule2.getId()), valueOf(hotspotRule.getId()));
 
-    assertThat(rule2.getStatus()).isEqualTo(RuleStatus.READY);
+    assertThat(rule2.getStatus()).isEqualTo(READY);
 
     when(system.now()).thenReturn(DATE2.getTime());
     execute(new FakeRepositoryV2());
 
     // On MySQL, need to update a rule otherwise rule2 will be seen as READY, but why ???
-    dbClient.ruleDao().update(dbTester.getSession(), rule1.getDefinition());
-    dbTester.getSession().commit();
+    dbClient.ruleDao().update(db.getSession(), rule1.getDefinition());
+    db.getSession().commit();
 
     // rule2 is removed
-    rule2 = dbClient.ruleDao().selectOrFailByKey(dbTester.getSession(), defaultOrganization, RULE_KEY2);
-    RuleDto rule3 = dbClient.ruleDao().selectOrFailByKey(dbTester.getSession(), defaultOrganization, RULE_KEY3);
-    assertThat(rule2.getStatus()).isEqualTo(RuleStatus.REMOVED);
+    rule2 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY2);
+    RuleDto rule3 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY3);
+    assertThat(rule2.getStatus()).isEqualTo(REMOVED);
 
     assertThat(ruleIndex.search(new RuleQuery(), new SearchOptions()).getIds()).containsOnly(rule1.getId(), rule3.getId());
 
     when(system.now()).thenReturn(DATE3.getTime());
     execute(new FakeRepositoryV2());
-    dbTester.getSession().commit();
+    db.getSession().commit();
 
     // -> rule2 is still removed, but not update at DATE3
-    rule2 = dbClient.ruleDao().selectOrFailByKey(dbTester.getSession(), defaultOrganization, RULE_KEY2);
-    assertThat(rule2.getStatus()).isEqualTo(RuleStatus.REMOVED);
+    rule2 = dbClient.ruleDao().selectOrFailByKey(db.getSession(), defaultOrganization, RULE_KEY2);
+    assertThat(rule2.getStatus()).isEqualTo(REMOVED);
     assertThat(rule2.getUpdatedAt()).isEqualTo(DATE2.getTime());
 
     assertThat(ruleIndex.search(new RuleQuery(), new SearchOptions()).getIds()).containsOnly(rule1.getId(), rule3.getId());
@@ -726,15 +772,15 @@ public class RegisterRulesTest {
   @Test
   public void mass_insert() {
     execute(new BigRepository());
-    assertThat(dbTester.countRowsOfTable("rules")).isEqualTo(BigRepository.SIZE);
-    assertThat(dbTester.countRowsOfTable("rules_parameters")).isEqualTo(BigRepository.SIZE * 20);
+    assertThat(db.countRowsOfTable("rules")).isEqualTo(BigRepository.SIZE);
+    assertThat(db.countRowsOfTable("rules_parameters")).isEqualTo(BigRepository.SIZE * 20);
     assertThat(es.getIds(RuleIndexDefinition.INDEX_TYPE_RULE)).hasSize(BigRepository.SIZE);
   }
 
   @Test
   public void manage_repository_extensions() {
     execute(new FindbugsRepository(), new FbContribRepository());
-    List<RuleDefinitionDto> rules = dbClient.ruleDao().selectAllDefinitions(dbTester.getSession());
+    List<RuleDefinitionDto> rules = dbClient.ruleDao().selectAllDefinitions(db.getSession());
     assertThat(rules).hasSize(2);
     for (RuleDefinitionDto rule : rules) {
       assertThat(rule.getRepositoryKey()).isEqualTo("findbugs");
@@ -744,7 +790,7 @@ public class RegisterRulesTest {
   @Test
   public void remove_system_tags_when_plugin_does_not_provide_any() {
     // Rule already exists in DB, with some system tags
-    dbClient.ruleDao().insert(dbTester.getSession(), new RuleDefinitionDto()
+    dbClient.ruleDao().insert(db.getSession(), new RuleDefinitionDto()
       .setRuleKey("rule1")
       .setRepositoryKey("findbugs")
       .setName("Rule One")
@@ -752,12 +798,12 @@ public class RegisterRulesTest {
       .setDescription("Rule one description")
       .setDescriptionFormat(RuleDto.Format.HTML)
       .setSystemTags(newHashSet("tag1", "tag2")));
-    dbTester.getSession().commit();
+    db.getSession().commit();
 
     // Synchronize rule without tag
     execute(new FindbugsRepository());
 
-    List<RuleDefinitionDto> rules = dbClient.ruleDao().selectAllDefinitions(dbTester.getSession());
+    List<RuleDefinitionDto> rules = dbClient.ruleDao().selectAllDefinitions(db.getSession());
     assertThat(rules).hasSize(1);
     RuleDefinitionDto result = rules.get(0);
     assertThat(result.getKey()).isEqualTo(RuleKey.of("findbugs", "rule1"));
@@ -766,16 +812,16 @@ public class RegisterRulesTest {
 
   @Test
   public void ignore_template_rules_if_organizations_are_enabled() {
-    organizationFlags.enable(dbTester.getSession());
+    organizationFlags.enable(db.getSession());
     execute(new RepositoryWithOneTemplateRule());
 
-    List<RuleDefinitionDto> rules = dbClient.ruleDao().selectAllDefinitions(dbTester.getSession());
+    List<RuleDefinitionDto> rules = dbClient.ruleDao().selectAllDefinitions(db.getSession());
     assertThat(rules).hasSize(0);
   }
 
   @Test
   public void log_ignored_template_rules_if_organizations_are_enabled() {
-    organizationFlags.enable(dbTester.getSession());
+    organizationFlags.enable(db.getSession());
     execute(new RepositoryWithOneTemplateRule());
 
     assertThat(logTester.logs(LoggerLevel.INFO)).contains("Template rule test:rule1 will not be imported, because organizations are enabled.");
@@ -811,8 +857,8 @@ public class RegisterRulesTest {
       repo.done();
     });
 
-    List<RuleDefinitionDto> rules = dbClient.ruleDao().selectAllDefinitions(dbTester.getSession());
-    Set<DeprecatedRuleKeyDto> deprecatedRuleKeys = dbClient.ruleDao().selectAllDeprecatedRuleKeys(dbTester.getSession());
+    List<RuleDefinitionDto> rules = dbClient.ruleDao().selectAllDefinitions(db.getSession());
+    Set<DeprecatedRuleKeyDto> deprecatedRuleKeys = dbClient.ruleDao().selectAllDeprecatedRuleKeys(db.getSession());
     assertThat(rules).hasSize(1);
     assertThat(deprecatedRuleKeys).hasSize(2);
   }
@@ -847,8 +893,8 @@ public class RegisterRulesTest {
       repo.done();
     });
 
-    assertThat(dbClient.ruleDao().selectAllDefinitions(dbTester.getSession())).hasSize(1);
-    Set<DeprecatedRuleKeyDto> deprecatedRuleKeys = dbClient.ruleDao().selectAllDeprecatedRuleKeys(dbTester.getSession());
+    assertThat(dbClient.ruleDao().selectAllDefinitions(db.getSession())).hasSize(1);
+    Set<DeprecatedRuleKeyDto> deprecatedRuleKeys = dbClient.ruleDao().selectAllDeprecatedRuleKeys(db.getSession());
     assertThat(deprecatedRuleKeys).hasSize(2);
 
     execute(context -> {
@@ -864,8 +910,8 @@ public class RegisterRulesTest {
       repo.done();
     });
 
-    assertThat(dbClient.ruleDao().selectAllDefinitions(dbTester.getSession())).hasSize(1);
-    deprecatedRuleKeys = dbClient.ruleDao().selectAllDeprecatedRuleKeys(dbTester.getSession());
+    assertThat(dbClient.ruleDao().selectAllDefinitions(db.getSession())).hasSize(1);
+    deprecatedRuleKeys = dbClient.ruleDao().selectAllDeprecatedRuleKeys(db.getSession());
     assertThat(deprecatedRuleKeys).hasSize(0);
   }
 
@@ -984,7 +1030,7 @@ public class RegisterRulesTest {
       languages, system, organizationFlags, webServerRuleFinder, uuidFactory);
     task.start();
     // Execute a commit to refresh session state as the task is using its own session
-    dbTester.getSession().commit();
+    db.getSession().commit();
 
     verify(webServerRuleFinder).startCaching();
   }
@@ -1062,7 +1108,7 @@ public class RegisterRulesTest {
         // tag2 and tag3 removed, tag4 added
         .setTags("tag1", "tag4")
         .setType(RuleType.BUG)
-        .setStatus(RuleStatus.READY)
+        .setStatus(READY)
         .setGapDescription("squid.S115.effortToFix.v2");
       rule1.setDebtRemediationFunction(rule1.debtRemediationFunctions().linearWithOffset("6d", "2h"));
       rule1.createParam("param1").setDescription("parameter one v2").setDefaultValue("default1 v2");
index 4dff170b40e8d031180d2f68de27c3b4399cb6d9..fb11ffa0bf0419969f51c85c324176b5a5f63dc2 100644 (file)
@@ -104,6 +104,8 @@ public class RuleCreatorTest {
     assertThat(rule.getTags()).containsOnly("usertag1", "usertag2");
     assertThat(rule.getSystemTags()).containsOnly("tag1", "tag4");
     assertThat(rule.getSecurityStandards()).containsOnly("owaspTop10:a1", "cwe:123");
+    assertThat(rule.isExternal()).isFalse();
+    assertThat(rule.isAdHoc()).isFalse();
 
     List<RuleParamDto> params = dbTester.getDbClient().ruleDao().selectRuleParamsByRuleKey(dbSession, customRuleKey);
     assertThat(params).hasSize(1);
index 2607915bf612489720ba38b77f4e3ca62ce3ce59..63b66538ca92e8a67b28b75588cfd29593cfc0a6 100644 (file)
@@ -42,6 +42,8 @@
          def_remediation_base_effort="10h"
          gap_description="squid.S115.effortToFix"
          description_format="MARKDOWN"
+         is_external="[false]"
+         is_ad_hoc="[false]"
          created_at="150000"
          updated_at="150000"
          scope="MAIN"