Skip to content

Commit

Permalink
SONAR-6306 Show rule stats on quality profile inheritance items
Browse files Browse the repository at this point in the history
  • Loading branch information
jblievremont committed Apr 10, 2015
1 parent 5a4027c commit 9fa4c60
Show file tree
Hide file tree
Showing 6 changed files with 251 additions and 119 deletions.
Expand Up @@ -19,6 +19,7 @@
*/
package org.sonar.server.qualityprofile.ws;

import com.google.common.collect.Multimap;
import org.sonar.api.resources.Languages;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
Expand All @@ -31,23 +32,29 @@
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.qualityprofile.QProfile;
import org.sonar.server.qualityprofile.QProfileFactory;
import org.sonar.server.qualityprofile.QProfileLoader;
import org.sonar.server.qualityprofile.QProfileLookup;
import org.sonar.server.search.FacetValue;

import java.util.List;
import java.util.Map;

public class QProfileInheritanceAction implements BaseQProfileWsAction {

private final DbClient dbClient;

private final QProfileLookup profileLookup;

private final QProfileLoader profileLoader;

private final QProfileFactory profileFactory;

private final Languages languages;

public QProfileInheritanceAction(DbClient dbClient, QProfileLookup profileLookup, QProfileFactory profileFactory, Languages languages) {
public QProfileInheritanceAction(DbClient dbClient, QProfileLookup profileLookup, QProfileLoader profileLoader, QProfileFactory profileFactory, Languages languages) {
this.dbClient = dbClient;
this.profileLookup = profileLookup;
this.profileLoader = profileLoader;
this.profileFactory = profileFactory;
this.languages = languages;
}
Expand Down Expand Up @@ -75,40 +82,86 @@ public void handle(Request request, Response response) throws Exception {

List<QProfile> ancestors = profileLookup.ancestors(profile, session);
List<QualityProfileDto> children = dbClient.qualityProfileDao().findChildren(session, profileKey);
Map<String, Multimap<String, FacetValue>> profileStats = profileLoader.getAllProfileStats();

writeResponse(response.newJsonWriter(), ancestors, children);
writeResponse(response.newJsonWriter(), profile, ancestors, children, profileStats);
} finally {
session.close();
}
}

private void writeResponse(JsonWriter json, List<QProfile> ancestors, List<QualityProfileDto> children) {
private void writeResponse(JsonWriter json, QualityProfileDto profile, List<QProfile> ancestors, List<QualityProfileDto> children,
Map<String, Multimap<String, FacetValue>> profileStats) {
json.beginObject();
writeAncestors(json, ancestors);
writeChildren(json, children);
writeProfile(json, profile, profileStats);
writeAncestors(json, ancestors, profileStats);
writeChildren(json, children, profileStats);
json.endObject().close();
}

private void writeAncestors(JsonWriter json, List<QProfile> ancestors) {
private void writeProfile(JsonWriter json, QualityProfileDto profile, Map<String, Multimap<String, FacetValue>> profileStats) {
String profileKey = profile.getKey();
json.name("profile").beginObject()
.prop("key", profileKey)
.prop("name", profile.getName())
.prop("parent", profile.getParentKee());
writeStats(json, profileKey, profileStats);
json.endObject();
}

private void writeAncestors(JsonWriter json, List<QProfile> ancestors, Map<String, Multimap<String, FacetValue>> profileStats) {
json.name("ancestors").beginArray();
for (QProfile ancestor : ancestors) {
String ancestorKey = ancestor.key();
json.beginObject()
.prop("key", ancestor.key())
.prop("key", ancestorKey)
.prop("name", ancestor.name())
.prop("parent", ancestor.parent())
.endObject();
.prop("parent", ancestor.parent());
writeStats(json, ancestorKey, profileStats);
json.endObject();
}
json.endArray();
}

private void writeChildren(JsonWriter json, List<QualityProfileDto> children) {
private void writeChildren(JsonWriter json, List<QualityProfileDto> children, Map<String, Multimap<String, FacetValue>> profileStats) {
json.name("children").beginArray();
for (QualityProfileDto child : children) {
String childKey = child.getKey();
json.beginObject()
.prop("key", child.getKey())
.prop("name", child.getName())
.endObject();
.prop("key", childKey)
.prop("name", child.getName());
writeStats(json, childKey, profileStats);
json.endObject();
}
json.endArray();
}

private void writeStats(JsonWriter json, String profileKey, Map<String, Multimap<String, FacetValue>> profileStats) {
if (profileStats.containsKey(profileKey)) {
Multimap<String, FacetValue> ancestorStats = profileStats.get(profileKey);
json.prop("activeRuleCount", getActiveRuleCount(ancestorStats));
json.prop("overridingRuleCount", getOverridingRuleCount(ancestorStats));
}
}

private Long getActiveRuleCount(Multimap<String, FacetValue> profileStats) {
Long result = null;
if (profileStats.containsKey("countActiveRules")) {
result = profileStats.get("countActiveRules").iterator().next().getValue();
}
return result;
}

private Long getOverridingRuleCount(Multimap<String, FacetValue> profileStats) {
Long result = null;
if (profileStats.containsKey("inheritance")) {
for (FacetValue value : profileStats.get("inheritance")) {
if ("OVERRIDES".equals(value.getKey())) {
result = value.getValue();
}
}
}
return result;
}

}
@@ -0,0 +1,35 @@
{
"profile": {
"key": "xoo-my-bu-profile-23456",
"name": "My BU Profile",
"parent": "xoo-my-company-profile-12345",
"activeRuleCount": 3,
"overridingRuleCount": 1
},
"ancestors": [
{
"key": "xoo-my-company-profile-12345",
"name": "My Company Profile",
"parent": "xoo-my-group-profile-01234",
"activeRuleCount": 3
},
{
"key": "xoo-my-group-profile-01234",
"name": "My Group Profile",
"activeRuleCount": 2
}
],
"children": [
{
"key": "xoo-for-project-one-34567",
"name": "For Project One",
"activeRuleCount": 5
},
{
"key": "xoo-for-project-two-45678",
"name": "For Project Two",
"activeRuleCount": 4,
"overridingRuleCount": 1
}
]
}
@@ -0,0 +1,136 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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.qualityprofile.ws;

import org.junit.After;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.rule.Severity;
import org.sonar.core.persistence.DbSession;
import org.sonar.core.qualityprofile.db.ActiveRuleDto;
import org.sonar.core.qualityprofile.db.QualityProfileDto;
import org.sonar.core.rule.RuleDto;
import org.sonar.server.db.DbClient;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.qualityprofile.QProfileName;
import org.sonar.server.qualityprofile.QProfileTesting;
import org.sonar.server.qualityprofile.RuleActivation;
import org.sonar.server.qualityprofile.RuleActivator;
import org.sonar.server.tester.ServerTester;
import org.sonar.server.ws.WsTester;

public class QProfileInheritanceActionMediumTest {

@ClassRule
public static final ServerTester tester = new ServerTester();

private WsTester wsTester;

private DbClient db;

private DbSession session;

@Before
public void setUp() throws Exception {
tester.clearDbAndIndexes();
db = tester.get(DbClient.class);
session = db.openSession(false);

wsTester = new WsTester(tester.get(QProfilesWs.class));
}

@After
public void tearDown() {
session.close();
}

@Test
public void inheritance_nominal() throws Exception {
RuleDto rule1 = createRule("xoo", "rule1");
RuleDto rule2 = createRule("xoo", "rule2");
RuleDto rule3 = createRule("xoo", "rule3");

/*
* groupWide (2) <- companyWide (2) <- buWide (2, 1 overriding) <- (forProject1 (2), forProject2 (2))
*/
QualityProfileDto groupWide = createProfile("xoo", "My Group Profile", "xoo-my-group-profile-01234");
createActiveRule(rule1, groupWide);
createActiveRule(rule2, groupWide);
session.commit();

QualityProfileDto companyWide = createProfile("xoo", "My Company Profile", "xoo-my-company-profile-12345");
setParent(groupWide, companyWide);

QualityProfileDto buWide = createProfile("xoo", "My BU Profile", "xoo-my-bu-profile-23456");
setParent(companyWide, buWide);
overrideActiveRuleSeverity(rule1, buWide, Severity.CRITICAL);

QualityProfileDto forProject1 = createProfile("xoo", "For Project One", "xoo-for-project-one-34567");
setParent(buWide, forProject1);
createActiveRule(rule3, forProject1);
session.commit();

QualityProfileDto forProject2 = createProfile("xoo", "For Project Two", "xoo-for-project-two-45678");
setParent(buWide, forProject2);
overrideActiveRuleSeverity(rule2, forProject2, Severity.CRITICAL);

wsTester.newGetRequest("api/qualityprofiles", "inheritance").setParam("profileKey", buWide.getKee()).execute().assertJson(getClass(), "inheritance-buWide.json");
}

@Test(expected = NotFoundException.class)
public void fail_if_not_found() throws Exception {
wsTester.newGetRequest("api/qualityprofiles", "inheritance").setParam("profileKey", "polop").execute();
}

private QualityProfileDto createProfile(String lang, String name, String key) {
QualityProfileDto profile = QProfileTesting.newDto(new QProfileName(lang, name), key);
db.qualityProfileDao().insert(session, profile);
session.commit();
return profile;
}

private void setParent(QualityProfileDto profile, QualityProfileDto parent) {
tester.get(RuleActivator.class).setParent(parent.getKey(), profile.getKey());
}

private RuleDto createRule(String lang, String id) {
RuleDto rule = RuleDto.createFor(RuleKey.of("blah", id))
.setLanguage(lang)
.setSeverity(Severity.BLOCKER)
.setStatus(RuleStatus.READY);
db.ruleDao().insert(session, rule);
return rule;
}

private ActiveRuleDto createActiveRule(RuleDto rule, QualityProfileDto profile) {
ActiveRuleDto activeRule = ActiveRuleDto.createFor(profile, rule)
.setSeverity(rule.getSeverityString());
db.activeRuleDao().insert(session, activeRule);
return activeRule;
}

private void overrideActiveRuleSeverity(RuleDto rule, QualityProfileDto profile, String severity) {
tester.get(RuleActivator.class).activate(session, new RuleActivation(rule.getKey()).setSeverity(severity), profile.getKey());
session.commit();
}
}

0 comments on commit 9fa4c60

Please sign in to comment.