]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6294 Apply feedback on description and missing fields
authorJean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com>
Tue, 31 Mar 2015 10:45:52 +0000 (12:45 +0200)
committerJean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com>
Tue, 31 Mar 2015 12:03:37 +0000 (14:03 +0200)
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/QProfileSearchAction.java
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfileSearchActionTest.java
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsTest.java
server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/ws/QProfileSearchActionTest/search.json
server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/ws/QProfileSearchActionTest/search_fields.json
server/sonar-server/src/test/resources/org/sonar/server/qualityprofile/ws/QProfileSearchActionTest/search_xoo1.json

index 1a2a8618316a94cf2d77cd40c0547b642488d653..fcdfea11a98e588faf6a0fee6f08777a0f3cd465 100644 (file)
@@ -22,6 +22,7 @@ package org.sonar.server.qualityprofile.ws;
 import com.google.common.base.Function;
 import com.google.common.collect.Collections2;
 import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
 import org.apache.commons.lang.builder.CompareToBuilder;
 import org.sonar.api.resources.Language;
 import org.sonar.api.resources.Languages;
@@ -30,7 +31,9 @@ import org.sonar.api.server.ws.Response;
 import org.sonar.api.server.ws.WebService;
 import org.sonar.api.server.ws.WebService.NewAction;
 import org.sonar.api.utils.text.JsonWriter;
+import org.sonar.core.util.NonNullInputFunction;
 import org.sonar.server.qualityprofile.QProfile;
+import org.sonar.server.qualityprofile.QProfileLoader;
 import org.sonar.server.qualityprofile.QProfileLookup;
 
 import javax.annotation.CheckForNull;
