]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6306 Show rule stats on quality profile inheritance items
authorJean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com>
Wed, 8 Apr 2015 14:19:44 +0000 (16:19 +0200)
committerJean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com>
Fri, 10 Apr 2015 09:19:25 +0000 (11:19 +0200)
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfileInheritanceAction.java
server/sonar-server/src/main/resources/org/sonar/server/qualityprofile/ws/example-inheritance.json [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfileInheritanceActionMediumTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfileInheritanceActionTest.java [deleted file]
server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/ws/QProfileInheritanceActionMediumTest/inheritance-buWide.json [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/ws/QProfileInheritanceActionTest/inheritance-buWide.json [deleted file]

index 131215733b5dbc62047fe9875a4cf415ecb49c48..2212384869c5a4c063eaee89ebeeabfa07d2fcc9 100644 (file)
@@ -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;
@@ -31,9 +32,12 @@ import org.sonar.server.db.DbClient;
 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 {
 
@@ -41,13 +45,16 @@ public class QProfileInheritanceAction implements BaseQProfileWsAction {
 
   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;
   }
@@ -75,40 +82,86 @@ public class QProfileInheritanceAction implements BaseQProfileWsAction {
 
       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;
+  }
+
 }
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/qualityprofile/ws/example-inheritance.json b/server/sonar-server/src/main/resources/org/sonar/server/qualityprofile/ws/example-inheritance.json
new file mode 100644 (file)
index 0000000..743a4b7
--- /dev/null
@@ -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
+    }
+  ]
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfileInheritanceActionMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfileInheritanceActionMediumTest.java
new file mode 100644 (file)
index 0000000..0a6d0c8
--- /dev/null
@@ -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();
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfileInheritanceActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfileInheritanceActionTest.java
deleted file mode 100644 (file)
index 4231d26..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * 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.junit.experimental.categories.Category;
-import org.sonar.api.utils.System2;
-import org.sonar.core.persistence.DbSession;
-import org.sonar.core.persistence.DbTester;
-import org.sonar.core.qualityprofile.db.QualityProfileDao;
-import org.sonar.core.qualityprofile.db.QualityProfileDto;
-import org.sonar.server.db.DbClient;
-import org.sonar.server.exceptions.NotFoundException;
-import org.sonar.server.language.LanguageTesting;
-import org.sonar.server.qualityprofile.QProfileFactory;
-import org.sonar.server.qualityprofile.QProfileLookup;
-import org.sonar.server.qualityprofile.QProfileName;
-import org.sonar.server.qualityprofile.QProfileTesting;
-import org.sonar.server.ws.WsTester;
-import org.sonar.test.DbTests;
-
-import static org.mockito.Mockito.mock;
-
-@Category(DbTests.class)
-public class QProfileInheritanceActionTest {
-
-  @ClassRule
-  public static final DbTester dbTester = new DbTester();
-
-  private WsTester wsTester;
-
-  private DbClient dbClient;
-
-  private DbSession session;
-
-  @Before
-  public void setUp() throws Exception {
-    dbTester.truncateTables();
-    dbClient = new DbClient(dbTester.database(), dbTester.myBatis(),
-      new QualityProfileDao(dbTester.myBatis(), mock(System2.class)));
-    session = dbClient.openSession(false);
-
-    wsTester = new WsTester(new QProfilesWs(
-      mock(RuleActivationActions.class),
-      mock(BulkRuleActivationActions.class),
-      mock(ProjectAssociationActions.class),
-      new QProfileInheritanceAction(dbClient, new QProfileLookup(dbClient), new QProfileFactory(dbClient), LanguageTesting.newLanguages("xoo"))));
-  }
-
-  @After
-  public void tearDown() {
-    session.close();
-  }
-
-  @Test
-  public void inheritance_nominal() throws Exception {
-    /*
-     * groupWide <- companyWide <- buWide <- (forProject1, forProject2)
-     */
-    QualityProfileDto groupWide = QProfileTesting.newDto(QProfileName.createFor("xoo", "My Group Profile"), "xoo-my-group-profile-01234");
-    QualityProfileDto companyWide = QProfileTesting.newDto(QProfileName.createFor("xoo", "My Company Profile"), "xoo-my-company-profile-12345").setParentKee(groupWide.getKee());
-    QualityProfileDto buWide = QProfileTesting.newDto(QProfileName.createFor("xoo", "My BU Profile"), "xoo-my-by-profile-23456").setParentKee(companyWide.getKee());
-    QualityProfileDto forProject1 = QProfileTesting.newDto(QProfileName.createFor("xoo", "For Project One"), "xoo-for-project-one-34567").setParentKee(buWide.getKee());
-    QualityProfileDto forProject2 = QProfileTesting.newDto(QProfileName.createFor("xoo", "For Project Two"), "xoo-for-project-two-45678").setParentKee(buWide.getKee());
-
-    dbClient.qualityProfileDao().insert(session, groupWide, companyWide, buWide, forProject1, forProject2);
-    session.commit();
-
-    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();
-  }
-}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/ws/QProfileInheritanceActionMediumTest/inheritance-buWide.json b/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/ws/QProfileInheritanceActionMediumTest/inheritance-buWide.json
new file mode 100644 (file)
index 0000000..9e3707e
--- /dev/null
@@ -0,0 +1,14 @@
+{
+  "profile": {
+    "key": "xoo-my-bu-profile-23456", "name": "My BU Profile", "parent": "xoo-my-company-profile-12345",
+    "activeRuleCount": 2, "overridingRuleCount": 1
+  },
+  "ancestors": [
+    {"key": "xoo-my-company-profile-12345", "name": "My Company Profile", "parent": "xoo-my-group-profile-01234", "activeRuleCount": 2},
+    {"key": "xoo-my-group-profile-01234", "name": "My Group Profile", "activeRuleCount": 2}
+  ],
+  "children": [
+    {"key": "xoo-for-project-one-34567", "name": "For Project One", "activeRuleCount": 3},
+    {"key": "xoo-for-project-two-45678", "name": "For Project Two", "activeRuleCount": 2, "overridingRuleCount": 1}
+  ]
+}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/ws/QProfileInheritanceActionTest/inheritance-buWide.json b/server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/ws/QProfileInheritanceActionTest/inheritance-buWide.json
deleted file mode 100644 (file)
index 154c25e..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-  "ancestors": [
-    {"key": "xoo-my-company-profile-12345", "name": "My Company Profile", "parent": "xoo-my-group-profile-01234"},
-    {"key": "xoo-my-group-profile-01234", "name": "My Group Profile"}
-  ],
-  "children": [
-    {"key": "xoo-for-project-one-34567", "name": "For Project One"},
-    {"key": "xoo-for-project-two-45678", "name": "For Project Two"}
-  ]
-}
\ No newline at end of file