]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-5007 - Implemented activation and qprofile params for WS
authorStephane Gamard <stephane.gamard@searchbox.com>
Mon, 19 May 2014 12:38:36 +0000 (14:38 +0200)
committerStephane Gamard <stephane.gamard@searchbox.com>
Mon, 19 May 2014 12:57:44 +0000 (14:57 +0200)
sonar-core/src/main/java/org/sonar/core/qualityprofile/db/QualityProfileKey.java
sonar-server/src/main/java/org/sonar/server/qualityprofile/index/ActiveRuleIndex.java
sonar-server/src/main/java/org/sonar/server/rule2/RuleService.java
sonar-server/src/main/java/org/sonar/server/rule2/index/RuleIndex.java
sonar-server/src/main/java/org/sonar/server/rule2/index/RuleQuery.java
sonar-server/src/main/java/org/sonar/server/rule2/ws/SearchAction.java
sonar-server/src/test/java/org/sonar/server/rule2/RuleServiceMediumTest.java
sonar-server/src/test/java/org/sonar/server/rule2/ws/RulesWebServiceTest.java
sonar-server/src/test/resources/org/sonar/server/rule2/ws/RulesWebServiceTest/search_no_active_rules.json [new file with mode: 0644]
sonar-server/src/test/resources/org/sonar/server/rule2/ws/RulesWebServiceTest/search_profile_active_rules.json [new file with mode: 0644]

index f6677a43d5129fafe94eabccb6c1e32317897d8d..7f59ecf5e6d6b7059fecdd57d673b948816d6fe6 100644 (file)
@@ -25,7 +25,6 @@ import com.google.common.base.Strings;
 import java.io.Serializable;
 
 /**
- * Created by gamars on 05/05/14.
  *
  * @since 4.4
  */