@@ -43,10 +46,14 @@ public class QProfileSearchAction implements BaseQProfileWsAction {
   private static final String FIELD_KEY = "key";
   private static final String FIELD_NAME = "name";
   private static final String FIELD_LANGUAGE = "language";
+  private static final String FIELD_LANGUAGE_NAME = "languageName";
   private static final String FIELD_IS_INHERITED = "isInherited";
   private static final String FIELD_IS_DEFAULT = "isDefault";
   private static final String FIELD_PARENT_KEY = "parentKey";
-  private static final Set<String> ALL_FIELDS = ImmutableSet.of(FIELD_KEY, FIELD_NAME, FIELD_LANGUAGE, FIELD_IS_INHERITED, FIELD_PARENT_KEY, FIELD_IS_DEFAULT);
+  private static final String FIELD_PARENT_NAME = "parentName";
+  private static final String FIELD_ACTIVE_RULE_COUNT = "activeRuleCount";
+  private static final Set<String> ALL_FIELDS = ImmutableSet.of(
+    FIELD_KEY, FIELD_NAME, FIELD_LANGUAGE, FIELD_LANGUAGE_NAME, FIELD_IS_INHERITED, FIELD_PARENT_KEY, FIELD_PARENT_NAME, FIELD_IS_DEFAULT, FIELD_ACTIVE_RULE_COUNT);
 
   private static final String PARAM_LANGUAGE = FIELD_LANGUAGE;
   private static final String PARAM_FIELDS = "f";
@@ -56,9 +63,12 @@ public class QProfileSearchAction implements BaseQProfileWsAction {
 
   private final QProfileLookup profileLookup;
 
-  public QProfileSearchAction(Languages languages, QProfileLookup profileLookup) {
+  private final QProfileLoader profileLoader;
+
+  public QProfileSearchAction(Languages languages, QProfileLookup profileLookup, QProfileLoader profileLoader) {
     this.languages = languages;
     this.profileLookup = profileLookup;
+    this.profileLoader = profileLoader;
   }
 
   @Override
@@ -86,19 +96,34 @@ public class QProfileSearchAction implements BaseQProfileWsAction {
 
     JsonWriter json = response.newJsonWriter().beginObject();
     writeProfiles(json, profiles, fields);
-    writeLanguages(json);
     json.endObject().close();
   }
 
   private void writeProfiles(JsonWriter json, List<QProfile> profiles, List<String> fields) {
+    Map<String, QProfile> profilesByKey = Maps.uniqueIndex(profiles, new NonNullInputFunction<QProfile, String>() {
+      @Override
+      protected String doApply(QProfile input) {
+        return input.key();
+      }
+    });
+    Map<String, Long> activeRuleCountByKey = profileLoader.countAllActiveRules();
+
+
     json.name("profiles")
       .beginArray();
     for (QProfile profile : profiles) {
+      if (languages.get(profile.language()) == null) {
+        // Hide profiles on an unsupported language
+        continue;
+      }
+
+      String key = profile.key();
       json.beginObject()
-        .prop(FIELD_KEY, nullUnlessNeeded(FIELD_KEY, profile.key(), fields))
+        .prop(FIELD_KEY, nullUnlessNeeded(FIELD_KEY, key, fields))
         .prop(FIELD_NAME, nullUnlessNeeded(FIELD_NAME, profile.name(), fields))
-        .prop(FIELD_LANGUAGE, nullUnlessNeeded(FIELD_LANGUAGE, profile.language(), fields))
-        .prop(FIELD_PARENT_KEY, nullUnlessNeeded(FIELD_PARENT_KEY, profile.parent(), fields));
+        .prop(FIELD_ACTIVE_RULE_COUNT, activeRuleCountByKey.get(key));
+      writeLanguageFields(json, profile, fields);
+      writeParentFields(json, profile, fields, profilesByKey);
       // Special case for booleans
       if (fieldIsNeeded(FIELD_IS_INHERITED, fields)) {
         json.prop(FIELD_IS_INHERITED, profile.isInherited());
@@ -111,6 +136,19 @@ public class QProfileSearchAction implements BaseQProfileWsAction {
     json.endArray();
   }
 
+  private void writeLanguageFields(JsonWriter json, QProfile profile, List<String> fields) {
+    String languageKey = profile.language();
+    json.prop(FIELD_LANGUAGE, nullUnlessNeeded(FIELD_LANGUAGE, languageKey, fields))
+      .prop(FIELD_LANGUAGE_NAME, nullUnlessNeeded(FIELD_LANGUAGE_NAME, languages.get(languageKey).getName(), fields));
+  }
+
+  private void writeParentFields(JsonWriter json, QProfile profile, List<String> fields, Map<String, QProfile> profilesByKey) {
+    String parentKey = profile.parent();
+    QProfile parent = parentKey == null ? null : profilesByKey.get(parentKey);
+    json.prop(FIELD_PARENT_KEY, nullUnlessNeeded(FIELD_PARENT_KEY, parentKey, fields))
+      .prop(FIELD_PARENT_NAME, nullUnlessNeeded(FIELD_PARENT_NAME, parent == null ? parentKey : parent.name(), fields));
+  }
+
   @CheckForNull
   private <T> T nullUnlessNeeded(String field, T value, @Nullable List<String> fields) {
     return fieldIsNeeded(field, fields) ? value : null;
@@ -120,28 +158,16 @@ public class QProfileSearchAction implements BaseQProfileWsAction {
     return fields == null || fields.contains(field);
   }
 
-  private void writeLanguages(JsonWriter json) {
-    json.name("languages")
-      .beginArray();
-    for (Language language : languages.all()) {
-      json.beginObject()
-        .prop(FIELD_KEY, language.getKey())
-        .prop(FIELD_NAME, language.getName())
-        .endObject();
-    }
-    json.endArray();
-  }
-
   @Override
   public void define(WebService.NewController controller) {
     NewAction search = controller.createAction("search")
       .setSince("5.2")
-      .setDescription("")
+      .setDescription("List quality profiles.")
       .setHandler(this)
       .setResponseExample(getClass().getResource("example-search.json"));
 
     search.createParam(PARAM_LANGUAGE)
-      .setDescription("The key of a language supported by the platform. If specified, only profiles for the given language are returned")
+      .setDescription("The key of a language supported by the platform. If specified, only profiles for the given language are returned.")
       .setExampleValue("js")
       .setPossibleValues(Collections2.transform(Arrays.asList(languages.all()), new Function<Language, String>() {
         @Override
@@ -151,7 +177,7 @@ public class QProfileSearchAction implements BaseQProfileWsAction {
       }));
 
     search.createParam(PARAM_FIELDS)
-      .setDescription("Use to restrict returned fields")
+      .setDescription("Use to restrict returned fields.")
       .setExampleValue("key,language")
       .setPossibleValues(ALL_FIELDS);
   }
index f0d371c900ffea2036ea7dd9787ae857046e6e44..44165ee051632ab3e4bdd4be320ba0810b1374d7 100644 (file)
@@ -19,6 +19,7 @@
  */
 package org.sonar.server.qualityprofile.ws;
 
+import com.google.common.collect.ImmutableMap;
 import org.apache.commons.lang.StringUtils;
 import org.junit.After;
 import org.junit.Before;
@@ -33,10 +34,12 @@ 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.qualityprofile.QProfileLoader;
 import org.sonar.server.qualityprofile.QProfileLookup;
 import org.sonar.server.ws.WsTester;
 
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 public class QProfileSearchActionTest {
 
@@ -53,6 +56,7 @@ public class QProfileSearchActionTest {
 
   private DbSession session;
 
+  private QProfileLoader profileLoader;
 
   @Before
   public void setUp() throws Exception {
@@ -61,6 +65,9 @@ public class QProfileSearchActionTest {
     dbClient = new DbClient(dbTester.database(), dbTester.myBatis(), qualityProfileDao);
     session = dbClient.openSession(false);
 
+    // TODO Replace with actual implementation after removal of DaoV2...
+    profileLoader = mock(QProfileLoader.class);
+
     xoo1 = createLanguage("xoo1");
     xoo2 = createLanguage("xoo2");
 
@@ -68,7 +75,7 @@ public class QProfileSearchActionTest {
       mock(RuleActivationActions.class),
       mock(BulkRuleActivationActions.class),
       mock(ProjectAssociationActions.class),
-      new QProfileSearchAction(new Languages(xoo1, xoo2), new QProfileLookup(dbClient))));
+      new QProfileSearchAction(new Languages(xoo1, xoo2), new QProfileLookup(dbClient), profileLoader)));
   }
 
   @After
@@ -78,10 +85,17 @@ public class QProfileSearchActionTest {
 
   @Test
   public void search_nominal() throws Exception {
+    when(profileLoader.countAllActiveRules()).thenReturn(ImmutableMap.of(
+      "sonar-way-xoo1-12345", 11L,
+      "sonar-way-xoo2-23456", 22L,
+      "my-sonar-way-xoo2-34567", 33L
+      ));
+
     qualityProfileDao.insert(session,
       QualityProfileDto.createFor("sonar-way-xoo1-12345").setLanguage(xoo1.getKey()).setName("Sonar way").setDefault(true),
       QualityProfileDto.createFor("sonar-way-xoo2-23456").setLanguage(xoo2.getKey()).setName("Sonar way"),
-      QualityProfileDto.createFor("my-sonar-way-xoo2-34567").setLanguage(xoo2.getKey()).setName("My Sonar way").setParentKee("sonar-way-xoo2-23456")
+      QualityProfileDto.createFor("my-sonar-way-xoo2-34567").setLanguage(xoo2.getKey()).setName("My Sonar way").setParentKee("sonar-way-xoo2-23456"),
+      QualityProfileDto.createFor("sonar-way-other-666").setLanguage("other").setName("Sonar way").setDefault(true)
       );
     session.commit();
 
index 5ffaa3d3fc18a4a7fe7798aea88f6f29297ce01a..c2eb08cab48e555f5d70bdbc89a538cc9eb3e70e 100644 (file)
@@ -70,7 +70,7 @@ public class QProfilesWsTest {
       new ProjectAssociationActions(null, null, null, languages),
       new QProfileRestoreBuiltInAction(
         mock(QProfileService.class)),
-      new QProfileSearchAction(new Languages(xoo1, xoo2), null)
+      new QProfileSearchAction(new Languages(xoo1, xoo2), null, null)
     )).controller(QProfilesWs.API_ENDPOINT);
   }
 
@@ -97,7 +97,8 @@ public class QProfilesWsTest {
     assertThat(search.isPost()).isFalse();
     assertThat(search.params()).hasSize(2);
     assertThat(search.param("language").possibleValues()).containsOnly("xoo1", "xoo2");
-    assertThat(search.param("f").possibleValues()).containsOnly("key", "name", "language", "isInherited", "parentKey", "isDefault");
+    assertThat(search.param("f").possibleValues())
+      .containsOnly("key", "name", "language", "languageName", "isInherited", "parentKey", "parentName", "isDefault", "activeRuleCount");
   }
 
   @Test
index 5e0ebb37eb58521ba44ced33b3f2736393cfb41a..bc7499c23b25a31c66aee9efd52ab953e46437c6 100644 (file)
@@ -4,25 +4,28 @@
       "key": "sonar-way-xoo1-12345",
       "name": "Sonar way",
       "language": "xoo1",
+      "languageName": "Xoo1",
       "isInherited": false,
-      "isDefault": true
+      "isDefault": true,
+      "activeRuleCount": 11
     },
     {
       "key": "my-sonar-way-xoo2-34567",
       "name": "My Sonar way",
       "language": "xoo2",
+      "languageName": "Xoo2",
       "isInherited": true,
-      "parentKey": "sonar-way-xoo2-23456"
+      "parentKey": "sonar-way-xoo2-23456",
+      "parentName": "Sonar way",
+      "activeRuleCount": 33
     },
     {
       "key": "sonar-way-xoo2-23456",
       "name": "Sonar way",
       "language": "xoo2",
+      "languageName": "Xoo2",
       "isInherited": false,
+      "activeRuleCount": 22
     }
-  ],
-  "languages": [
-    {"key": "xoo1", "name": "Xoo1"},
-    {"key": "xoo2", "name": "Xoo2"}
   ]
 }
\ No newline at end of file
index 99cefd4739af0c0ea1a4f772faedf0132b3840b1..143625c201f7aaa60a8537df57f8c80bf874bbb4 100644 (file)
@@ -2,19 +2,15 @@
   "profiles": [
     {
       "key": "sonar-way-xoo1-12345",
-      "language": "xoo1",
+      "language": "xoo1"
     },
     {
       "key": "my-sonar-way-xoo2-34567",
-      "language": "xoo2",
+      "language": "xoo2"
     },
     {
       "key": "sonar-way-xoo2-23456",
-      "language": "xoo2",
+      "language": "xoo2"
     }
-  ],
-  "languages": [
-    {"key": "xoo1", "name": "Xoo1"},
-    {"key": "xoo2", "name": "Xoo2"}
   ]
 }
\ No newline at end of file
index 5932aa0a1460bee0d5715e223d5902f1d243ba32..fcff99ce520483b5c377d313a46b83ec1b172e76 100644 (file)
@@ -4,11 +4,8 @@
       "key": "sonar-way-xoo1-12345",
       "name": "Sonar way",
       "language": "xoo1",
+      "languageName": "Xoo1",
       "isInherited": false
     }
-  ],
-  "languages": [
-    {"key": "xoo1", "name": "Xoo1"},
-    {"key": "xoo2", "name": "Xoo2"}
   ]
 }
\ No newline at end of file