@Test
  public void not_update_custom_rule_from_template_if_no_change() throws Exception {
    Rule templateRule = index.getByKey(RuleKey.of("xoo", "template1"));

    // Create custom rule
    RuleKey customRuleKey =
        tester
            .get(RuleCreator.class)
            .create(
                NewRule.createForCustomRule("CUSTOM_RULE", templateRule.key())
                    .setName("My custom")
                    .setHtmlDescription("Some description")
                    .setSeverity(Severity.MAJOR)
                    .setStatus(RuleStatus.READY)
                    .setParameters(ImmutableMap.of("format", "txt")));
    dbSession.commit();
    dbSession.clearCache();

    // Store updated at date
    Date updatedAt = index.getByKey(customRuleKey).updatedAt();

    // Re-execute startup tasks
    tester.get(Platform.class).executeStartupTasks();

    // Verify custom rule has not been updated
    Rule customRuleReloaded = index.getByKey(customRuleKey);
    assertThat(customRuleReloaded.updatedAt()).isEqualTo(updatedAt);
  }
  @Before
  public void before() {
    tester.clearDbAndIndexes();
    db = tester.get(DbClient.class);
    dbSession = db.openSession(false);
    ruleActivator = tester.get(RuleActivator.class);
    index = tester.get(ActiveRuleIndex.class);
    copier = tester.get(QProfileCopier.class);

    // create pre-defined rules
    RuleDto xooRule1 = RuleTesting.newXooX1().setSeverity("MINOR");
    RuleDto xooRule2 = RuleTesting.newXooX2().setSeverity("MAJOR");
    db.deprecatedRuleDao().insert(dbSession, xooRule1, xooRule2);
    db.deprecatedRuleDao()
        .insertRuleParam(
            dbSession,
            xooRule1,
            RuleParamDto.createFor(xooRule1)
                .setName("max")
                .setDefaultValue("10")
                .setType(RuleParamType.INTEGER.type()));

    // create pre-defined profile
    db.qualityProfileDao().insert(dbSession, QProfileTesting.newXooP1());
    dbSession.commit();
    dbSession.clearCache();
  }
  @Test
  public void deactivate_removed_rules_only_if_repository_still_exists() throws Exception {
    MockUserSession.set()
        .setGlobalPermissions(GlobalPermissions.QUALITY_PROFILE_ADMIN)
        .setLogin("me");

    // create a profile and activate rule
    db.qualityProfileDao().insert(dbSession, QProfileTesting.newXooP1());
    dbSession.commit();
    dbSession.clearCache();
    RuleActivation activation = new RuleActivation(RuleTesting.XOO_X1);
    tester.get(QProfileService.class).activate(QProfileTesting.XOO_P1_KEY, activation);
    dbSession.clearCache();

    // restart, x2 still exists -> deactivate x1
    rulesDefinition.includeX1 = false;
    rulesDefinition.includeX2 = true;
    tester.get(Platform.class).executeStartupTasks();
    dbSession.clearCache();
    assertThat(db.ruleDao().getByKey(dbSession, RuleKey.of("xoo", "x1")).getStatus())
        .isEqualTo(RuleStatus.REMOVED);
    assertThat(db.ruleDao().getByKey(dbSession, RuleKey.of("xoo", "x2")).getStatus())
        .isEqualTo(RuleStatus.READY);
    assertThat(db.activeRuleDao().findByProfileKey(dbSession, QProfileTesting.XOO_P1_KEY))
        .hasSize(0);
  }
  @Test
  public void do_not_deactivate_removed_rules_if_repository_accidentaly_uninstalled()
      throws Exception {
    MockUserSession.set()
        .setGlobalPermissions(GlobalPermissions.QUALITY_PROFILE_ADMIN)
        .setLogin("me");

    // create a profile and activate rule
    db.qualityProfileDao().insert(dbSession, QProfileTesting.newXooP1());
    dbSession.commit();
    dbSession.clearCache();
    RuleActivation activation = new RuleActivation(RuleTesting.XOO_X1);
    tester.get(QProfileService.class).activate(QProfileTesting.XOO_P1_KEY, activation);
    dbSession.clearCache();

    // restart without x1, x2, template1 -> keep active rule of x1
    rulesDefinition.includeX1 = false;
    rulesDefinition.includeX2 = false;
    rulesDefinition.includeTemplate1 = false;
    tester.get(Platform.class).executeStartupTasks();
    dbSession.clearCache();
    assertThat(db.ruleDao().getByKey(dbSession, RuleTesting.XOO_X1).getStatus())
        .isEqualTo(RuleStatus.REMOVED);
    assertThat(db.ruleDao().getByKey(dbSession, RuleTesting.XOO_X2).getStatus())
        .isEqualTo(RuleStatus.REMOVED);
    assertThat(db.activeRuleDao().findByProfileKey(dbSession, QProfileTesting.XOO_P1_KEY))
        .hasSize(1);
  }
  @Test
  public void delete_descendants() {
    initRules();

    // create parent and child profiles
    db.qualityProfileDao()
        .insert(
            dbSession,
            QProfileTesting.newXooP1(),
            QProfileTesting.newXooP2(),
            QProfileTesting.newXooP3());
    tester.get(RuleActivator.class).setParent(dbSession, XOO_P2_KEY, XOO_P1_KEY);
    tester.get(RuleActivator.class).setParent(dbSession, XOO_P3_KEY, XOO_P1_KEY);
    tester
        .get(RuleActivator.class)
        .activate(dbSession, new RuleActivation(RuleTesting.XOO_X1), XOO_P1_KEY);
    dbSession.commit();
    dbSession.clearCache();
    assertThat(db.qualityProfileDao().selectAll(dbSession)).hasSize(3);
    assertThat(db.activeRuleDao().selectAll(dbSession)).hasSize(3);

    factory.delete(XOO_P1_KEY);

    dbSession.clearCache();
    assertThat(db.qualityProfileDao().selectAll(dbSession)).isEmpty();
    assertThat(db.activeRuleDao().selectAll(dbSession)).isEmpty();
    assertThat(db.activeRuleDao().selectAllParams(dbSession)).isEmpty();
    assertThat(index.get(ActiveRuleIndex.class).findByProfile(XOO_P1_KEY)).isEmpty();
    assertThat(index.get(ActiveRuleIndex.class).findByProfile(XOO_P2_KEY)).isEmpty();
    assertThat(index.get(ActiveRuleIndex.class).findByProfile(XOO_P3_KEY)).isEmpty();
  }
  @Test
  public void get_search_health() {
    DbSession dbSession = tester.get(DbClient.class).openSession(false);
    tester
        .get(RuleDao.class)
        .insert(dbSession, RuleTesting.newDto(RuleKey.of("javascript", "S001")));
    dbSession.commit();

    SearchHealth health = tester.get(SearchHealth.class);
    Date now = new Date();

    ClusterHealth clusterHealth = health.getClusterHealth();
    assertThat(clusterHealth.isClusterAvailable()).isTrue();
    assertThat(clusterHealth.getNumberOfNodes()).isEqualTo(1);

    NodeHealth nodeHealth = health.getNodesHealth().values().iterator().next();
    assertThat(nodeHealth.isMaster()).isTrue();
    System.out.println(nodeHealth.getAddress());
    assertThat(nodeHealth.getAddress()).contains(":");
    assertThat(nodeHealth.getJvmHeapUsedPercent()).contains("%");
    assertThat(nodeHealth.getFsUsedPercent()).contains("%");
    assertThat(nodeHealth.getJvmThreads()).isGreaterThanOrEqualTo(0L);
    assertThat(nodeHealth.getProcessCpuPercent()).contains("%");
    assertThat(nodeHealth.getOpenFiles()).isGreaterThanOrEqualTo(0L);
    assertThat(nodeHealth.getJvmUpSince().before(now)).isTrue();

    Map<String, IndexHealth> indexHealth = health.getIndexHealth();
    assertThat(indexHealth).isNotEmpty();
    for (IndexHealth index : indexHealth.values()) {
      assertThat(index.getDocumentCount()).isGreaterThanOrEqualTo(0L);
      assertThat(index.getLastSynchronization().before(now)).isTrue();
      assertThat(index.isOptimized()).isIn(true, false);
    }
  }
  @Test
  public void reactivate_disabled_custom_rules() {
    Rule templateRule = index.getByKey(RuleKey.of("xoo", "template1"));

    // Create custom rule
    RuleKey customRuleKey =
        tester
            .get(RuleCreator.class)
            .create(
                NewRule.createForCustomRule("CUSTOM_RULE", templateRule.key())
                    .setName("My custom")
                    .setHtmlDescription("Some description")
                    .setSeverity(Severity.MAJOR)
                    .setStatus(RuleStatus.READY));
    dbSession.commit();
    dbSession.clearCache();
    assertThat(index.getByKey(customRuleKey).status()).isEqualTo(RuleStatus.READY);

    // Restart without template rule
    rulesDefinition.includeTemplate1 = false;
    tester.get(Platform.class).executeStartupTasks();
    dbSession.clearCache();

    // Verify custom rule is removed
    assertThat(index.getByKey(customRuleKey).status()).isEqualTo(RuleStatus.REMOVED);

    // Restart with template rule
    rulesDefinition.includeTemplate1 = true;
    tester.get(Platform.class).executeStartupTasks();
    dbSession.clearCache();

    // Verify custom rule is reactivate
    assertThat(index.getByKey(customRuleKey).status()).isEqualTo(RuleStatus.READY);
  }
 @Before
 public void setUp() {
   tester.clearDbAndIndexes();
   wsTester = tester.get(WsTester.class);
   ruleService = tester.get(RuleService.class);
   ruleDao = tester.get(RuleDao.class);
   session = tester.get(DbClient.class).openSession(false);
 }
 @Before
 public void before() {
   tester.clearDbAndIndexes();
   db = tester.get(DbClient.class);
   dbSession = db.openSession(false);
   index = tester.get(IndexClient.class);
   factory = tester.get(QProfileFactory.class);
 }
  @Before
  public void before() {
    tester.clearDbAndIndexes();
    rulesDefinition.includeX1 = true;
    rulesDefinition.includeX1bis = false;
    rulesDefinition.includeX2 = true;
    rulesDefinition.includeTemplate1 = true;
    rulesDefinition.includeRuleLinkedToRootCharacteristic = false;
    tester.get(Platform.class).executeStartupTasks();
    db = tester.get(DbClient.class);
    dbSession = tester.get(DbClient.class).openSession(false);
    dbSession.clearCache();

    index = tester.get(RuleIndex.class);
  }
  @Test
  public void bulk_activate_rule_by_query_with_severity() throws Exception {
    QualityProfileDto profile = createProfile("java");
    RuleDto rule0 = createRule(profile.getLanguage(), "toto");
    RuleDto rule1 = createRule(profile.getLanguage(), "tata");
    session.commit();
    ruIndexer.index();

    // 0. Assert No Active Rule for profile
    assertThat(db.activeRuleDao().selectByProfileKey(session, profile.getKey())).isEmpty();

    // 2. Assert ActiveRule with BLOCKER severity
    assertThat(
            tester
                .get(RuleIndex.class)
                .search(
                    new RuleQuery().setSeverities(ImmutableSet.of("BLOCKER")), new SearchOptions())
                .getIds())
        .hasSize(2);

    // 1. Activate Rule with query returning 2 hits
    WsTester.TestRequest request =
        wsTester.newPostRequest(
            QProfilesWs.API_ENDPOINT, BulkRuleActivationActions.BULK_ACTIVATE_ACTION);
    request.setParam(BulkRuleActivationActions.PROFILE_KEY, profile.getKey());
    request.setParam(BulkRuleActivationActions.SEVERITY, "MINOR");
    request.execute();
    session.commit();

    // 2. Assert ActiveRule with MINOR severity
    assertThat(
            tester
                .get(ActiveRuleDao.class)
                .selectByRuleId(session, rule0.getId())
                .get(0)
                .getSeverityString())
        .isEqualTo("MINOR");
    assertThat(
            tester
                .get(RuleIndex.class)
                .searchAll(
                    new RuleQuery()
                        .setQProfileKey(profile.getKey())
                        .setKey(rule0.getKey().toString())
                        .setActiveSeverities(Collections.singleton("MINOR"))
                        .setActivation(true)))
        .hasSize(1);
  }
  @Test
  public void remove_debt_rule() throws Exception {
    verifyRulesInDb();

    // Set some default debt on x2 rule, which has no debt provided by th plugin
    RuleDto ruleDto = db.ruleDao().getByKey(dbSession, RuleTesting.XOO_X2);
    db.ruleDao()
        .update(
            dbSession,
            ruleDto
                .setDefaultSubCharacteristicId(
                    db.debtCharacteristicDao()
                        .selectByKey(
                            RulesDefinition.SubCharacteristics.INTEGRATION_TESTABILITY, dbSession)
                        .getId())
                .setDefaultRemediationFunction("LINEAR_OFFSET")
                .setDefaultRemediationCoefficient("2h")
                .setDefaultRemediationOffset("35min"));
    dbSession.commit();
    dbSession.clearCache();

    // Re-execute startup tasks
    tester.get(Platform.class).executeStartupTasks();

    // Verify default debt has been removed
    Rule ruleReloaded = index.getByKey(RuleTesting.XOO_X2);
    assertThat(ruleReloaded.debtSubCharacteristicKey()).isNull();
    assertThat(ruleReloaded.debtRemediationFunction()).isNull();
  }
  @Test
  public void update_debt_rule() throws Exception {
    verifyRulesInDb();

    // Update x1 rule
    RuleDto ruleDto = db.ruleDao().getByKey(dbSession, RuleTesting.XOO_X1);
    db.ruleDao()
        .update(
            dbSession,
            ruleDto
                .setDefaultSubCharacteristicId(123456)
                .setDefaultRemediationFunction("LINEAR_OFFSET")
                .setDefaultRemediationCoefficient("2h")
                .setDefaultRemediationOffset("35min"));
    dbSession.commit();
    dbSession.clearCache();

    // Re-execute startup tasks
    tester.get(Platform.class).executeStartupTasks();

    // Verify default debt has been reset to plugin definition
    Rule ruleReloaded = index.getByKey(RuleTesting.XOO_X1);
    assertThat(ruleReloaded.debtSubCharacteristicKey())
        .isEqualTo(RulesDefinition.SubCharacteristics.INTEGRATION_TESTABILITY);
    assertThat(ruleReloaded.debtRemediationFunction().type())
        .isEqualTo(DebtRemediationFunction.Type.LINEAR_OFFSET);
    assertThat(ruleReloaded.debtRemediationFunction().coefficient()).isEqualTo("1h");
    assertThat(ruleReloaded.debtRemediationFunction().offset()).isEqualTo("30min");
  }
  @Test
  public void update_rule() {
    verifyRulesInDb();

    // The plugin X1 will be updated
    rulesDefinition.includeX1 = false;
    rulesDefinition.includeX1bis = true;
    tester.get(Platform.class).executeStartupTasks();

    Rule rule = index.getByKey(RuleTesting.XOO_X1);
    assertThat(rule.severity()).isEqualTo(Severity.INFO);
    assertThat(rule.name()).isEqualTo("x1 name updated");
    assertThat(rule.htmlDescription()).isEqualTo("x1 desc updated");
    assertThat(rule.systemTags()).contains("tag1", "tag2");

    assertThat(rule.params()).hasSize(2);

    assertThat(rule.param("acceptWhitespace").type()).isEqualTo(RuleParamType.BOOLEAN);
    assertThat(rule.param("acceptWhitespace").defaultValue()).isEqualTo("true");
    assertThat(rule.param("acceptWhitespace").description())
        .isEqualTo("Accept whitespaces on the line updated");

    // New parameter
    assertThat(rule.param("format").type()).isEqualTo(RuleParamType.TEXT);
    assertThat(rule.param("format").defaultValue()).isEqualTo("txt");
    assertThat(rule.param("format").description()).isEqualTo("Format");

    assertThat(rule.debtSubCharacteristicKey())
        .isEqualTo(RulesDefinition.SubCharacteristics.INSTRUCTION_RELIABILITY);
    assertThat(rule.debtRemediationFunction().type())
        .isEqualTo(DebtRemediationFunction.Type.LINEAR);
    assertThat(rule.debtRemediationFunction().coefficient()).isEqualTo("2h");
    assertThat(rule.debtRemediationFunction().offset()).isNull();
    assertThat(rule.effortToFixDescription()).isEqualTo("x1 effort to fix updated");
  }
  @Test
  public void search() throws Exception {
    Activity activity1 = new Activity();
    activity1.setType(Activity.Type.ANALYSIS_REPORT);
    activity1.setAction("LOG_ANALYSIS_REPORT");
    activity1.setData("projectKey", "P1");
    activity1.setData("projectName", "POne");
    activity1.setData("projectUuid", "U1");
    activity1.setData("status", AnalysisReportDto.Status.SUCCESS);
    activity1.setData("submittedAt", new Date());
    activityService.save(activity1);

    Activity activity2 = new Activity();
    activity2.setType(Activity.Type.ANALYSIS_REPORT);
    activity2.setAction("LOG_ANALYSIS_REPORT");
    activity2.setData("projectKey", "P2");
    activity2.setData("projectName", "PTwo");
    activity2.setData("projectUuid", "U2");
    activity2.setData("status", AnalysisReportDto.Status.FAILED);
    activity2.setData("submittedAt", new Date());
    activityService.save(activity2);

    userSessionRule.setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);

    WsTester.TestRequest request = tester.wsTester().newGetRequest("api/computation", "history");
    request.execute().assertJson(getClass(), "list_history_reports.json");
  }
  @Test
  public void change_project_association_with_key_and_uuid() throws Exception {
    ComponentDto project = ComponentTesting.newProjectDto("ABCD").setId(1L);
    db.componentDao().insert(session, project);
    QualityProfileDto profile1 = QProfileTesting.newXooP1();
    QualityProfileDto profile2 = QProfileTesting.newXooP2();
    db.qualityProfileDao().insert(session, profile1, profile2);
    db.qualityProfileDao()
        .insertProjectProfileAssociation(project.uuid(), profile1.getKey(), session);

    session.commit();

    wsTester
        .newPostRequest(QProfilesWs.API_ENDPOINT, "add_project")
        .setParam("profileKey", profile2.getKee())
        .setParam("projectUuid", project.uuid())
        .execute()
        .assertNoContent();
    assertThat(
            tester
                .get(QProfileFactory.class)
                .getByProjectAndLanguage(session, project.getKey(), "xoo")
                .getKee())
        .isEqualTo(profile2.getKee());
  }
  @Test
  public void get_profile_by_project_and_language() {
    ComponentDto project =
        new ComponentDto()
            .setId(1L)
            .setUuid("ABCD")
            .setKey("org.codehaus.sonar:sonar")
            .setName("SonarQube")
            .setLongName("SonarQube")
            .setQualifier("TRK")
            .setScope("TRK")
            .setEnabled(true);
    db.componentDao().insert(dbSession, project);

    QualityProfileDto profileDto = QProfileTesting.newXooP1();
    db.qualityProfileDao().insert(dbSession, profileDto);
    dbSession.commit();
    dbSession.clearCache();
    assertThat(factory.getByProjectAndLanguage("org.codehaus.sonar:sonar", "xoo")).isNull();

    tester
        .get(QProfileProjectOperations.class)
        .addProject(
            profileDto.getKey(),
            project.uuid(),
            new MockUserSession("me").setGlobalPermissions(GlobalPermissions.QUALITY_PROFILE_ADMIN),
            dbSession);
    dbSession.commit();
    dbSession.clearCache();
    assertThat(factory.getByProjectAndLanguage("org.codehaus.sonar:sonar", "xoo").getKey())
        .isEqualTo(XOO_P1_KEY);
  }
  @Test
  public void search_qprofile_activity_with_rule_not_found() throws InterruptedException {
    MockUserSession.set()
        .setGlobalPermissions(GlobalPermissions.QUALITY_PROFILE_ADMIN)
        .setLogin("me");

    RuleKey ruleKey = RuleKey.of("xoo", "deleted_rule");

    tester
        .get(ActivityService.class)
        .write(
            dbSession,
            Activity.Type.QPROFILE,
            ActiveRuleChange.createFor(
                    ActiveRuleChange.Type.ACTIVATED, ActiveRuleKey.of(XOO_P1_KEY, ruleKey))
                .setSeverity(Severity.MAJOR)
                .setParameter("max", "10"));
    dbSession.commit();

    Result<QProfileActivity> activities =
        service.searchActivities(new QProfileActivityQuery(), new QueryContext());
    assertThat(activities.getHits()).hasSize(1);

    QProfileActivity activity = activities.getHits().get(0);
    assertThat(activity.ruleKey()).isEqualTo(ruleKey);
    assertThat(activity.ruleName()).isNull();
  }
  @Test
  public void search_qprofile_activity_with_user_not_found() throws InterruptedException {
    MockUserSession.set()
        .setGlobalPermissions(GlobalPermissions.QUALITY_PROFILE_ADMIN)
        .setLogin("david");

    // We need an actual rule in DB to test RuleName in Activity
    db.ruleDao().getByKey(dbSession, RuleTesting.XOO_X1);

    tester
        .get(ActivityService.class)
        .write(
            dbSession,
            Activity.Type.QPROFILE,
            ActiveRuleChange.createFor(
                    ActiveRuleChange.Type.ACTIVATED,
                    ActiveRuleKey.of(XOO_P1_KEY, RuleTesting.XOO_X1))
                .setSeverity(Severity.MAJOR)
                .setParameter("max", "10"));
    dbSession.commit();

    Result<QProfileActivity> activities =
        service.searchActivities(new QProfileActivityQuery(), new QueryContext());
    assertThat(activities.getHits()).hasSize(1);

    QProfileActivity activity = activities.getHits().get(0);
    assertThat(activity.login()).isEqualTo("david");
    assertThat(activity.authorName()).isNull();
  }
  @Test
  public void reactivate_disabled_rules() {
    verifyRulesInDb();

    // Disable plugin X1
    rulesDefinition.includeX1 = false;
    tester.get(Platform.class).executeStartupTasks();

    RuleDto rule = db.ruleDao().getByKey(dbSession, RuleTesting.XOO_X1);
    assertThat(rule.getStatus()).isEqualTo(RuleStatus.REMOVED);
    dbSession.clearCache();

    // Reactivate plugin X1
    rulesDefinition.includeX1 = true;
    tester.get(Platform.class).executeStartupTasks();

    RuleDto ruleReloaded = db.ruleDao().getByKey(dbSession, RuleTesting.XOO_X1);
    assertThat(ruleReloaded.getStatus()).isEqualTo(RuleStatus.READY);
  }
  @Before
  public void before() {
    tester.clearDbAndIndexes();
    db = tester.get(DbClient.class);
    dbSession = db.openSession(false);
    service = tester.get(QProfileService.class);
    loader = tester.get(QProfileLoader.class);
    activator = tester.get(RuleActivator.class);

    // create pre-defined rules
    RuleDto xooRule1 = RuleTesting.newXooX1().setSeverity("MINOR");
    db.ruleDao().insert(dbSession, xooRule1);

    // create pre-defined profiles P1 and P2
    db.qualityProfileDao()
        .insert(dbSession, QProfileTesting.newXooP1(), QProfileTesting.newXooP2());
    dbSession.commit();
    dbSession.clearCache();
  }
  @Test
  public void search_activity_by_qprofile_having_dashes_in_keys() throws InterruptedException {
    tester
        .get(ActivityService.class)
        .write(
            dbSession,
            Activity.Type.QPROFILE,
            ActiveRuleChange.createFor(
                ActiveRuleChange.Type.ACTIVATED,
                ActiveRuleKey.of("java-default", RuleTesting.XOO_X1)));
    tester
        .get(ActivityService.class)
        .write(
            dbSession,
            Activity.Type.QPROFILE,
            ActiveRuleChange.createFor(
                ActiveRuleChange.Type.ACTIVATED,
                ActiveRuleKey.of("java-toto", RuleTesting.XOO_X1)));
    dbSession.commit();

    // 0. Base case verify 2 activities in index
    assertThat(service.searchActivities(new QProfileActivityQuery(), new QueryContext()).getHits())
        .hasSize(2);

    // 1. filter by QProfile
    List<QProfileActivity> result =
        service
            .searchActivities(
                new QProfileActivityQuery().setQprofileKeys(ImmutableSet.of("java-default")),
                new QueryContext())
            .getHits();
    assertThat(result).hasSize(1);

    // 1. filter by QProfiles
    assertThat(
            service
                .searchActivities(
                    new QProfileActivityQuery()
                        .setQprofileKeys(ImmutableSet.of("java-default", "java-toto")),
                    new QueryContext())
                .getHits())
        .hasSize(2);
  }
  @Test
  public void update_custom_rule_from_template() throws Exception {
    Rule templateRule = index.getByKey(RuleKey.of("xoo", "template1"));

    // Create custom rule
    RuleKey customRuleKey =
        tester
            .get(RuleCreator.class)
            .create(
                NewRule.createForCustomRule("CUSTOM_RULE", templateRule.key())
                    .setName("My custom")
                    .setHtmlDescription("Some description")
                    .setSeverity(Severity.MAJOR)
                    .setStatus(RuleStatus.READY)
                    .setParameters(ImmutableMap.of("format", "txt")));

    // Update custom rule
    RuleDto customRuleDto = db.ruleDao().getByKey(dbSession, customRuleKey);
    db.ruleDao()
        .update(
            dbSession,
            customRuleDto
                .setLanguage("other language")
                .setConfigKey("other config key")
                .setDefaultSubCharacteristicId(45)
                .setDefaultRemediationFunction("LINEAR_OFFSET")
                .setDefaultRemediationCoefficient("1h")
                .setDefaultRemediationOffset("5min")
                .setEffortToFixDescription("effort to fix desc"));
    dbSession.commit();
    dbSession.clearCache();

    // Re-execute startup tasks
    tester.get(Platform.class).executeStartupTasks();

    // Verify custom rule has been restore from the template
    Rule customRule = index.getByKey(customRuleKey);
    assertThat(customRule.language()).isEqualTo("xoo");
    assertThat(customRule.internalKey()).isNull();
    assertThat(customRule.debtSubCharacteristicKey()).isNull();
    assertThat(customRule.debtRemediationFunction()).isNull();
  }
  @Test
  public void mark_rule_as_removed() throws Exception {
    verifyRulesInDb();

    rulesDefinition.includeX2 = false;
    tester.get(Platform.class).executeStartupTasks();

    verifyRulesInDb();
    RuleDto rule = db.ruleDao().getByKey(dbSession, RuleKey.of("xoo", "x2"));
    assertThat(rule.getStatus()).isEqualTo(RuleStatus.REMOVED);
  }
  @Test
  public void not_disable_manual_rules() {
    // Create manual rule
    RuleKey manualRuleKey =
        tester
            .get(RuleCreator.class)
            .create(
                NewRule.createForManualRule("MANUAL_RULE")
                    .setName("My manual")
                    .setHtmlDescription("Some description"));
    dbSession.commit();
    dbSession.clearCache();
    assertThat(index.getByKey(manualRuleKey).status()).isEqualTo(RuleStatus.READY);

    // Restart
    tester.get(Platform.class).executeStartupTasks();

    // Verify manual rule is still ready
    assertThat(index.getByKey(manualRuleKey).status()).isEqualTo(RuleStatus.READY);
  }
  /**
   * support the use-case: 1. start server 2. stop server 3. drop elasticsearch index: rm -rf
   * data/es 4. start server -> db is up-to-date (no changes) but rules must be re-indexed
   */
  @Test
  public void index_even_if_no_changes() throws Exception {
    verifyRulesInDb();

    // clear ES but keep db
    tester.clearIndexes();
    verifyRulesInDb();
    Result<Rule> searchResult = index.search(new RuleQuery(), new QueryOptions());
    assertThat(searchResult.getTotal()).isEqualTo(0);
    assertThat(searchResult.getHits()).hasSize(0);

    // db is not updated (same rules) but es must be reindexed
    tester.get(Platform.class).executeStartupTasks();

    index = tester.get(RuleIndex.class);

    verifyRulesInDb();
    searchResult = index.search(new RuleQuery().setKey("xoo:x1"), new QueryOptions());
    assertThat(searchResult.getTotal()).isEqualTo(1);
    assertThat(searchResult.getHits()).hasSize(1);
    assertThat(searchResult.getHits().get(0).params()).hasSize(1);
  }
  @Test
  public void not_update_rule_if_no_change() throws Exception {
    // Store updated at date
    Date updatedAt = index.getByKey(RuleTesting.XOO_X1).updatedAt();

    // Re-execute startup tasks
    tester.get(Platform.class).executeStartupTasks();
    dbSession.clearCache();

    // Verify rule has not been updated
    Rule customRuleReloaded = index.getByKey(RuleTesting.XOO_X1);
    assertThat(DateUtils.isSameInstant(customRuleReloaded.updatedAt(), updatedAt));
  }
  @Test
  public void not_update_custom_rule_params_from_template() throws Exception {
    Rule templateRule = index.getByKey(RuleKey.of("xoo", "template1"));

    // Create custom rule
    RuleKey customRuleKey =
        tester
            .get(RuleCreator.class)
            .create(
                NewRule.createForCustomRule("CUSTOM_RULE", templateRule.key())
                    .setName("My custom")
                    .setHtmlDescription("Some description")
                    .setSeverity(Severity.MAJOR)
                    .setStatus(RuleStatus.READY)
                    .setParameters(ImmutableMap.of("format", "txt")));
    dbSession.commit();
    dbSession.clearCache();

    // Update custom rule param name
    RuleDto customRuleDto = db.ruleDao().getByKey(dbSession, customRuleKey);
    RuleParamDto customRuleParamDto =
        db.ruleDao().findRuleParamsByRuleKey(dbSession, customRuleKey).get(0);
    db.ruleDao().removeRuleParam(dbSession, customRuleDto, customRuleParamDto);
    db.ruleDao().addRuleParam(dbSession, customRuleDto, customRuleParamDto.setName("format2"));
    dbSession.commit();
    dbSession.clearCache();

    // Verify param has been updated
    Rule customRule = index.getByKey(customRuleKey);
    assertThat(customRule.params()).hasSize(1);
    assertThat(customRule.params().get(0).key()).isEqualTo("format2");

    // Re-execute startup tasks
    tester.get(Platform.class).executeStartupTasks();

    // Verify custom rule param has not been changed!
    Rule customRuleReloaded = index.getByKey(customRuleKey);
    assertThat(customRuleReloaded.params().get(0).key()).isEqualTo("format2");
  }
  @Test
  public void remove_end_user_tags_that_are_declared_as_system() {
    verifyRulesInDb();

    Rule rule = index.getByKey(RuleTesting.XOO_X1);
    assertThat(rule.systemTags()).contains("tag1");
    assertThat(rule.tags()).isEmpty();

    // Add a user tag
    tester
        .get(RuleUpdater.class)
        .update(
            RuleUpdate.createForPluginRule(rule.key()).setTags(newHashSet("user-tag")),
            UserSession.get());
    dbSession.clearCache();

    // Verify tags
    Rule ruleUpdated = index.getByKey(RuleTesting.XOO_X1);
    assertThat(ruleUpdated.systemTags()).contains("tag1");
    assertThat(ruleUpdated.tags()).contains("user-tag");

    // The plugin X1 will be updated
    rulesDefinition.includeX1 = false;
    rulesDefinition.includeX1bis = true;
    tester.get(Platform.class).executeStartupTasks();
    dbSession.clearCache();

    // User tag should become a system tag
    RuleDto ruleDtoReloaded = db.ruleDao().getByKey(dbSession, RuleTesting.XOO_X1);
    assertThat(ruleDtoReloaded.getSystemTags()).contains("tag1", "tag2", "user-tag");
    assertThat(ruleDtoReloaded.getTags()).isEmpty();

    // User tag should become a system tag
    Rule ruleReloaded = index.getByKey(RuleTesting.XOO_X1);
    assertThat(ruleReloaded.systemTags()).contains("tag1", "tag2", "user-tag");
    assertThat(ruleReloaded.tags()).isEmpty();
  }
  @Test
  public void search() throws Exception {
    Activity activity = new Activity();
    activity.setType(Activity.Type.ANALYSIS_REPORT);
    activity.setAction("THE_ACTION");
    activity.setMessage("THE_MSG");
    activity.setData("foo", "bar");
    service.save(activity);

    WsTester.TestRequest request = tester.wsTester().newGetRequest("api/activities", "search");
    WsTester.Result result = request.execute();
    assertThat(result.outputAsString()).contains("\"total\":1");
    assertThat(result.outputAsString()).contains("\"type\":\"ANALYSIS_REPORT\"");
    assertThat(result.outputAsString()).contains("\"details\":{\"foo\":\"bar\"}");
  }