aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorTeryk Bellahsene <teryk.bellahsene@sonarsource.com>2017-06-29 15:01:11 +0200
committerJulien Lancelot <julien.lancelot@sonarsource.com>2017-07-04 16:29:36 +0200
commita756c3bc2cd74b77ec0ae9c7e0401932c408c7bb (patch)
treeac6e241caf308107387a7684fdfd3acb96bac03e /server
parente817dc3291ad2197f5bb0622385cdfacafeb04db (diff)
downloadsonarqube-a756c3bc2cd74b77ec0ae9c7e0401932c408c7bb.tar.gz
sonarqube-a756c3bc2cd74b77ec0ae9c7e0401932c408c7bb.zip
SONAR-9482 Show ws counts missing rules compared to Sonar way
Diffstat (limited to 'server')
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ShowAction.java13
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleIndex.java36
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleQuery.java11
-rw-r--r--server/sonar-server/src/main/resources/org/sonar/server/qualityprofile/ws/show-example.json5
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ShowActionTest.java67
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/rule/index/RuleIndexTest.java26
6 files changed, 130 insertions, 28 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ShowAction.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ShowAction.java
index 629cc55025a..cff1902a7b4 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ShowAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ShowAction.java
@@ -35,6 +35,9 @@ import org.sonar.db.DbSession;
import org.sonar.db.organization.OrganizationDto;
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.ShowWsResponse;
import org.sonarqube.ws.QualityProfiles.ShowWsResponse.CompareToSonarWay;
import org.sonarqube.ws.QualityProfiles.ShowWsResponse.QualityProfile;
@@ -57,11 +60,13 @@ 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) {
+ public ShowAction(DbClient dbClient, QProfileWsSupport qProfileWsSupport, Languages languages, RuleIndex ruleIndex) {
this.dbClient = dbClient;
this.qProfileWsSupport = qProfileWsSupport;
this.languages = languages;
+ this.ruleIndex = ruleIndex;
}
@Override
@@ -132,9 +137,15 @@ public class ShowAction implements QProfileWsAction {
return null;
}
+ long missingRuleCount = ruleIndex.search(
+ new RuleQuery().setQProfile(profile).setActivation(false).setCompareToQProfile(sonarWay),
+ new SearchOptions().setLimit(1))
+ .getTotal();
+
return CompareToSonarWay.newBuilder()
.setProfile(sonarWay.getKee())
.setProfileName(sonarWay.getName())
+ .setMissingRuleCount(missingRuleCount)
.build();
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleIndex.java b/server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleIndex.java
index 7a623e10dd8..240145724e6 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleIndex.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleIndex.java
@@ -20,8 +20,6 @@
package org.sonar.server.rule.index;
import com.google.common.base.Joiner;
-import com.google.common.collect.Collections2;
-import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -56,6 +54,7 @@ import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.rule.Severity;
import org.sonar.api.rules.RuleType;
+import org.sonar.core.util.stream.MoreCollectors;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.qualityprofile.QProfileDto;
import org.sonar.server.es.EsClient;
@@ -65,6 +64,8 @@ import org.sonar.server.es.SearchOptions;
import org.sonar.server.es.StickyFacetBuilder;
import static com.google.common.base.Preconditions.checkArgument;
+import static java.lang.Boolean.FALSE;
+import static java.lang.Boolean.TRUE;
import static java.util.Optional.ofNullable;
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
@@ -114,10 +115,11 @@ public class RuleIndex {
public static final String FACET_TYPES = "types";
public static final String FACET_OLD_DEFAULT = "true";
- public static final List<String> ALL_STATUSES_EXCEPT_REMOVED = ImmutableList.copyOf(
- Collections2.filter(
- Collections2.transform(Arrays.asList(RuleStatus.values()), RuleStatus::toString),
- input -> !RuleStatus.REMOVED.toString().equals(input)));
+ public static final List<String> ALL_STATUSES_EXCEPT_REMOVED = Arrays.stream(RuleStatus.values())
+ .filter(status -> !RuleStatus.REMOVED.equals(status))
+ .map(RuleStatus::toString)
+ .collect(MoreCollectors.toList());
+
private static final String AGGREGATION_NAME = "_ref";
private static final String AGGREGATION_NAME_FOR_TAGS = "tagsAggregation";
private final EsClient client;
@@ -296,29 +298,35 @@ public class RuleIndex {
if (query.getActivation() != null && profile != null) {
// ActiveRule Filter (profile and inheritance)
- BoolQueryBuilder childrenFilter = boolQuery();
- addTermFilter(childrenFilter, FIELD_ACTIVE_RULE_PROFILE_UUID, profile.getRulesProfileUuid());
- addTermFilter(childrenFilter, FIELD_ACTIVE_RULE_INHERITANCE, query.getInheritance());
- addTermFilter(childrenFilter, FIELD_ACTIVE_RULE_SEVERITY, query.getActiveSeverities());
+ BoolQueryBuilder activeRuleFilter = boolQuery();
+ addTermFilter(activeRuleFilter, FIELD_ACTIVE_RULE_PROFILE_UUID, profile.getRulesProfileUuid());
+ addTermFilter(activeRuleFilter, FIELD_ACTIVE_RULE_INHERITANCE, query.getInheritance());
+ addTermFilter(activeRuleFilter, FIELD_ACTIVE_RULE_SEVERITY, query.getActiveSeverities());
// ChildQuery
QueryBuilder childQuery;
- if (childrenFilter.hasClauses()) {
- childQuery = childrenFilter;
+ if (activeRuleFilter.hasClauses()) {
+ childQuery = activeRuleFilter;
} else {
childQuery = matchAllQuery();
}
- if (Boolean.TRUE.equals(query.getActivation())) {
+ if (TRUE.equals(query.getActivation())) {
filters.put("activation",
QueryBuilders.hasChildQuery(INDEX_TYPE_ACTIVE_RULE.getType(),
childQuery));
- } else if (Boolean.FALSE.equals(query.getActivation())) {
+ } else if (FALSE.equals(query.getActivation())) {
filters.put("activation",
boolQuery().mustNot(
QueryBuilders.hasChildQuery(INDEX_TYPE_ACTIVE_RULE.getType(),
childQuery)));
}
+ QProfileDto compareToQProfile = query.getCompareToQProfile();
+ if (compareToQProfile != null) {
+ filters.put("comparison",
+ QueryBuilders.hasChildQuery(INDEX_TYPE_ACTIVE_RULE.getType(),
+ boolQuery().must(QueryBuilders.termQuery(FIELD_ACTIVE_RULE_PROFILE_UUID, compareToQProfile.getRulesProfileUuid()))));
+ }
}
return filters;
diff --git a/server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleQuery.java b/server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleQuery.java
index bdd4e25843e..376e3f5f035 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleQuery.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleQuery.java
@@ -43,6 +43,7 @@ public class RuleQuery {
private Collection<RuleType> types;
private Boolean activation;
private QProfileDto profile;
+ private QProfileDto compareToQProfile;
private Collection<String> inheritance;
private Collection<String> activeSeverities;
private String templateKey;
@@ -272,4 +273,14 @@ public class RuleQuery {
this.organization = o;
return this;
}
+
+ @CheckForNull
+ public QProfileDto getCompareToQProfile() {
+ return compareToQProfile;
+ }
+
+ public RuleQuery setCompareToQProfile(@Nullable QProfileDto compareToQProfile) {
+ this.compareToQProfile = compareToQProfile;
+ return this;
+ }
}
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/qualityprofile/ws/show-example.json b/server/sonar-server/src/main/resources/org/sonar/server/qualityprofile/ws/show-example.json
index a628efa37c2..3d047742da6 100644
--- a/server/sonar-server/src/main/resources/org/sonar/server/qualityprofile/ws/show-example.json
+++ b/server/sonar-server/src/main/resources/org/sonar/server/qualityprofile/ws/show-example.json
@@ -12,10 +12,5 @@
"projectCount": 7,
"rulesUpdatedAt": "2016-12-22T19:10:03+0100",
"lastUsed": "2016-12-01T19:10:03+0100"
- },
- "compareToSonarWay": {
- "profile": "iU5OvuD2FLz",
- "profileName": "Sonar way",
- "missingRuleCount": 4
}
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ShowActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ShowActionTest.java
index 4393bc8d638..4d06ff2ff1b 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ShowActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ShowActionTest.java
@@ -23,14 +23,22 @@ package org.sonar.server.qualityprofile.ws;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.config.MapSettings;
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.db.DbTester;
import org.sonar.db.qualityprofile.QProfileDto;
+import org.sonar.db.rule.RuleDefinitionDto;
+import org.sonar.server.es.EsTester;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.organization.TestDefaultOrganizationProvider;
+import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
+import org.sonar.server.qualityprofile.index.ActiveRuleIteratorFactory;
+import org.sonar.server.rule.index.RuleIndex;
+import org.sonar.server.rule.index.RuleIndexDefinition;
+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;
@@ -55,14 +63,20 @@ public class ShowActionTest {
private static Languages LANGUAGES = new Languages(XOO1, XOO2);
@Rule
+ public EsTester es = new EsTester(new RuleIndexDefinition(new MapSettings()));
+ @Rule
public DbTester db = DbTester.create();
@Rule
public UserSessionRule userSession = UserSessionRule.standalone();
@Rule
public ExpectedException expectedException = ExpectedException.none();
+ private RuleIndexer ruleIndexer = new RuleIndexer(es.client(), db.getDbClient());
+ private ActiveRuleIndexer activeRuleIndexer = new ActiveRuleIndexer(db.getDbClient(), es.client(), new ActiveRuleIteratorFactory(db.getDbClient()));
+ private RuleIndex ruleIndex = new RuleIndex(es.client());
+
private WsActionTester ws = new WsActionTester(
- new ShowAction(db.getDbClient(), new QProfileWsSupport(db.getDbClient(), userSession, TestDefaultOrganizationProvider.from(db)), LANGUAGES));
+ new ShowAction(db.getDbClient(), new QProfileWsSupport(db.getDbClient(), userSession, TestDefaultOrganizationProvider.from(db)), LANGUAGES, ruleIndex));
@Test
public void test_definition() {
@@ -161,6 +175,41 @@ public class ShowActionTest {
public void compare_to_sonar_way_profile() {
QProfileDto sonarWayProfile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setIsBuiltIn(true).setName("Sonar way").setLanguage(XOO1.getKey()));
QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(XOO1.getKey()));
+ RuleDefinitionDto commonRule = db.rules().insertRule(r -> r.setLanguage(XOO1.getKey())).getDefinition();
+ RuleDefinitionDto sonarWayRule1 = db.rules().insertRule(r -> r.setLanguage(XOO1.getKey())).getDefinition();
+ RuleDefinitionDto sonarWayRule2 = db.rules().insertRule(r -> r.setLanguage(XOO1.getKey())).getDefinition();
+ RuleDefinitionDto profileRule1 = db.rules().insertRule(r -> r.setLanguage(XOO1.getKey())).getDefinition();
+ RuleDefinitionDto profileRule2 = db.rules().insertRule(r -> r.setLanguage(XOO1.getKey())).getDefinition();
+ RuleDefinitionDto profileRule3 = db.rules().insertRule(r -> r.setLanguage(XOO1.getKey())).getDefinition();
+ db.qualityProfiles().activateRule(profile, commonRule);
+ db.qualityProfiles().activateRule(profile, profileRule1);
+ db.qualityProfiles().activateRule(profile, profileRule2);
+ db.qualityProfiles().activateRule(profile, profileRule3);
+ db.qualityProfiles().activateRule(sonarWayProfile, commonRule);
+ db.qualityProfiles().activateRule(sonarWayProfile, sonarWayRule1);
+ db.qualityProfiles().activateRule(sonarWayProfile, sonarWayRule2);
+ ruleIndexer.indexOnStartup(ruleIndexer.getIndexTypes());
+ activeRuleIndexer.indexOnStartup(activeRuleIndexer.getIndexTypes());
+
+ CompareToSonarWay result = call(ws.newRequest()
+ .setParam(PARAM_PROFILE, profile.getKee())
+ .setParam(PARAM_COMPARE_TO_SONAR_WAY, "true"))
+ .getCompareToSonarWay();
+
+ assertThat(result)
+ .extracting(CompareToSonarWay::getProfile, CompareToSonarWay::getProfileName, CompareToSonarWay::getMissingRuleCount)
+ .containsExactly(sonarWayProfile.getKee(), sonarWayProfile.getName(), 2L);
+ }
+
+ @Test
+ public void compare_to_sonar_way_profile_when_same_active_rules() {
+ QProfileDto sonarWayProfile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setIsBuiltIn(true).setName("Sonar way").setLanguage(XOO1.getKey()));
+ QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(XOO1.getKey()));
+ RuleDefinitionDto commonRule = db.rules().insertRule(r -> r.setLanguage(XOO1.getKey())).getDefinition();
+ db.qualityProfiles().activateRule(profile, commonRule);
+ db.qualityProfiles().activateRule(sonarWayProfile, commonRule);
+ ruleIndexer.indexOnStartup(ruleIndexer.getIndexTypes());
+ activeRuleIndexer.indexOnStartup(activeRuleIndexer.getIndexTypes());
CompareToSonarWay result = call(ws.newRequest()
.setParam(PARAM_PROFILE, profile.getKee())
@@ -168,13 +217,14 @@ public class ShowActionTest {
.getCompareToSonarWay();
assertThat(result)
- .extracting(CompareToSonarWay::getProfile, CompareToSonarWay::getProfileName)
- .containsExactly(sonarWayProfile.getKee(), sonarWayProfile.getName());
+ .extracting(CompareToSonarWay::getProfile, CompareToSonarWay::getProfileName, CompareToSonarWay::getMissingRuleCount)
+ .containsExactly(sonarWayProfile.getKee(), sonarWayProfile.getName(), 0L);
}
@Test
public void no_comparison_when_sonar_way_does_not_exist() {
- QProfileDto anotherSonarWayProfile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setIsBuiltIn(true).setName("Another Sonar way").setLanguage(XOO1.getKey()));
+ QProfileDto anotherSonarWayProfile = db.qualityProfiles().insert(db.getDefaultOrganization(),
+ p -> p.setIsBuiltIn(true).setName("Another Sonar way").setLanguage(XOO1.getKey()));
QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(XOO1.getKey()));
ShowWsResponse result = call(ws.newRequest()
@@ -228,7 +278,7 @@ public class ShowActionTest {
CompareToSonarWay result = call(ws.newRequest()
.setParam(PARAM_PROFILE, profile.getKee())
.setParam(PARAM_COMPARE_TO_SONAR_WAY, "true"))
- .getCompareToSonarWay();
+ .getCompareToSonarWay();
assertThat(result)
.extracting(CompareToSonarWay::getProfile, CompareToSonarWay::getProfileName)
@@ -244,7 +294,7 @@ public class ShowActionTest {
CompareToSonarWay result = call(ws.newRequest()
.setParam(PARAM_PROFILE, profile.getKee())
.setParam(PARAM_COMPARE_TO_SONAR_WAY, "true"))
- .getCompareToSonarWay();
+ .getCompareToSonarWay();
assertThat(result)
.extracting(CompareToSonarWay::getProfile, CompareToSonarWay::getProfileName)
@@ -292,10 +342,11 @@ public class ShowActionTest {
.mapToObj(i -> db.components().insertPrivateProject())
.forEach(project -> db.qualityProfiles().associateWithProject(project, profile));
- ws = new WsActionTester(new ShowAction(db.getDbClient(), new QProfileWsSupport(db.getDbClient(), userSession, TestDefaultOrganizationProvider.from(db)), new Languages(cs)));
+ ws = new WsActionTester(
+ new ShowAction(db.getDbClient(), new QProfileWsSupport(db.getDbClient(), userSession, TestDefaultOrganizationProvider.from(db)), new Languages(cs), ruleIndex));
String result = ws.newRequest().setParam(PARAM_PROFILE, profile.getKee()).execute().getInput();
- assertJson(result).ignoreFields("rulesUpdatedAt", "lastUsed", "userUpdatedAt", "compareToSonarWay").isSimilarTo(ws.getDef().responseExampleAsString());
+ assertJson(result).ignoreFields("rulesUpdatedAt", "lastUsed", "userUpdatedAt").isSimilarTo(ws.getDef().responseExampleAsString());
}
private ShowWsResponse call(TestRequest request) {
diff --git a/server/sonar-server/src/test/java/org/sonar/server/rule/index/RuleIndexTest.java b/server/sonar-server/src/test/java/org/sonar/server/rule/index/RuleIndexTest.java
index b4f3d8e912e..807d239bfeb 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/rule/index/RuleIndexTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/rule/index/RuleIndexTest.java
@@ -383,6 +383,32 @@ public class RuleIndexTest {
assertThat(underTest.search(query, new SearchOptions()).getIds()).hasSize(2);
}
+ @Test
+ public void compare_to_another_profile() {
+ String xoo = "xoo";
+ QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(xoo));
+ QProfileDto anotherProfile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(xoo));
+ RuleDefinitionDto commonRule = db.rules().insertRule(r -> r.setLanguage(xoo)).getDefinition();
+ RuleDefinitionDto profileRule1 = db.rules().insertRule(r -> r.setLanguage(xoo)).getDefinition();
+ RuleDefinitionDto profileRule2 = db.rules().insertRule(r -> r.setLanguage(xoo)).getDefinition();
+ RuleDefinitionDto profileRule3 = db.rules().insertRule(r -> r.setLanguage(xoo)).getDefinition();
+ RuleDefinitionDto anotherProfileRule1 = db.rules().insertRule(r -> r.setLanguage(xoo)).getDefinition();
+ RuleDefinitionDto anotherProfileRule2 = db.rules().insertRule(r -> r.setLanguage(xoo)).getDefinition();
+ db.qualityProfiles().activateRule(profile, commonRule);
+ db.qualityProfiles().activateRule(profile, profileRule1);
+ db.qualityProfiles().activateRule(profile, profileRule2);
+ db.qualityProfiles().activateRule(profile, profileRule3);
+ db.qualityProfiles().activateRule(anotherProfile, commonRule);
+ db.qualityProfiles().activateRule(anotherProfile, anotherProfileRule1);
+ db.qualityProfiles().activateRule(anotherProfile, anotherProfileRule2);
+ index();
+
+ verifySearch(newRuleQuery().setActivation(false).setQProfile(profile).setCompareToQProfile(anotherProfile), anotherProfileRule1, anotherProfileRule2);
+ verifySearch(newRuleQuery().setActivation(true).setQProfile(profile).setCompareToQProfile(anotherProfile), commonRule);
+ verifySearch(newRuleQuery().setActivation(true).setQProfile(profile).setCompareToQProfile(profile), commonRule, profileRule1, profileRule2, profileRule3);
+ verifySearch(newRuleQuery().setActivation(false).setQProfile(profile).setCompareToQProfile(profile));
+ }
+
@SafeVarargs
private final RuleDefinitionDto createRule(Consumer<RuleDefinitionDto>... consumers) {
return db.rules().insert(consumers);