]> source.dussan.org Git - sonarqube.git/commitdiff
Added searchability/filter by Tag for RuleIndex & service
authorStephane Gamard <stephane.gamard@searchbox.com>
Fri, 9 May 2014 14:03:52 +0000 (16:03 +0200)
committerStephane Gamard <stephane.gamard@searchbox.com>
Fri, 9 May 2014 14:10:31 +0000 (16:10 +0200)
sonar-core/src/main/java/org/sonar/core/rule/RuleDto.java
sonar-server/src/main/java/org/sonar/server/rule2/RuleDoc.java
sonar-server/src/main/java/org/sonar/server/rule2/RuleIndex.java
sonar-server/src/main/java/org/sonar/server/search/BaseIndex.java
sonar-server/src/test/java/org/sonar/server/rule2/RuleIndexMediumTest.java
sonar-server/src/test/java/org/sonar/server/rule2/RuleServiceMediumTest.java

index c547ac27d3da96553503ff6bfaff8972ffcd645a..532f04d484eabfa205486c57299d714da2aab9ea 100644 (file)
@@ -33,7 +33,8 @@ import javax.annotation.Nullable;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Date;
-import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
 
 public final class RuleDto implements Dto<RuleKey> {
 
@@ -313,16 +314,16 @@ public final class RuleDto implements Dto<RuleKey> {
     return this;
   }
 
-  public List<String> getTags() {
+  public Set<String> getTags() {
     return tags == null ?
-      Collections.EMPTY_LIST :
-      Arrays.asList(StringUtils.split(tags, ','));
+      Collections.EMPTY_SET :
+      new TreeSet<String>(Arrays.asList(StringUtils.split(tags, ',')));
   }
 
-  public List<String> getSystemTags() {
+  public Set<String> getSystemTags() {
     return systemTags == null ?
-      Collections.EMPTY_LIST :
-      Arrays.asList(StringUtils.split(systemTags, ','));
+      Collections.EMPTY_SET :
+      new TreeSet<String>(Arrays.asList(StringUtils.split(systemTags, ',')));
   }
 
   private String getTagsField() {
@@ -341,12 +342,12 @@ public final class RuleDto implements Dto<RuleKey> {
     systemTags = s;
   }
 
-  public RuleDto setTags(String[] tags) {
+  public RuleDto setTags(Set<String> tags) {
     this.tags = StringUtils.join(tags, ',');
     return this;
   }
 
-  public RuleDto setSystemTags(String[] tags) {
+  public RuleDto setSystemTags(Set<String> tags) {
     this.systemTags = StringUtils.join(tags, ',');
     return this;
   }
index 96d0648759b3ff3c6a5e120eb255c57196849c08..86eebe406796bc5028602a9445fa9bf25d354051 100644 (file)
@@ -19,6 +19,7 @@
  */
 package org.sonar.server.rule2;
 
+import org.apache.commons.lang.builder.ReflectionToStringBuilder;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.rule.RuleStatus;
 import org.sonar.api.server.debt.DebtRemediationFunction;
@@ -189,4 +190,9 @@ class RuleDoc implements Rule {
       throw new IllegalStateException("Cannot parse date", e);
     }
   }
+
+  @Override
+  public String toString() {
+    return ReflectionToStringBuilder.toString(this);
+  }
 }
index e263df3ee546e4262bc8e758fb5e8100dca202e1..de064ba5ceb959be21d165bff96888a359753c25 100644 (file)
@@ -258,11 +258,13 @@ public class RuleIndex extends BaseIndex<Rule, RuleQuery, RuleDto, RuleKey> {
   @Override
   protected FilterBuilder getFilter(RuleQuery query, QueryOptions options) {
     BoolFilterBuilder fb = FilterBuilders.boolFilter();
-    boolean hasFilter = false;
     this.addTermFilter(RuleField.LANGUAGE.key(), query.getLanguages(), fb);
     this.addTermFilter(RuleField.REPOSITORY.key(), query.getRepositories(), fb);
     this.addTermFilter(RuleField.SEVERITY.key(), query.getSeverities(), fb);
     this.addTermFilter(RuleField.KEY.key(), query.getKey(), fb);
+
+    this.addMultiFieldTermFilter(query.getTags(), fb, RuleField.TAGS.key(), RuleField.SYSTEM_TAGS.key());
+
     if(query.getStatuses() != null && !query.getStatuses().isEmpty()) {
       Collection<String> stringStatus = new ArrayList<String>();
       for (RuleStatus status : query.getStatuses()) {
@@ -274,6 +276,7 @@ public class RuleIndex extends BaseIndex<Rule, RuleQuery, RuleDto, RuleKey> {
     if((query.getLanguages() != null && !query.getLanguages().isEmpty()) ||
       (query.getRepositories() != null && !query.getRepositories().isEmpty()) ||
       (query.getSeverities() != null && !query.getSeverities().isEmpty()) ||
+      (query.getTags() != null && !query.getTags().isEmpty()) ||
       (query.getStatuses() != null && !query.getStatuses().isEmpty()) ||
       (query.getKey() != null && !query.getKey().isEmpty())) {
       return fb;
index c178ae57bcc434ee2cad3eb703b3acb0ac03777d..5c3b3be03dc8e6a4a5a665fff04f3f2e17e86ccf 100644 (file)
@@ -42,6 +42,7 @@ import org.sonar.server.es.ESNode;
 
 import java.io.IOException;
 import java.io.Serializable;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
@@ -158,7 +159,7 @@ public abstract class BaseIndex<R, Q, E extends Dto<K>, K extends Serializable>
 
     Result<R> result = new Result<R>(esResult);
 
-    if(esResult != null){
+    if (esResult != null) {
       result
         .setTotal((int) esResult.getHits().totalHits())
         .setTime(esResult.getTookInMillis());
@@ -175,10 +176,10 @@ public abstract class BaseIndex<R, Q, E extends Dto<K>, K extends Serializable>
 
   protected abstract R getSearchResult(Map<String, Object> fields);
 
-  protected R getSearchResult(SearchHit hit){
+  protected R getSearchResult(SearchHit hit) {
     Map<String, Object> fields = new HashMap<String, Object>();
-    for (Map.Entry<String, SearchHitField> field:hit.getFields().entrySet()){
-      fields.put(field.getKey(),field.getValue().getValue());
+    for (Map.Entry<String, SearchHitField> field : hit.getFields().entrySet()) {
+      fields.put(field.getKey(), field.getValue().getValue());
     }
     return this.getSearchResult(fields);
   }
@@ -340,6 +341,24 @@ public abstract class BaseIndex<R, Q, E extends Dto<K>, K extends Serializable>
 
   /* ES QueryHelper Methods */
 
+
+  protected BoolFilterBuilder addMultiFieldTermFilter(Collection<String> values, BoolFilterBuilder filter, String... fields) {
+    if (values != null && !values.isEmpty()) {
+      BoolFilterBuilder valuesFilter = FilterBuilders.boolFilter();
+      for (String value : values) {
+        Collection<FilterBuilder> filterBuilders = new ArrayList<FilterBuilder>();
+        for(String field:fields) {
+          filterBuilders.add(FilterBuilders.termFilter(field, value));
+        }
+        valuesFilter.should(FilterBuilders.orFilter(filterBuilders.toArray(new FilterBuilder[filterBuilders.size()])));
+      }
+      filter.must(valuesFilter);
+    }
+    return filter;
+  }
+
+
+
   protected BoolFilterBuilder addTermFilter(String field, Collection<String> values, BoolFilterBuilder filter) {
     if (values != null && !values.isEmpty()) {
       BoolFilterBuilder valuesFilter = FilterBuilders.boolFilter();
index 5ee5f2686160494661764bb10656a9e19607113a..b61f9ae8e7ceb1160ec74f9fbc5ec6c51c241cf7 100644 (file)
@@ -19,6 +19,7 @@
  */
 package org.sonar.server.rule2;
 
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import org.junit.After;
 import org.junit.Before;
@@ -32,7 +33,6 @@ import org.sonar.check.Cardinality;
 import org.sonar.core.persistence.DbSession;
 import org.sonar.core.persistence.MyBatis;
 import org.sonar.core.rule.RuleDto;
-import org.sonar.server.search.Hit;
 import org.sonar.server.search.QueryOptions;
 import org.sonar.server.search.Result;
 import org.sonar.server.tester.ServerTester;
@@ -319,6 +319,48 @@ public class RuleIndexMediumTest {
     assertThat(Iterables.getFirst(results.getHits(), null).key().rule()).isEqualTo("S002");
     assertThat(Iterables.getLast(results.getHits(), null).key().rule()).isEqualTo("S001");
   }
+  @Test
+  public void search_by_tag() {
+    dao.insert(newRuleDto(RuleKey.of("java", "S001")).setTags(ImmutableSet.of("tag1")), dbSession);
+    dao.insert(newRuleDto(RuleKey.of("java", "S002")).setTags(ImmutableSet.of("tag2")), dbSession);
+    dbSession.commit();
+    index.refresh();
+
+    // find all
+    RuleQuery query = new RuleQuery();
+    assertThat(index.search(query, new QueryOptions()).getHits()).hasSize(2);
+
+    // tag1 in query
+    query = new RuleQuery().setQueryText("tag1");
+    assertThat(index.search(query, new QueryOptions()).getHits()).hasSize(1);
+    assertThat(Iterables.getFirst(index.search(query, new QueryOptions()).getHits(),null).tags()).containsExactly("tag1");
+
+    // tag1 and tag2 in query
+    query = new RuleQuery().setQueryText("tag1 tag2");
+    assertThat(index.search(query, new QueryOptions()).getHits()).hasSize(2);
+
+    // tag2 in filter
+    query = new RuleQuery().setTags(ImmutableSet.of("tag2"));
+    assertThat(index.search(query, new QueryOptions()).getHits()).hasSize(1);
+    assertThat(Iterables.getFirst(index.search(query, new QueryOptions()).getHits(),null).tags()).containsExactly("tag2");
+
+    // tag2 in filter and tag1 tag2 in query
+    query = new RuleQuery().setTags(ImmutableSet.of("tag2")).setQueryText("tag1");
+    assertThat(index.search(query, new QueryOptions()).getHits()).hasSize(0);
+
+    // tag2 in filter and tag1 in query
+    query = new RuleQuery().setTags(ImmutableSet.of("tag2")).setQueryText("tag1 tag2");
+    assertThat(index.search(query, new QueryOptions()).getHits()).hasSize(1);
+    assertThat(Iterables.getFirst(index.search(query, new QueryOptions()).getHits(),null).tags()).containsExactly("tag2");
+
+    // null list => no filter
+    query = new RuleQuery().setTags(Collections.<String>emptySet());
+    assertThat(index.search(query, new QueryOptions()).getHits()).hasSize(2);
+
+    // null list => no filter
+    query = new RuleQuery().setTags(null);
+    assertThat(index.search(query, new QueryOptions()).getHits()).hasSize(2);
+  }
 
   @Test
   public void paging() {
index aabdc24308e108bc9caf4e01311512061a871b70..60a607955ba4e74323fcb092f0e5194fb34f2ed7 100644 (file)
@@ -19,6 +19,7 @@
  */
 package org.sonar.server.rule2;
 
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import org.junit.After;
 import org.junit.Before;
@@ -153,6 +154,8 @@ public class RuleServiceMediumTest {
       .setSeverity(Severity.INFO)
       .setCardinality(Cardinality.SINGLE)
       .setLanguage("js")
+      .setTags(ImmutableSet.of("tag1", "tag2"))
+      .setSystemTags(ImmutableSet.of("systag1", "systag2"))
       .setRemediationFunction("linear")
       .setDefaultRemediationFunction("linear_offset")
       .setRemediationCoefficient("1h")
@@ -160,8 +163,6 @@ public class RuleServiceMediumTest {
       .setRemediationOffset("5min")
       .setDefaultRemediationOffset("10h")
       .setEffortToFixDescription(ruleKey.repository() + "." + ruleKey.rule() + ".effortToFix")
-      .setTags(new String[]{"tag1", "tag2"})
-      .setSystemTags(new String[]{"systag1", "systag2"})
       .setCreatedAt(DateUtils.parseDate("2013-12-16"))
       .setUpdatedAt(DateUtils.parseDate("2013-12-17"));
   }