@@ -51,8 +50,8 @@ public class QualityProfileKey implements Serializable{
    * if the format is not valid.
    */
   public static QualityProfileKey parse(String s) {
-    String[] split = s.split(":");
-    Preconditions.checkArgument(split.length == 3, "Bad format of activeRule key: " + s);
+    String[] split = s.trim().split(":");
+    Preconditions.checkArgument(split.length == 2, "Bad format of QualityProfileKey: " + s);
     return QualityProfileKey.of(split[0], split[1]);
   }
 
@@ -97,7 +96,7 @@ public class QualityProfileKey implements Serializable{
   }
 
   /**
-   * Format is "qProfile:lang", for example "Java:javascript"
+   * Format is "profile:lang", for example "Java:javascript"
    */
   @Override
   public String toString() {
index 6b4a3148818ab5d37241e3371acfb82b831bcf86..b0296d502264a369145039c941734f2dc3076687 100644 (file)
@@ -103,15 +103,15 @@ public class ActiveRuleIndex extends BaseIndex<ActiveRule, ActiveRuleDto, Active
       .field("type", "object")
       .startObject("properties")
       .startObject("_id")
-      .field("type","string")
+      .field("type", "string")
       .endObject()
       .startObject(ActiveRuleNormalizer.ActiveRuleParamField.NAME.key())
-        .field("type", "string")
-        .endObject()
-        .startObject(ActiveRuleNormalizer.ActiveRuleParamField.VALUE.key())
-        .field("type", "string")
-        .endObject()
-        .endObject();
+      .field("type", "string")
+      .endObject()
+      .startObject(ActiveRuleNormalizer.ActiveRuleParamField.VALUE.key())
+      .field("type", "string")
+      .endObject()
+      .endObject();
     mapping.endObject();
 
     mapping.endObject().endObject();
@@ -123,20 +123,23 @@ public class ActiveRuleIndex extends BaseIndex<ActiveRule, ActiveRuleDto, Active
     return new ActiveRuleDoc(response.getSource());
   }
 
-  /** finder methods */
-  public List<ActiveRule> findByRule(RuleKey key){
+  /**
+   * finder methods
+   */
+  public List<ActiveRule> findByRule(RuleKey key) {
 
     SearchRequestBuilder request = getClient().prepareSearch(this.getIndexName())
       .setQuery(QueryBuilders
         .hasParentQuery(this.getParentType(),
           QueryBuilders.idsQuery(this.getParentType())
-          .addIds(key.toString())))
+            .addIds(key.toString())
+        ))
       .setRouting(key.toString());
 
     SearchResponse response = request.get();
 
     List<ActiveRule> activeRules = new ArrayList<ActiveRule>();
-    for(SearchHit hit:response.getHits()){
+    for (SearchHit hit : response.getHits()) {
       activeRules.add(new ActiveRuleDoc(hit.getSource()));
     }
 
@@ -147,7 +150,12 @@ public class ActiveRuleIndex extends BaseIndex<ActiveRule, ActiveRuleDto, Active
     return new RuleIndexDefinition().getIndexType();
   }
 
-  public ActiveRule getByRuleKeyAndProfileKey(RuleKey ruleKey, QualityProfileKey qualityProfileKey){
-    return null;
+  public ActiveRule getByRuleKeyAndProfileKey(RuleKey ruleKey, QualityProfileKey qualityProfileKey) {
+    return toDoc(getClient().prepareGet()
+      .setRouting(ruleKey.toString())
+      .setType(this.getIndexType())
+      .setIndex(this.getIndexName())
+      .setId(ActiveRuleKey.of(qualityProfileKey, ruleKey).toString())
+      .get());
   }
 }
index 977314c7915bc8b472f4c69693cdce40bcaafc53..220a985e0b6e8489c634a6d866b12a808506bad2 100644 (file)
@@ -24,6 +24,7 @@ import org.sonar.api.ServerComponent;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.core.permission.GlobalPermissions;
 import org.sonar.core.persistence.DbSession;
+import org.sonar.core.qualityprofile.db.QualityProfileKey;
 import org.sonar.core.rule.RuleDto;
 import org.sonar.server.db.DbClient;
 import org.sonar.server.qualityprofile.ActiveRule;
@@ -38,6 +39,7 @@ import org.sonar.server.user.UserSession;
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 import java.util.Date;
+import java.util.List;
 import java.util.Set;
 
 /**
@@ -65,15 +67,33 @@ public class RuleService implements ServerComponent {
   }
 
   public RuleResult search(RuleQuery query, QueryOptions options) {
-    // keep only supported fields and add the fields to always return
+
+    /** keep only supported fields and add the fields to always return */
     options.filterFieldsToReturn(RuleIndex.PUBLIC_FIELDS);
 
-    RuleResult result =  index.search(query, options);
-    for(Rule rule:result.getHits()){
-      for(ActiveRule activeRule:activeRuleIndex.findByRule(rule.key())){
-        result.getActiveRules().put(rule.key().toString(),activeRule);
+    RuleResult result = index.search(query, options);
+
+    /** Check for activation */
+    if (query.getActivation() != null && !query.getActivation().isEmpty()) {
+      if (query.getActivation().equalsIgnoreCase("true")) {
+        for (Rule rule : result.getHits()) {
+          if(query.getqProfileKey() == null){
+            throw new IllegalStateException("\"activation=true\" requires a profile key!");
+          }
+          QualityProfileKey qualityProfileKey =  QualityProfileKey.parse(query.getqProfileKey());
+          result.getActiveRules().put(rule.key().toString(),
+            activeRuleIndex.getByRuleKeyAndProfileKey(rule.key(),qualityProfileKey));
+        }
+      } else if (query.getActivation().equalsIgnoreCase("all")) {
+        for (Rule rule : result.getHits()) {
+          List<ActiveRule> activeRules = activeRuleIndex.findByRule(rule.key());
+          for (ActiveRule activeRule : activeRules) {
+            result.getActiveRules().put(rule.key().toString(), activeRule);
+          }
+        }
       }
     }
+
     return result;
   }
 
@@ -102,7 +122,8 @@ public class RuleService implements ServerComponent {
 
   /**
    * Extend rule description by adding a note.
-   * @param ruleKey the required key
+   *
+   * @param ruleKey      the required key
    * @param markdownNote markdown text. <code>null</code> to remove current note.
    */
   public void setNote(RuleKey ruleKey, @Nullable String markdownNote) {
index c8a31b78294819a5413d8ea31fa1d43a3d94889b..5210808909ca38d1395971a8437aa9d11f7a9e63 100644 (file)
@@ -190,6 +190,7 @@ public class RuleIndex extends BaseIndex<Rule, RuleDto, RuleKey> {
   protected SearchRequestBuilder buildRequest(RuleQuery query, QueryOptions options) {
     SearchRequestBuilder esSearch = getClient()
       .prepareSearch(this.getIndexName())
+      .setTypes(this.getIndexType())
       .setIndices(this.getIndexName());
 
     /* Integrate Facets */
index 0d3aac13d9d244b999263a772cead03791ac8b6b..5f8e189ee6402ce49d4c9ac089dc3bcdc46d9f22 100644 (file)
@@ -29,6 +29,8 @@ import java.util.Collection;
 
 public class RuleQuery {
 
+
+
   public static enum SortField {
     KEY(RuleNormalizer.RuleField.KEY),
     REPOSITORY(RuleNormalizer.RuleField.REPOSITORY),
@@ -74,6 +76,9 @@ public class RuleQuery {
   private Boolean hasDebtCharacteristic;
   private SortField sortField;
   private boolean ascendingSort = true;
+  private String activation;
+  private String qProfileKey;
+
 
   /**
    * @see org.sonar.server.rule2.RuleService#newRuleQuery()
@@ -81,6 +86,26 @@ public class RuleQuery {
   public RuleQuery() {
   }
 
+  @CheckForNull
+  public String getqProfileKey() {
+    return qProfileKey;
+  }
+
+  public RuleQuery setqProfileKey(String qProfileKey) {
+    this.qProfileKey = qProfileKey;
+    return this;
+  }
+
+  public RuleQuery setActivation(String activation) {
+    this.activation = activation;
+    return this;
+  }
+
+  @CheckForNull
+  public String getActivation(){
+    return this.activation;
+  }
+
   @CheckForNull
   public String getKey() {
     return key;
index 9374bfce3ba0ee6e3bfe8acd0b60426bdd9899a9..f69a612fab5dfb6d8f4fcb11a2f599d7bba4cb1a 100644 (file)
@@ -52,6 +52,8 @@ public class SearchAction implements RequestHandler {
 
   private static final String PARAM_TEXT_QUERY = "q";
   private static final String PARAM_REPOSITORIES = "repositories";
+  private static final String PARAM_ACTIVATION = "activation";
+  private static final String PARAM_QPROFILE = "qprofile";
   private static final String PARAM_SEVERITIES = "severities";
   private static final String PARAM_STATUSES = "statuses";
   private static final String PARAM_LANGUAGES = "languages";
@@ -163,12 +165,12 @@ public class SearchAction implements RequestHandler {
       .setExampleValue("security,java8");
 
     action
-      .createParam("qprofile")
+      .createParam(PARAM_QPROFILE)
       .setDescription("Key of Quality profile")
       .setExampleValue("java:Sonar way");
 
     action
-      .createParam("activation")
+      .createParam(PARAM_ACTIVATION)
       .setDescription("Used only if 'qprofile' is set")
       .setExampleValue("java:Sonar way")
       .setPossibleValues("false", "true", "all");
@@ -184,6 +186,8 @@ public class SearchAction implements RequestHandler {
     query.setLanguages(request.paramAsStrings(PARAM_LANGUAGES));
     query.setDebtCharacteristics(request.paramAsStrings(PARAM_DEBT_CHARACTERISTICS));
     query.setHasDebtCharacteristic(request.paramAsBoolean(PARAM_HAS_DEBT_CHARACTERISTIC));
+    query.setActivation(request.param(PARAM_ACTIVATION));
+    query.setqProfileKey(request.param(PARAM_QPROFILE));
 
     // TODO move to QueryOptions ?
     query.setSortField(RuleQuery.SortField.valueOfOrNull(request.param(PARAM_SORT)));
index 42f05f555b0a182dde2c74b46ed0216f2c53c2b6..ecc17fba96d297bb005b536c0e6118b407062301 100644 (file)
@@ -32,11 +32,18 @@ import org.sonar.check.Cardinality;
 import org.sonar.core.permission.GlobalPermissions;
 import org.sonar.core.persistence.DbSession;
 import org.sonar.core.persistence.MyBatis;
+import org.sonar.core.qualityprofile.db.ActiveRuleDto;
+import org.sonar.core.qualityprofile.db.QualityProfileDao;
+import org.sonar.core.qualityprofile.db.QualityProfileDto;
 import org.sonar.core.rule.RuleDto;
 import org.sonar.server.exceptions.ForbiddenException;
 import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.qualityprofile.persistence.ActiveRuleDao;
 import org.sonar.server.rule2.index.RuleIndex;
+import org.sonar.server.rule2.index.RuleQuery;
+import org.sonar.server.rule2.index.RuleResult;
 import org.sonar.server.rule2.persistence.RuleDao;
+import org.sonar.server.search.QueryOptions;
 import org.sonar.server.tester.ServerTester;
 import org.sonar.server.user.MockUserSession;
 
@@ -49,7 +56,8 @@ import static org.fest.assertions.Fail.fail;
 public class RuleServiceMediumTest {
 
   @ClassRule
-  public static ServerTester tester = new ServerTester();
+  public static ServerTester tester = new ServerTester()
+    .setProperty("sonar.es.http.port","9200");
 
   RuleDao dao = tester.get(RuleDao.class);
   RuleIndex index = tester.get(RuleIndex.class);
@@ -158,6 +166,62 @@ public class RuleServiceMediumTest {
 //    assertThat(rule.getNoteUpdatedAt()).isNull();
 //    assertThat(rule.getNoteUserLogin()).isNull();
 
+  }
+
+  @Test
+  public void test_search_activation_on_rules() throws InterruptedException {
+
+    // 1. Create in DB
+    QualityProfileDto qprofile1 = QualityProfileDto.createFor("profile1","java");
+    QualityProfileDto qprofile2 = QualityProfileDto.createFor("profile2","java");
+    tester.get(QualityProfileDao.class).insert(qprofile1, dbSession);
+    tester.get(QualityProfileDao.class).insert(qprofile2, dbSession);
+
+    RuleDto rule1 = newRuleDto(RuleKey.of("test", "rule1"));
+    RuleDto rule2 = newRuleDto(RuleKey.of("test", "rule2"));
+    tester.get(RuleDao.class).insert(rule1, dbSession);
+    tester.get(RuleDao.class).insert(rule2, dbSession);
+
+    ActiveRuleDto activeRule1 = ActiveRuleDto.createFor(qprofile1, rule1)
+      .setSeverity(Severity.BLOCKER);
+    ActiveRuleDto activeRule2 = ActiveRuleDto.createFor(qprofile1, rule2)
+      .setSeverity(Severity.BLOCKER);
+    ActiveRuleDto activeRule3 = ActiveRuleDto.createFor(qprofile2, rule2)
+      .setSeverity(Severity.BLOCKER);
+    tester.get(ActiveRuleDao.class).insert(activeRule1, dbSession);
+    tester.get(ActiveRuleDao.class).insert(activeRule2, dbSession);
+    tester.get(ActiveRuleDao.class).insert(activeRule3, dbSession);
+
+    dbSession.commit();
+    service.refresh();
+
+
+    // 2. test in DB
+    assertThat(tester.get(RuleDao.class).findAll(dbSession)).hasSize(2);
+    assertThat(tester.get(ActiveRuleDao.class).findByRule(rule1, dbSession)).hasSize(1);
+    assertThat(tester.get(ActiveRuleDao.class).findByRule(rule2, dbSession)).hasSize(2);
+
+
+    // 3. Test for ALL activations
+    RuleQuery query = new RuleQuery()
+      .setActivation("all");
+    RuleResult result = service.search(query, new QueryOptions());
+    assertThat(result.getActiveRules().values()).hasSize(3);
+
+    // 4. Test for NO active rules
+    query = new RuleQuery()
+      .setActivation("false");
+    result = service.search(query, new QueryOptions());
+    assertThat(result.getActiveRules().values()).hasSize(0);
+
+    // 4. Test for  active rules of QProfile
+    query = new RuleQuery()
+      .setActivation("true")
+      .setqProfileKey(qprofile1.getKey().toString());
+    result = service.search(query, new QueryOptions());
+    assertThat(result.getActiveRules().values()).hasSize(2);
+
+
   }
 
   private RuleDto newRuleDto(RuleKey ruleKey) {
index d456a9bd443d8354f71649ac4bf7a13ff45eda5a..7cb40dca15765f6aac1729775950ae75c609b6ec 100644 (file)
@@ -145,7 +145,7 @@ public class RulesWebServiceTest {
 
 
   @Test
-  public void search_active_rules() throws Exception {
+  public void search_all_active_rules() throws Exception {
     QualityProfileDto profile = newQualityProfile();
     tester.get(QualityProfileDao.class).insert(profile, session);
 
@@ -163,21 +163,78 @@ public class RulesWebServiceTest {
     MockUserSession.set();
     WsTester.TestRequest request = wsTester.newGetRequest("api/rules", "search");
     request.setParam("q","S001");
+    request.setParam("activation","all");
     WsTester.Result result = request.execute();
 
     result.assertJson(this.getClass(),"search_active_rules.json");
   }
 
   @Test
-  public void search_active_rules_params() throws Exception {
+  public void search_no_active_rules() throws Exception {
     QualityProfileDto profile = newQualityProfile();
     tester.get(QualityProfileDao.class).insert(profile, session);
 
     RuleDto rule = newRuleDto(RuleKey.of(profile.getLanguage(), "S001"));
-    ruleDao.insert(rule, session);
+    ruleDao.insert(rule,  session);
+
+    ActiveRuleDto activeRule = newActiveRule(profile, rule);
+    tester.get(ActiveRuleDao.class).insert(activeRule, session);
 
     session.commit();
 
+    tester.get(RuleService.class).refresh();
+
+
+    MockUserSession.set();
+    WsTester.TestRequest request = wsTester.newGetRequest("api/rules2", "search");
+    request.setParam("q","S001");
+    request.setParam("activation","false");
+    WsTester.Result result = request.execute();
+
+    result.assertJson(this.getClass(),"search_no_active_rules.json");
+  }
+
+  @Test
+  public void search_profile_active_rules() throws Exception {
+    QualityProfileDto profile = newQualityProfile().setName("p1");
+    tester.get(QualityProfileDao.class).insert(profile, session);
+
+    QualityProfileDto profile2 = newQualityProfile().setName("p2");
+    tester.get(QualityProfileDao.class).insert(profile2, session);
+
+    session.commit();
+
+    RuleDto rule = newRuleDto(RuleKey.of(profile.getLanguage(), "S001"));
+    ruleDao.insert(rule,  session);
+
+    ActiveRuleDto activeRule = newActiveRule(profile, rule);
+    tester.get(ActiveRuleDao.class).insert(activeRule, session);
+    ActiveRuleDto activeRule2 = newActiveRule(profile2, rule);
+    tester.get(ActiveRuleDao.class).insert(activeRule2, session);
+
+    session.commit();
+    tester.get(RuleService.class).refresh();
+
+
+    MockUserSession.set();
+    WsTester.TestRequest request = wsTester.newGetRequest("api/rules2", "search");
+    request.setParam("q","S001");
+    request.setParam("activation","true");
+    request.setParam("qprofile",profile2.getKey().toString());
+    WsTester.Result result = request.execute();
+
+    result.assertJson(this.getClass(),"search_profile_active_rules.json");
+  }
+
+  @Test
+  public void search_all_active_rules_params() throws Exception {
+    QualityProfileDto profile = newQualityProfile();
+    tester.get(QualityProfileDao.class).insert(profile, session);
+
+    RuleDto rule = newRuleDto(RuleKey.of(profile.getLanguage(), "S001"));
+    ruleDao.insert(rule, session);
+
+    session.commit();
 
     RuleParamDto param = RuleParamDto.createFor(rule)
       .setDefaultValue("some value")
@@ -210,8 +267,11 @@ public class RulesWebServiceTest {
     MockUserSession.set();
     WsTester.TestRequest request = wsTester.newGetRequest("api/rules", "search");
     request.setParam("q", "S001");
+    request.setParam("activation", "all");
+
     WsTester.Result result = request.execute();
 
+    System.out.println("result.outputAsString() = " + result.outputAsString());
     result.assertJson(this.getClass(),"search_active_rules_params.json");
   }
 
@@ -272,7 +332,7 @@ public class RulesWebServiceTest {
 
   private ActiveRuleDto  newActiveRule(QualityProfileDto profile, RuleDto rule) {
     return ActiveRuleDto.createFor(profile, rule)
-      .setInheritance("NONE")
+      .setInheritance("none")
       .setSeverity("BLOCKER");
   }
 }
diff --git a/sonar-server/src/test/resources/org/sonar/server/rule2/ws/RulesWebServiceTest/search_no_active_rules.json b/sonar-server/src/test/resources/org/sonar/server/rule2/ws/RulesWebServiceTest/search_no_active_rules.json
new file mode 100644 (file)
index 0000000..592701e
--- /dev/null
@@ -0,0 +1,20 @@
+{"total": 1, "p": 1, "ps": 25, "rules": [
+    {
+        "key": "java:S001",
+        "repo": "java",
+        "lang": "js",
+        "name": "Rule S001",
+        "htmlDesc": "Description S001",
+        "status": "READY",
+        "template": false,
+        "internalKey": "InternalKeyS001",
+        "severity": "INFO",
+        "tags": [],
+        "sysTags": [],
+        "debtRemediationFunctionType": "LINEAR",
+        "debtRemediationFunctionCoefficient": "1h",
+        "debtRemediationFunctionOffset": "5min",
+        "params": [],
+        "actives": []
+    }
+]}
diff --git a/sonar-server/src/test/resources/org/sonar/server/rule2/ws/RulesWebServiceTest/search_profile_active_rules.json b/sonar-server/src/test/resources/org/sonar/server/rule2/ws/RulesWebServiceTest/search_profile_active_rules.json
new file mode 100644 (file)
index 0000000..ee43cf7
--- /dev/null
@@ -0,0 +1,32 @@
+{
+    "p": 1,
+    "ps": 25,
+    "rules": [
+        {
+            "actives": [
+                {
+                    "inherit": "NONE",
+                    "key": "p2:java:java:S001",
+                    "params": [],
+                    "severity": "BLOCKER"
+                }
+            ],
+            "debtRemediationFunctionCoefficient": "1h",
+            "debtRemediationFunctionOffset": "5min",
+            "debtRemediationFunctionType": "LINEAR",
+            "htmlDesc": "Description S001",
+            "internalKey": "InternalKeyS001",
+            "key": "java:S001",
+            "lang": "js",
+            "name": "Rule S001",
+            "params": [],
+            "repo": "java",
+            "severity": "INFO",
+            "status": "READY",
+            "sysTags": [],
+            "tags": [],
+            "template": false
+        }
+    ],
+    "total": 1
+}