From 743c18768fcaf696b909c1ab3ebed2c3359d5ca9 Mon Sep 17 00:00:00 2001 From: "antoine.vinot" Date: Fri, 17 Nov 2023 17:03:52 +0100 Subject: [PATCH] SONAR-21043 - Remove Elasticsearch usage for missing rules count --- .../db/qualityprofile/ActiveRuleDaoIT.java | 38 +++++++- .../db/qualityprofile/ActiveRuleDao.java | 4 + .../db/qualityprofile/ActiveRuleMapper.java | 1 + .../db/qualityprofile/ActiveRuleMapper.xml | 24 ++++- .../qualityprofile/ws/ShowActionIT.java | 97 +++++++------------ .../server/qualityprofile/ws/ShowAction.java | 12 +-- 6 files changed, 99 insertions(+), 77 deletions(-) diff --git a/server/sonar-db-dao/src/it/java/org/sonar/db/qualityprofile/ActiveRuleDaoIT.java b/server/sonar-db-dao/src/it/java/org/sonar/db/qualityprofile/ActiveRuleDaoIT.java index 5af54de947d..9dfdd9f07d6 100644 --- a/server/sonar-db-dao/src/it/java/org/sonar/db/qualityprofile/ActiveRuleDaoIT.java +++ b/server/sonar-db-dao/src/it/java/org/sonar/db/qualityprofile/ActiveRuleDaoIT.java @@ -42,6 +42,7 @@ import static java.util.Arrays.asList; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatNoException; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.entry; import static org.assertj.core.api.Assertions.tuple; @@ -365,7 +366,7 @@ public class ActiveRuleDaoIT { @Test public void delete_does_not_fail_when_active_rule_does_not_exist() { - underTest.delete(dbSession, ActiveRuleKey.of(profile1, rule1.getKey())); + assertThatNoException().isThrownBy(() -> underTest.delete(dbSession, ActiveRuleKey.of(profile1, rule1.getKey()))); } @Test @@ -705,6 +706,41 @@ public class ActiveRuleDaoIT { tuple(ar3.getUuid(), ar3.getRuleKey().repository(), ar3.getRuleKey().rule(), profile2.getRulesProfileUuid(), ar3.getSeverity())); } + @Test + public void countMissingRules() { + db.qualityProfiles().activateRule(profile1, rule1); + db.qualityProfiles().activateRule(profile1, rule3); + db.qualityProfiles().activateRule(profile2, rule1); + db.qualityProfiles().activateRule(profile2, rule2); + + int result = underTest.countMissingRules(dbSession, profile1.getRulesProfileUuid(), profile2.getRulesProfileUuid()); + + assertThat(result).isOne(); + } + + @Test + public void countMissingRules_whenNoRulesInCommon_shouldReturnNumberOfRulesInComparedToProfile() { + db.qualityProfiles().activateRule(profile1, rule1); + db.qualityProfiles().activateRule(profile2, rule2); + db.qualityProfiles().activateRule(profile2, rule3); + + int result = underTest.countMissingRules(dbSession, profile1.getRulesProfileUuid(), profile2.getRulesProfileUuid()); + + assertThat(result).isEqualTo(2); + } + + @Test + public void countMissingRules_whenSomeRulesRemoved_shouldNotCountRemovedRules() { + db.qualityProfiles().activateRule(profile1, rule1); + db.qualityProfiles().activateRule(profile2, rule2); + db.qualityProfiles().activateRule(profile2, rule3); + db.qualityProfiles().activateRule(profile2, removedRule); + + int result = underTest.countMissingRules(dbSession, profile1.getRulesProfileUuid(), profile2.getRulesProfileUuid()); + + assertThat(result).isEqualTo(2); + } + private static class Accumulator implements Consumer { private final List list = new ArrayList<>(); diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/ActiveRuleDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/ActiveRuleDao.java index 9dcc54cdd79..2fb65852630 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/ActiveRuleDao.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/ActiveRuleDao.java @@ -220,6 +220,10 @@ public class ActiveRuleDao implements Dao { }); } + public int countMissingRules(DbSession dbSession, String rulesProfileUuid, String compareToRulesProfileUuid) { + return mapper(dbSession).countMissingRules(rulesProfileUuid, compareToRulesProfileUuid); + } + private static ActiveRuleMapper mapper(DbSession dbSession) { return dbSession.getMapper(ActiveRuleMapper.class); } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/ActiveRuleMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/ActiveRuleMapper.java index 75ffd6180a6..b95d10a2a9a 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/ActiveRuleMapper.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/ActiveRuleMapper.java @@ -84,4 +84,5 @@ public interface ActiveRuleMapper { void scrollByRuleProfileUuidForIndexing(@Param("ruleProfileUuid") String ruleProfileUuid, ResultHandler handler); + int countMissingRules(@Param("rulesProfileUuid") String rulesProfileUuid, @Param("compareToRulesProfileUuid") String compareToRulesProfileUuid); } diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/qualityprofile/ActiveRuleMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/qualityprofile/ActiveRuleMapper.xml index d450e04b1a0..96c6fd22f17 100644 --- a/server/sonar-db-dao/src/main/resources/org/sonar/db/qualityprofile/ActiveRuleMapper.xml +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/qualityprofile/ActiveRuleMapper.xml @@ -234,7 +234,8 @@ delete from active_rule_parameters where active_rule_uuid in - #{activeRuleUuid, jdbcType=VARCHAR} + #{activeRuleUuid, jdbcType=VARCHAR} - - where ar.uuid in #{uuid, jdbcType=VARCHAR} - where rp.uuid = #{ruleProfileUuid, jdbcType=VARCHAR} @@ -310,5 +314,17 @@ inner join rules_profiles rp on rp.uuid = ar.profile_uuid inner join rules r on r.uuid = ar.rule_uuid + + + diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/qualityprofile/ws/ShowActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/qualityprofile/ws/ShowActionIT.java index c7fc1eb58de..576a1abc9dc 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/qualityprofile/ws/ShowActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/qualityprofile/ws/ShowActionIT.java @@ -19,22 +19,23 @@ */ package org.sonar.server.qualityprofile.ws; +import com.tngtech.java.junit.dataprovider.DataProvider; +import com.tngtech.java.junit.dataprovider.DataProviderRunner; +import com.tngtech.java.junit.dataprovider.UseDataProvider; +import java.util.function.Consumer; import org.junit.Rule; import org.junit.Test; +import org.junit.runner.RunWith; import org.sonar.api.resources.Language; import org.sonar.api.resources.Languages; import org.sonar.api.server.ws.WebService; import org.sonar.api.utils.DateUtils; -import org.sonar.api.utils.System2; import org.sonar.db.DbTester; import org.sonar.db.qualityprofile.QProfileDto; import org.sonar.db.rule.RuleDto; import org.sonar.db.user.UserDto; import org.sonar.server.es.EsTester; import org.sonar.server.exceptions.NotFoundException; -import org.sonar.server.qualityprofile.index.ActiveRuleIndexer; -import org.sonar.server.rule.index.RuleIndex; -import org.sonar.server.rule.index.RuleIndexer; import org.sonar.server.tester.UserSessionRule; import org.sonar.server.ws.TestRequest; import org.sonar.server.ws.WsActionTester; @@ -53,11 +54,12 @@ import static org.sonar.test.JsonAssert.assertJson; import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_COMPARE_TO_SONAR_WAY; import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_KEY; +@RunWith(DataProviderRunner.class) public class ShowActionIT { - private static Language XOO1 = newLanguage("xoo1"); - private static Language XOO2 = newLanguage("xoo2"); - private static Languages LANGUAGES = new Languages(XOO1, XOO2); + private final static Language XOO1 = newLanguage("xoo1"); + private final static Language XOO2 = newLanguage("xoo2"); + private final static Languages LANGUAGES = new Languages(XOO1, XOO2); @Rule public EsTester es = EsTester.create(); @@ -66,12 +68,8 @@ public class ShowActionIT { @Rule public UserSessionRule userSession = UserSessionRule.standalone(); - private RuleIndexer ruleIndexer = new RuleIndexer(es.client(), db.getDbClient()); - private ActiveRuleIndexer activeRuleIndexer = new ActiveRuleIndexer(db.getDbClient(), es.client()); - private RuleIndex ruleIndex = new RuleIndex(es.client(), System2.INSTANCE); - private WsActionTester ws = new WsActionTester( - new ShowAction(db.getDbClient(), new QProfileWsSupport(db.getDbClient(), userSession), LANGUAGES, ruleIndex)); + new ShowAction(db.getDbClient(), new QProfileWsSupport(db.getDbClient(), userSession), LANGUAGES)); @Test public void profile_info() { @@ -162,8 +160,6 @@ public class ShowActionIT { db.qualityProfiles().activateRule(sonarWayProfile, commonRule); db.qualityProfiles().activateRule(sonarWayProfile, sonarWayRule1); db.qualityProfiles().activateRule(sonarWayProfile, sonarWayRule2); - ruleIndexer.indexAll(); - activeRuleIndexer.indexAll(); CompareToSonarWay result = call(ws.newRequest() .setParam(PARAM_KEY, profile.getKee()) @@ -182,8 +178,6 @@ public class ShowActionIT { RuleDto commonRule = db.rules().insertRule(r -> r.setLanguage(XOO1.getKey())); db.qualityProfiles().activateRule(profile, commonRule); db.qualityProfiles().activateRule(sonarWayProfile, commonRule); - ruleIndexer.indexAll(); - activeRuleIndexer.indexAll(); CompareToSonarWay result = call(ws.newRequest() .setParam(PARAM_KEY, profile.getKee()) @@ -195,50 +189,29 @@ public class ShowActionIT { .containsExactly(sonarWayProfile.getKee(), sonarWayProfile.getName(), 0L); } - @Test - public void no_comparison_when_sonar_way_does_not_exist() { - QProfileDto anotherSonarWayProfile = db.qualityProfiles().insert(p -> p.setIsBuiltIn(true).setName("Another Sonar way").setLanguage(XOO1.getKey())); - QProfileDto profile = db.qualityProfiles().insert(p -> p.setLanguage(XOO1.getKey())); - - ShowResponse result = call(ws.newRequest() - .setParam(PARAM_KEY, profile.getKee()) - .setParam(PARAM_COMPARE_TO_SONAR_WAY, "true")); - - assertThat(result.hasCompareToSonarWay()).isFalse(); + @DataProvider + public static Object[][] dataForComparison() { + Consumer sonarWay = p -> p.setIsBuiltIn(true).setName("Sonar way").setLanguage(XOO1.getKey()); + Consumer notBuiltInSonarWay = p -> p.setIsBuiltIn(false).setName("Sonar way").setLanguage(XOO1.getKey()); + Consumer anotherSonarWay = p -> p.setIsBuiltIn(true).setName("Another Sonar way").setLanguage(XOO1.getKey()); + Consumer anotherBuiltIn = p -> p.setIsBuiltIn(true).setLanguage(XOO1.getKey()); + Consumer profile = p -> p.setLanguage(XOO1.getKey()); + return new Object[][] { + {profile, anotherSonarWay, "true"}, + {anotherBuiltIn, sonarWay, "true"}, + {profile, notBuiltInSonarWay, "true"}, + {profile, sonarWay, "false"}}; } @Test - public void no_comparison_when_profile_is_built_in() { - QProfileDto sonarWayProfile = db.qualityProfiles().insert(p -> p.setIsBuiltIn(true).setName("Sonar way").setLanguage(XOO1.getKey())); - QProfileDto anotherBuiltInProfile = db.qualityProfiles().insert(p -> p.setIsBuiltIn(true).setLanguage(XOO1.getKey())); - - ShowResponse result = call(ws.newRequest() - .setParam(PARAM_KEY, anotherBuiltInProfile.getKee()) - .setParam(PARAM_COMPARE_TO_SONAR_WAY, "true")); - - assertThat(result.hasCompareToSonarWay()).isFalse(); - } - - @Test - public void no_comparison_if_sonar_way_is_not_built_in() { - QProfileDto sonarWayProfile = db.qualityProfiles().insert(p -> p.setIsBuiltIn(false).setName("Sonar way").setLanguage(XOO1.getKey())); - QProfileDto profile = db.qualityProfiles().insert(p -> p.setLanguage(XOO1.getKey())); - - ShowResponse result = call(ws.newRequest() - .setParam(PARAM_KEY, profile.getKee()) - .setParam(PARAM_COMPARE_TO_SONAR_WAY, "true")); - - assertThat(result.hasCompareToSonarWay()).isFalse(); - } - - @Test - public void no_comparison_when_param_is_false() { - QProfileDto sonarWayProfile = db.qualityProfiles().insert(p -> p.setIsBuiltIn(true).setName("Sonar way").setLanguage(XOO1.getKey())); - QProfileDto profile = db.qualityProfiles().insert(p -> p.setLanguage(XOO1.getKey())); + @UseDataProvider("dataForComparison") + public void response_shouldNotHaveCompareToSonarWay(Consumer profileData, Consumer profileToCompareData, String paramCompareToSonarWay) { + db.qualityProfiles().insert(profileToCompareData); + QProfileDto profile = db.qualityProfiles().insert(profileData); ShowResponse result = call(ws.newRequest() .setParam(PARAM_KEY, profile.getKee()) - .setParam(PARAM_COMPARE_TO_SONAR_WAY, "false")); + .setParam(PARAM_COMPARE_TO_SONAR_WAY, paramCompareToSonarWay)); assertThat(result.hasCompareToSonarWay()).isFalse(); } @@ -261,7 +234,7 @@ public class ShowActionIT { @Test public void compare_to_sonar_way_over_sonarqube_way() { QProfileDto sonarWayProfile = db.qualityProfiles().insert(p -> p.setIsBuiltIn(true).setName("Sonar way").setLanguage(XOO1.getKey())); - QProfileDto sonarQubeWayProfile = db.qualityProfiles().insert(p -> p.setIsBuiltIn(true).setName("SonarQube way").setLanguage(XOO1.getKey())); + db.qualityProfiles().insert(p -> p.setIsBuiltIn(true).setName("SonarQube way").setLanguage(XOO1.getKey())); QProfileDto profile = db.qualityProfiles().insert(p -> p.setLanguage(XOO1.getKey())); CompareToSonarWay result = call(ws.newRequest() @@ -291,18 +264,16 @@ public class ShowActionIT { public void fail_if_profile_language_is_not_supported() { QProfileDto profile = db.qualityProfiles().insert(p -> p.setKee("unknown-profile").setLanguage("kotlin")); - assertThatThrownBy(() -> { - call(ws.newRequest().setParam(PARAM_KEY, profile.getKee())); - }) + TestRequest testRequest = ws.newRequest().setParam(PARAM_KEY, profile.getKee()); + assertThatThrownBy(() -> call(testRequest)) .isInstanceOf(NotFoundException.class) .hasMessage("Quality Profile with key 'unknown-profile' does not exist"); } @Test public void fail_if_profile_does_not_exist() { - assertThatThrownBy(() -> { - call(ws.newRequest().setParam(PARAM_KEY, "unknown-profile")); - }) + TestRequest testRequest = ws.newRequest().setParam(PARAM_KEY, "unknown-profile"); + assertThatThrownBy(() -> call(testRequest)) .isInstanceOf(NotFoundException.class) .hasMessage("Quality Profile with key 'unknown-profile' does not exist"); } @@ -331,7 +302,7 @@ public class ShowActionIT { .forEach(project -> db.qualityProfiles().associateWithProject(project, profile)); ws = new WsActionTester( - new ShowAction(db.getDbClient(), new QProfileWsSupport(db.getDbClient(), userSession), new Languages(cs), ruleIndex)); + new ShowAction(db.getDbClient(), new QProfileWsSupport(db.getDbClient(), userSession), new Languages(cs))); String result = ws.newRequest().setParam(PARAM_KEY, profile.getKee()).execute().getInput(); assertJson(result).ignoreFields("rulesUpdatedAt", "lastUsed", "userUpdatedAt").isSimilarTo(ws.getDef().responseExampleAsString()); @@ -346,11 +317,13 @@ public class ShowActionIT { assertThat(action.since()).isEqualTo("6.5"); WebService.Param profile = action.param("key"); + assertThat(profile).isNotNull(); assertThat(profile.isRequired()).isTrue(); assertThat(profile.isInternal()).isFalse(); assertThat(profile.description()).isNotEmpty(); WebService.Param compareToSonarWay = action.param("compareToSonarWay"); + assertThat(compareToSonarWay).isNotNull(); assertThat(compareToSonarWay.isRequired()).isFalse(); assertThat(compareToSonarWay.isInternal()).isTrue(); assertThat(compareToSonarWay.description()).isNotEmpty(); diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/ws/ShowAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/ws/ShowAction.java index 4bcad7c17a2..d2bf31ce028 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/ws/ShowAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/ws/ShowAction.java @@ -34,9 +34,6 @@ import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.qualityprofile.ActiveRuleCountQuery; import org.sonar.db.qualityprofile.QProfileDto; -import org.sonar.server.es.SearchOptions; -import org.sonar.server.rule.index.RuleIndex; -import org.sonar.server.rule.index.RuleQuery; import org.sonarqube.ws.Qualityprofiles; import org.sonarqube.ws.Qualityprofiles.ShowResponse; import org.sonarqube.ws.Qualityprofiles.ShowResponse.CompareToSonarWay; @@ -61,13 +58,11 @@ public class ShowAction implements QProfileWsAction { private final DbClient dbClient; private final QProfileWsSupport qProfileWsSupport; private final Languages languages; - private final RuleIndex ruleIndex; - public ShowAction(DbClient dbClient, QProfileWsSupport qProfileWsSupport, Languages languages, RuleIndex ruleIndex) { + public ShowAction(DbClient dbClient, QProfileWsSupport qProfileWsSupport, Languages languages) { this.dbClient = dbClient; this.qProfileWsSupport = qProfileWsSupport; this.languages = languages; - this.ruleIndex = ruleIndex; } @Override @@ -137,10 +132,7 @@ public class ShowAction implements QProfileWsAction { return null; } - long missingRuleCount = ruleIndex.search( - new RuleQuery().setQProfile(profile).setActivation(false).setCompareToQProfile(sonarWay), - new SearchOptions().setLimit(1)) - .getTotal(); + long missingRuleCount = dbClient.activeRuleDao().countMissingRules(dbSession, profile.getRulesProfileUuid(), sonarWay.getRulesProfileUuid()); return CompareToSonarWay.newBuilder() .setProfile(sonarWay.getKee()) -- 2.39.5