Browse Source

SONAR-9482 Show ws counts missing rules compared to Sonar way

tags/6.5-M2
Teryk Bellahsene 7 years ago
parent
commit
a756c3bc2c

+ 12
- 1
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ShowAction.java View File

@@ -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();
}


+ 22
- 14
server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleIndex.java View File

@@ -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;

+ 11
- 0
server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleQuery.java View File

@@ -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;
}
}

+ 0
- 5
server/sonar-server/src/main/resources/org/sonar/server/qualityprofile/ws/show-example.json View File

@@ -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
}
}

+ 59
- 8
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ShowActionTest.java View File

@@ -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;
@@ -54,6 +62,8 @@ public class ShowActionTest {
private static Language XOO2 = newLanguage("xoo2");
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
@@ -61,8 +71,12 @@ public class ShowActionTest {
@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) {

+ 26
- 0
server/sonar-server/src/test/java/org/sonar/server/rule/index/RuleIndexTest.java View File

@@ -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);

Loading…
Cancel
Save