]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-7330 Remove old Index used by daov2
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Fri, 26 Feb 2016 14:05:34 +0000 (15:05 +0100)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Mon, 29 Feb 2016 12:26:54 +0000 (13:26 +0100)
28 files changed:
server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel1.java
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileLoader.java
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivator.java
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/index/ActiveRuleIndex.java
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/index/ActiveRuleIndex2.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/InheritanceAction.java
server/sonar-server/src/main/java/org/sonar/server/rule/RuleService.java
server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleIndex.java
server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleIndex2.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/rule/ws/SearchAction.java
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileCopierMediumTest.java
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileFactoryMediumTest.java
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileResetMediumTest.java
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RegisterQualityProfilesMediumTest.java
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RuleActivatorMediumTest.java
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/index/ActiveRuleIndex2Test.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/index/ActiveRuleIndexTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ChangeParentActionMediumTest.java
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ExportActionTest.java
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/QProfilesWsMediumTest.java
server/sonar-server/src/test/java/org/sonar/server/rule/RegisterRulesMediumTest.java
server/sonar-server/src/test/java/org/sonar/server/rule/RegisterRulesTest.java
server/sonar-server/src/test/java/org/sonar/server/rule/RuleCreatorMediumTest.java
server/sonar-server/src/test/java/org/sonar/server/rule/RuleDeleterMediumTest.java
server/sonar-server/src/test/java/org/sonar/server/rule/RuleServiceMediumTest.java
server/sonar-server/src/test/java/org/sonar/server/rule/RuleUpdaterMediumTest.java
server/sonar-server/src/test/java/org/sonar/server/rule/index/RuleIndex2Test.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/rule/index/RuleIndexTest.java [new file with mode: 0644]

index b80f273298525f395b2024eaac8ee5b3ed11aacc..7f19739bc102c670f617cf29a31afb8ef9ff143c 100644 (file)
@@ -42,10 +42,10 @@ import org.sonar.server.platform.Platform;
 import org.sonar.server.platform.ServerImpl;
 import org.sonar.server.platform.ServerSettings;
 import org.sonar.server.platform.TempFolderProvider;
-import org.sonar.server.qualityprofile.index.ActiveRuleIndex2;
+import org.sonar.server.qualityprofile.index.ActiveRuleIndex;
 import org.sonar.server.qualityprofile.index.ActiveRuleNormalizer;
 import org.sonar.server.ruby.PlatformRackBridge;
-import org.sonar.server.rule.index.RuleIndex2;
+import org.sonar.server.rule.index.RuleIndex;
 import org.sonar.server.rule.index.RuleNormalizer;
 import org.sonar.server.search.EsSearchModule;
 import org.sonar.server.search.IndexQueue;
@@ -102,8 +102,8 @@ public class PlatformLevel1 extends PlatformLevel {
       EsSearchModule.class,
 
       // rules/qprofiles
-      RuleIndex2.class,
-      ActiveRuleIndex2.class,
+      RuleIndex.class,
+      ActiveRuleIndex.class,
       RuleNormalizer.class,
       ActiveRuleNormalizer.class,
 
index 36343f1410c32e87b6cc985956beb7f92ce4928b..1e23d75a0f99914bef0153faac0c39d123edb4bd 100644 (file)
@@ -35,8 +35,8 @@ import org.sonar.db.qualityprofile.ActiveRuleKey;
 import org.sonar.db.qualityprofile.QualityProfileDto;
 import org.sonar.server.es.SearchOptions;
 import org.sonar.server.qualityprofile.index.ActiveRuleDoc;
-import org.sonar.server.qualityprofile.index.ActiveRuleIndex2;
-import org.sonar.server.rule.index.RuleIndex2;
+import org.sonar.server.qualityprofile.index.ActiveRuleIndex;
+import org.sonar.server.rule.index.RuleIndex;
 import org.sonar.server.rule.index.RuleQuery;
 import org.sonar.server.search.FacetValue;
 
@@ -44,10 +44,10 @@ import org.sonar.server.search.FacetValue;
 public class QProfileLoader {
 
   private final DbClient dbClient;
-  private final ActiveRuleIndex2 activeRuleIndex;
-  private final RuleIndex2 ruleIndex;
+  private final ActiveRuleIndex activeRuleIndex;
+  private final RuleIndex ruleIndex;
 
-  public QProfileLoader(DbClient dbClient, ActiveRuleIndex2 activeRuleIndex, RuleIndex2 ruleIndex) {
+  public QProfileLoader(DbClient dbClient, ActiveRuleIndex activeRuleIndex, RuleIndex ruleIndex) {
     this.dbClient = dbClient;
     this.activeRuleIndex = activeRuleIndex;
     this.ruleIndex = ruleIndex;
index f73164f415eea44914c14fba2d3c5905f6d1483b..a278611705fb337135ed573c6d9f2cf9b1479e26 100644 (file)
@@ -44,7 +44,7 @@ import org.sonar.db.rule.RuleParamDto;
 import org.sonar.server.activity.ActivityService;
 import org.sonar.server.exceptions.BadRequestException;
 import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
-import org.sonar.server.rule.index.RuleIndex2;
+import org.sonar.server.rule.index.RuleIndex;
 import org.sonar.server.rule.index.RuleQuery;
 import org.sonar.server.util.TypeValidations;
 
@@ -60,11 +60,11 @@ public class RuleActivator {
   private final DbClient db;
   private final TypeValidations typeValidations;
   private final RuleActivatorContextFactory contextFactory;
-  private final RuleIndex2 ruleIndex;
+  private final RuleIndex ruleIndex;
   private final ActiveRuleIndexer activeRuleIndexer;
   private final ActivityService activityService;
 
-  public RuleActivator(System2 system2, DbClient db, RuleIndex2 ruleIndex,
+  public RuleActivator(System2 system2, DbClient db, RuleIndex ruleIndex,
     RuleActivatorContextFactory contextFactory, TypeValidations typeValidations,
     ActiveRuleIndexer activeRuleIndexer, ActivityService activityService) {
     this.system2 = system2;
index 1601f33f1eaba4600ae67895f5d82d8c7c55753c..9e7964ae2989387b4c8aef2c558b2948c250d150 100644 (file)
  */
 package org.sonar.server.qualityprofile.index;
 
+import com.google.common.base.Function;
+import com.google.common.collect.ArrayListMultimap;
 import com.google.common.collect.Multimap;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import org.elasticsearch.action.get.GetRequestBuilder;
+import org.elasticsearch.action.get.GetResponse;
 import org.elasticsearch.action.search.SearchRequestBuilder;
 import org.elasticsearch.action.search.SearchResponse;
 import org.elasticsearch.action.search.SearchType;
 import org.elasticsearch.common.unit.TimeValue;
+import org.elasticsearch.index.query.FilterBuilder;
 import org.elasticsearch.index.query.FilterBuilders;
 import org.elasticsearch.index.query.QueryBuilders;
 import org.elasticsearch.search.SearchHit;
 import org.elasticsearch.search.aggregations.Aggregation;
 import org.elasticsearch.search.aggregations.AggregationBuilders;
+import org.elasticsearch.search.aggregations.Aggregations;
+import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
 import org.elasticsearch.search.aggregations.bucket.terms.Terms;
+import org.elasticsearch.search.aggregations.metrics.valuecount.InternalValueCount;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.rule.RuleStatus;
-import org.sonar.db.qualityprofile.ActiveRuleDto;
 import org.sonar.db.qualityprofile.ActiveRuleKey;
+import org.sonar.server.es.BaseIndex;
+import org.sonar.server.es.EsClient;
 import org.sonar.server.qualityprofile.ActiveRule;
 import org.sonar.server.rule.index.RuleIndexDefinition;
-import org.sonar.server.search.BaseIndex;
 import org.sonar.server.search.FacetValue;
-import org.sonar.server.search.IndexDefinition;
-import org.sonar.server.search.IndexField;
-import org.sonar.server.search.SearchClient;
 
-@Deprecated
-public class ActiveRuleIndex extends BaseIndex<ActiveRule, ActiveRuleDto, ActiveRuleKey> {
+import static org.sonar.server.es.EsUtils.SCROLL_TIME_IN_MINUTES;
+import static org.sonar.server.es.EsUtils.scroll;
+import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_INHERITANCE;
+import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_PROFILE_KEY;
+import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_SEVERITY;
+import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_RULE_STATUS;
+import static org.sonar.server.rule.index.RuleIndexDefinition.INDEX;
+import static org.sonar.server.rule.index.RuleIndexDefinition.TYPE_ACTIVE_RULE;
+import static org.sonar.server.rule.index.RuleIndexDefinition.TYPE_RULE;
+
+/**
+ * The unique entry-point to interact with Elasticsearch index "active rules".
+ * All the requests are listed here.
+ */
+public class ActiveRuleIndex extends BaseIndex {
 
   public static final String COUNT_ACTIVE_RULES = "countActiveRules";
 
-  public ActiveRuleIndex(ActiveRuleNormalizer normalizer, SearchClient node) {
-    super(IndexDefinition.ACTIVE_RULE, normalizer, node);
-  }
-
-  @Override
-  protected String getKeyValue(ActiveRuleKey key) {
-    return key.toString();
-  }
-
-  @Override
-  protected Map mapKey() {
-    Map<String, Object> mapping = new HashMap<>();
-    mapping.put("path", ActiveRuleNormalizer.ActiveRuleField.KEY.field());
-    return mapping;
+  public ActiveRuleIndex(EsClient client) {
+    super(client);
   }
 
-  @Override
-  protected Map mapProperties() {
-    Map<String, Object> mapping = new HashMap<>();
-    for (IndexField field : ActiveRuleNormalizer.ActiveRuleField.ALL_FIELDS) {
-      mapping.put(field.field(), mapField(field));
+  /**
+   * @deprecated since 5.5, use {@link org.sonar.db.qualityprofile.ActiveRuleDao instead}
+   */
+  @Deprecated
+  @CheckForNull
+  public ActiveRule getNullableByKey(ActiveRuleKey key) {
+    GetRequestBuilder request = getClient().prepareGet()
+      .setIndex(RuleIndexDefinition.INDEX)
+      .setType(RuleIndexDefinition.TYPE_ACTIVE_RULE)
+      .setId(key.toString())
+      .setFetchSource(true)
+      .setRouting(key.ruleKey().repository());
+
+    GetResponse response = request.get();
+    if (response.isExists()) {
+      return new ActiveRuleDoc(response.getSource());
     }
-    return mapping;
-  }
-
-  @Override
-  protected Map mapDomain() {
-    Map<String, Object> mapping = new HashMap<>();
-    mapping.put("dynamic", false);
-    mapping.put("_id", mapKey());
-    mapping.put("_parent", mapParent());
-    mapping.put("_routing", mapRouting());
-    mapping.put("properties", mapProperties());
-    return mapping;
-  }
-
-  private Map mapRouting() {
-    Map<String, Object> mapping = new HashMap<>();
-    mapping.put("required", true);
-    mapping.put("path", ActiveRuleNormalizer.ActiveRuleField.RULE_KEY.field());
-    return mapping;
-  }
-
-  private Object mapParent() {
-    Map<String, Object> mapping = new HashMap<>();
-    mapping.put("type", this.getParentType());
-    return mapping;
-  }
-
-  @Override
-  public ActiveRule toDoc(Map<String, Object> fields) {
-    return new ActiveRuleDoc(fields);
+    return null;
   }
 
   /**
-   * finder methods
+   * @deprecated since 5.5, use {@link org.sonar.db.qualityprofile.ActiveRuleDao instead}
    */
+  @Deprecated
   public List<ActiveRule> findByRule(RuleKey key) {
-    SearchRequestBuilder request = getClient().prepareSearch(this.getIndexName())
+    SearchRequestBuilder request = getClient().prepareSearch(RuleIndexDefinition.INDEX)
       .setQuery(QueryBuilders
-        .hasParentQuery(this.getParentType(),
-          QueryBuilders.idsQuery(this.getParentType())
+        .hasParentQuery(RuleIndexDefinition.TYPE_RULE,
+          QueryBuilders.idsQuery(RuleIndexDefinition.TYPE_RULE)
             .addIds(key.toString())
         ))
-      .setRouting(key.toString())
-      // TODO replace by scrolling
+      .setRouting(key.repository())
       .setSize(Integer.MAX_VALUE);
 
     SearchResponse response = request.get();
 
     List<ActiveRule> activeRules = new ArrayList<>();
     for (SearchHit hit : response.getHits()) {
-      activeRules.add(toDoc(hit.getSource()));
+      activeRules.add(new ActiveRuleDoc(hit.getSource()));
     }
     return activeRules;
   }
 
-  public Iterator<ActiveRule> findByProfile(String key) {
-    SearchRequestBuilder request = getClient().prepareSearch(getIndexName())
-      .setTypes(IndexDefinition.ACTIVE_RULE.getIndexType())
+  /**
+   * @deprecated since 5.5, use {@link org.sonar.db.qualityprofile.ActiveRuleDao instead}
+   */
+  @Deprecated
+  public Iterator<ActiveRuleDoc> findByProfile(String key) {
+    SearchRequestBuilder request = getClient().prepareSearch(RuleIndexDefinition.INDEX)
+      .setTypes(RuleIndexDefinition.TYPE_ACTIVE_RULE)
       .setSearchType(SearchType.SCAN)
       .setScroll(TimeValue.timeValueMinutes(SCROLL_TIME_IN_MINUTES))
       .setSize(100)
       .setQuery(QueryBuilders.filteredQuery(QueryBuilders.matchAllQuery(), FilterBuilders.boolFilter()
-        .must(FilterBuilders.termFilter(ActiveRuleNormalizer.ActiveRuleField.PROFILE_KEY.field(), key))
-        .mustNot(FilterBuilders.hasParentFilter(this.getParentType(),
-          FilterBuilders.termFilter(RuleIndexDefinition.FIELD_RULE_STATUS, RuleStatus.REMOVED.name())))))
-      .setRouting(key);
+        .must(FilterBuilders.termFilter(RuleIndexDefinition.FIELD_ACTIVE_RULE_PROFILE_KEY, key))
+        .mustNot(FilterBuilders.hasParentFilter(RuleIndexDefinition.TYPE_RULE,
+          FilterBuilders.termFilter(RuleIndexDefinition.FIELD_RULE_STATUS, RuleStatus.REMOVED.name())))));
 
     SearchResponse response = request.get();
-    return scroll(response.getScrollId());
+    return scroll(getClient(), response.getScrollId(), ToDoc.INSTANCE);
   }
 
-  private String getParentType() {
-    return IndexDefinition.RULE.getIndexType();
-  }
-
-  public Long countByQualityProfileKey(String key) {
-    return countByField(ActiveRuleNormalizer.ActiveRuleField.PROFILE_KEY,
-      FilterBuilders.hasParentFilter(IndexDefinition.RULE.getIndexType(),
+  public Map<String, Long> countAllByQualityProfileKey() {
+    return countByField(FIELD_ACTIVE_RULE_PROFILE_KEY,
+      FilterBuilders.hasParentFilter(TYPE_RULE,
         FilterBuilders.notFilter(
-          FilterBuilders.termFilter(RuleIndexDefinition.FIELD_RULE_STATUS, "REMOVED")))).get(key);
+          FilterBuilders.termFilter(FIELD_RULE_STATUS, "REMOVED"))));
   }
 
-  public Map<String, Long> countAllByQualityProfileKey() {
-    return countByField(ActiveRuleNormalizer.ActiveRuleField.PROFILE_KEY,
-      FilterBuilders.hasParentFilter(IndexDefinition.RULE.getIndexType(),
-        FilterBuilders.notFilter(
-          FilterBuilders.termFilter(RuleIndexDefinition.FIELD_RULE_STATUS, "REMOVED"))));
+  private Map<String, Long> countByField(String indexField, FilterBuilder filter) {
+    Map<String, Long> counts = new HashMap<>();
+
+    SearchRequestBuilder request = getClient().prepareSearch(INDEX)
+      .setTypes(TYPE_ACTIVE_RULE)
+      .setQuery(QueryBuilders.filteredQuery(
+        QueryBuilders.matchAllQuery(),
+        filter))
+      .setSize(0)
+      .addAggregation(AggregationBuilders
+        .terms(indexField)
+        .field(indexField)
+        .order(Terms.Order.count(false))
+        .size(Integer.MAX_VALUE)
+        .minDocCount(0));
+
+    SearchResponse response = request.get();
+
+    Terms values =
+      response.getAggregations().get(indexField);
+
+    for (Terms.Bucket value : values.getBuckets()) {
+      counts.put(value.getKey(), value.getDocCount());
+    }
+    return counts;
   }
 
   public Map<String, Multimap<String, FacetValue>> getStatsByProfileKeys(List<String> keys) {
-    SearchRequestBuilder request = getClient().prepareSearch(this.getIndexName())
+    SearchRequestBuilder request = getClient().prepareSearch(INDEX)
       .setQuery(QueryBuilders.filteredQuery(
-        QueryBuilders.termsQuery(ActiveRuleNormalizer.ActiveRuleField.PROFILE_KEY.field(), keys),
+        QueryBuilders.termsQuery(FIELD_ACTIVE_RULE_PROFILE_KEY, keys),
         FilterBuilders.boolFilter()
-          .mustNot(FilterBuilders.hasParentFilter(this.getParentType(),
-            FilterBuilders.termFilter(RuleIndexDefinition.FIELD_RULE_STATUS, RuleStatus.REMOVED.name())))))
-      .addAggregation(AggregationBuilders.terms(ActiveRuleNormalizer.ActiveRuleField.PROFILE_KEY.field())
-        .field(ActiveRuleNormalizer.ActiveRuleField.PROFILE_KEY.field()).size(0)
-        .subAggregation(AggregationBuilders.terms(ActiveRuleNormalizer.ActiveRuleField.INHERITANCE.field())
-          .field(ActiveRuleNormalizer.ActiveRuleField.INHERITANCE.field()))
-        .subAggregation(AggregationBuilders.terms(ActiveRuleNormalizer.ActiveRuleField.SEVERITY.field())
-          .field(ActiveRuleNormalizer.ActiveRuleField.SEVERITY.field()))
+          .mustNot(FilterBuilders.hasParentFilter(TYPE_RULE,
+            FilterBuilders.termFilter(FIELD_RULE_STATUS, RuleStatus.REMOVED.name())))))
+      .addAggregation(AggregationBuilders.terms(FIELD_ACTIVE_RULE_PROFILE_KEY)
+        .field(RuleIndexDefinition.FIELD_ACTIVE_RULE_PROFILE_KEY).size(0)
+        .subAggregation(AggregationBuilders.terms(FIELD_ACTIVE_RULE_INHERITANCE)
+          .field(RuleIndexDefinition.FIELD_ACTIVE_RULE_INHERITANCE))
+        .subAggregation(AggregationBuilders.terms(FIELD_ACTIVE_RULE_SEVERITY)
+          .field(RuleIndexDefinition.FIELD_ACTIVE_RULE_SEVERITY))
         .subAggregation(AggregationBuilders.count(COUNT_ACTIVE_RULES)))
       .setSize(0)
-      .setTypes(this.getIndexType());
+      .setTypes(TYPE_ACTIVE_RULE);
     SearchResponse response = request.get();
     Map<String, Multimap<String, FacetValue>> stats = new HashMap<>();
-    Aggregation aggregation = response.getAggregations().get(ActiveRuleNormalizer.ActiveRuleField.PROFILE_KEY.field());
+    Aggregation aggregation = response.getAggregations().get(FIELD_ACTIVE_RULE_PROFILE_KEY);
     for (Terms.Bucket value : ((Terms) aggregation).getBuckets()) {
-      stats.put(value.getKey()
-        , this.processAggregations(value.getAggregations()));
+      stats.put(value.getKey(), processAggregations(value.getAggregations()));
     }
 
     return stats;
   }
+
+  private Multimap<String, FacetValue> processAggregations(Aggregations aggregations) {
+    Multimap<String, FacetValue> stats = ArrayListMultimap.create();
+    if (aggregations != null) {
+      for (Aggregation aggregation : aggregations.asList()) {
+        if (aggregation instanceof StringTerms) {
+          for (Terms.Bucket value : ((Terms) aggregation).getBuckets()) {
+            FacetValue facetValue = new FacetValue(value.getKey(), value.getDocCount());
+            stats.put(aggregation.getName(), facetValue);
+          }
+        } else if (aggregation instanceof InternalValueCount) {
+          InternalValueCount count = (InternalValueCount) aggregation;
+          FacetValue facetValue = new FacetValue(count.getName(), count.getValue());
+          stats.put(count.getName(), facetValue);
+        }
+      }
+    }
+    return stats;
+  }
+
+  private enum ToDoc implements Function<Map<String, Object>, ActiveRuleDoc> {
+    INSTANCE;
+
+    @Override
+    public ActiveRuleDoc apply(@Nonnull Map<String, Object> input) {
+      return new ActiveRuleDoc(input);
+    }
+  }
+
 }
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/index/ActiveRuleIndex2.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/index/ActiveRuleIndex2.java
deleted file mode 100644 (file)
index 01dcaaf..0000000
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program 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.
- *
- * This program 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.index;
-
-import com.google.common.base.Function;
-import com.google.common.collect.ArrayListMultimap;
-import com.google.common.collect.Multimap;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nonnull;
-import org.elasticsearch.action.get.GetRequestBuilder;
-import org.elasticsearch.action.get.GetResponse;
-import org.elasticsearch.action.search.SearchRequestBuilder;
-import org.elasticsearch.action.search.SearchResponse;
-import org.elasticsearch.action.search.SearchType;
-import org.elasticsearch.common.unit.TimeValue;
-import org.elasticsearch.index.query.FilterBuilder;
-import org.elasticsearch.index.query.FilterBuilders;
-import org.elasticsearch.index.query.QueryBuilders;
-import org.elasticsearch.search.SearchHit;
-import org.elasticsearch.search.aggregations.Aggregation;
-import org.elasticsearch.search.aggregations.AggregationBuilders;
-import org.elasticsearch.search.aggregations.Aggregations;
-import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
-import org.elasticsearch.search.aggregations.bucket.terms.Terms;
-import org.elasticsearch.search.aggregations.metrics.valuecount.InternalValueCount;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rule.RuleStatus;
-import org.sonar.db.qualityprofile.ActiveRuleKey;
-import org.sonar.server.es.BaseIndex;
-import org.sonar.server.es.EsClient;
-import org.sonar.server.qualityprofile.ActiveRule;
-import org.sonar.server.rule.index.RuleIndexDefinition;
-import org.sonar.server.search.FacetValue;
-
-import static org.sonar.server.es.EsUtils.SCROLL_TIME_IN_MINUTES;
-import static org.sonar.server.es.EsUtils.scroll;
-import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_INHERITANCE;
-import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_PROFILE_KEY;
-import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_SEVERITY;
-import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_RULE_STATUS;
-import static org.sonar.server.rule.index.RuleIndexDefinition.INDEX;
-import static org.sonar.server.rule.index.RuleIndexDefinition.TYPE_ACTIVE_RULE;
-import static org.sonar.server.rule.index.RuleIndexDefinition.TYPE_RULE;
-
-/**
- * The unique entry-point to interact with Elasticsearch index "active rules".
- * All the requests are listed here.
- */
-public class ActiveRuleIndex2 extends BaseIndex {
-
-  public static final String COUNT_ACTIVE_RULES = "countActiveRules";
-
-  public ActiveRuleIndex2(EsClient client) {
-    super(client);
-  }
-
-  /**
-   * @deprecated since 5.5, use {@link org.sonar.db.qualityprofile.ActiveRuleDao instead}
-   */
-  @Deprecated
-  @CheckForNull
-  public ActiveRule getNullableByKey(ActiveRuleKey key) {
-    GetRequestBuilder request = getClient().prepareGet()
-      .setIndex(RuleIndexDefinition.INDEX)
-      .setType(RuleIndexDefinition.TYPE_ACTIVE_RULE)
-      .setId(key.toString())
-      .setFetchSource(true)
-      .setRouting(key.ruleKey().repository());
-
-    GetResponse response = request.get();
-    if (response.isExists()) {
-      return new ActiveRuleDoc(response.getSource());
-    }
-    return null;
-  }
-
-  /**
-   * @deprecated since 5.5, use {@link org.sonar.db.qualityprofile.ActiveRuleDao instead}
-   */
-  @Deprecated
-  public List<ActiveRule> findByRule(RuleKey key) {
-    SearchRequestBuilder request = getClient().prepareSearch(RuleIndexDefinition.INDEX)
-      .setQuery(QueryBuilders
-        .hasParentQuery(RuleIndexDefinition.TYPE_RULE,
-          QueryBuilders.idsQuery(RuleIndexDefinition.TYPE_RULE)
-            .addIds(key.toString())
-        ))
-      .setRouting(key.repository())
-      .setSize(Integer.MAX_VALUE);
-
-    SearchResponse response = request.get();
-
-    List<ActiveRule> activeRules = new ArrayList<>();
-    for (SearchHit hit : response.getHits()) {
-      activeRules.add(new ActiveRuleDoc(hit.getSource()));
-    }
-    return activeRules;
-  }
-
-  /**
-   * @deprecated since 5.5, use {@link org.sonar.db.qualityprofile.ActiveRuleDao instead}
-   */
-  @Deprecated
-  public Iterator<ActiveRuleDoc> findByProfile(String key) {
-    SearchRequestBuilder request = getClient().prepareSearch(RuleIndexDefinition.INDEX)
-      .setTypes(RuleIndexDefinition.TYPE_ACTIVE_RULE)
-      .setSearchType(SearchType.SCAN)
-      .setScroll(TimeValue.timeValueMinutes(SCROLL_TIME_IN_MINUTES))
-      .setSize(100)
-      .setQuery(QueryBuilders.filteredQuery(QueryBuilders.matchAllQuery(), FilterBuilders.boolFilter()
-        .must(FilterBuilders.termFilter(RuleIndexDefinition.FIELD_ACTIVE_RULE_PROFILE_KEY, key))
-        .mustNot(FilterBuilders.hasParentFilter(RuleIndexDefinition.TYPE_RULE,
-          FilterBuilders.termFilter(RuleIndexDefinition.FIELD_RULE_STATUS, RuleStatus.REMOVED.name())))));
-
-    SearchResponse response = request.get();
-    return scroll(getClient(), response.getScrollId(), ToDoc.INSTANCE);
-  }
-
-  public Map<String, Long> countAllByQualityProfileKey() {
-    return countByField(FIELD_ACTIVE_RULE_PROFILE_KEY,
-      FilterBuilders.hasParentFilter(TYPE_RULE,
-        FilterBuilders.notFilter(
-          FilterBuilders.termFilter(FIELD_RULE_STATUS, "REMOVED"))));
-  }
-
-  private Map<String, Long> countByField(String indexField, FilterBuilder filter) {
-    Map<String, Long> counts = new HashMap<>();
-
-    SearchRequestBuilder request = getClient().prepareSearch(INDEX)
-      .setTypes(TYPE_ACTIVE_RULE)
-      .setQuery(QueryBuilders.filteredQuery(
-        QueryBuilders.matchAllQuery(),
-        filter))
-      .setSize(0)
-      .addAggregation(AggregationBuilders
-        .terms(indexField)
-        .field(indexField)
-        .order(Terms.Order.count(false))
-        .size(Integer.MAX_VALUE)
-        .minDocCount(0));
-
-    SearchResponse response = request.get();
-
-    Terms values =
-      response.getAggregations().get(indexField);
-
-    for (Terms.Bucket value : values.getBuckets()) {
-      counts.put(value.getKey(), value.getDocCount());
-    }
-    return counts;
-  }
-
-  public Map<String, Multimap<String, FacetValue>> getStatsByProfileKeys(List<String> keys) {
-    SearchRequestBuilder request = getClient().prepareSearch(INDEX)
-      .setQuery(QueryBuilders.filteredQuery(
-        QueryBuilders.termsQuery(FIELD_ACTIVE_RULE_PROFILE_KEY, keys),
-        FilterBuilders.boolFilter()
-          .mustNot(FilterBuilders.hasParentFilter(TYPE_RULE,
-            FilterBuilders.termFilter(FIELD_RULE_STATUS, RuleStatus.REMOVED.name())))))
-      .addAggregation(AggregationBuilders.terms(FIELD_ACTIVE_RULE_PROFILE_KEY)
-        .field(RuleIndexDefinition.FIELD_ACTIVE_RULE_PROFILE_KEY).size(0)
-        .subAggregation(AggregationBuilders.terms(FIELD_ACTIVE_RULE_INHERITANCE)
-          .field(RuleIndexDefinition.FIELD_ACTIVE_RULE_INHERITANCE))
-        .subAggregation(AggregationBuilders.terms(FIELD_ACTIVE_RULE_SEVERITY)
-          .field(RuleIndexDefinition.FIELD_ACTIVE_RULE_SEVERITY))
-        .subAggregation(AggregationBuilders.count(COUNT_ACTIVE_RULES)))
-      .setSize(0)
-      .setTypes(TYPE_ACTIVE_RULE);
-    SearchResponse response = request.get();
-    Map<String, Multimap<String, FacetValue>> stats = new HashMap<>();
-    Aggregation aggregation = response.getAggregations().get(FIELD_ACTIVE_RULE_PROFILE_KEY);
-    for (Terms.Bucket value : ((Terms) aggregation).getBuckets()) {
-      stats.put(value.getKey(), processAggregations(value.getAggregations()));
-    }
-
-    return stats;
-  }
-
-  private Multimap<String, FacetValue> processAggregations(Aggregations aggregations) {
-    Multimap<String, FacetValue> stats = ArrayListMultimap.create();
-    if (aggregations != null) {
-      for (Aggregation aggregation : aggregations.asList()) {
-        if (aggregation instanceof StringTerms) {
-          for (Terms.Bucket value : ((Terms) aggregation).getBuckets()) {
-            FacetValue facetValue = new FacetValue(value.getKey(), value.getDocCount());
-            stats.put(aggregation.getName(), facetValue);
-          }
-        } else if (aggregation instanceof InternalValueCount) {
-          InternalValueCount count = (InternalValueCount) aggregation;
-          FacetValue facetValue = new FacetValue(count.getName(), count.getValue());
-          stats.put(count.getName(), facetValue);
-        }
-      }
-    }
-    return stats;
-  }
-
-  private enum ToDoc implements Function<Map<String, Object>, ActiveRuleDoc> {
-    INSTANCE;
-
-    @Override
-    public ActiveRuleDoc apply(@Nonnull Map<String, Object> input) {
-      return new ActiveRuleDoc(input);
-    }
-  }
-
-}
index d2c171ae224f040ad6f4316adbbe8b934096f72e..a6e38d3a11355bda7e0f46544fd457d752cf95c9 100644 (file)
@@ -40,7 +40,7 @@ import org.sonar.server.qualityprofile.QProfileLookup;
 import org.sonar.server.rule.index.RuleIndexDefinition;
 import org.sonar.server.search.FacetValue;
 
-import static org.sonar.server.qualityprofile.index.ActiveRuleIndex2.COUNT_ACTIVE_RULES;
+import static org.sonar.server.qualityprofile.index.ActiveRuleIndex.COUNT_ACTIVE_RULES;
 
 public class InheritanceAction implements QProfileWsAction {
 
index a409042a7e91ed2f6c6e9c576618d17b79e34989..75b4989141fef88993a321bb277d573aea7b0658 100644 (file)
@@ -27,7 +27,7 @@ import javax.annotation.Nullable;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.server.ServerSide;
 import org.sonar.core.permission.GlobalPermissions;
-import org.sonar.server.rule.index.RuleIndex2;
+import org.sonar.server.rule.index.RuleIndex;
 import org.sonar.server.rule.index.RuleIndexDefinition;
 import org.sonar.server.rule.index.RuleQuery;
 import org.sonar.server.search.QueryContext;
@@ -40,13 +40,13 @@ import org.sonar.server.user.UserSession;
 @ServerSide
 public class RuleService {
 
-  private final RuleIndex2 index;
+  private final RuleIndex index;
   private final RuleUpdater ruleUpdater;
   private final RuleCreator ruleCreator;
   private final RuleDeleter ruleDeleter;
   private final UserSession userSession;
 
-  public RuleService(RuleIndex2 index, RuleUpdater ruleUpdater, RuleCreator ruleCreator, RuleDeleter ruleDeleter, UserSession userSession) {
+  public RuleService(RuleIndex index, RuleUpdater ruleUpdater, RuleCreator ruleCreator, RuleDeleter ruleDeleter, UserSession userSession) {
     this.index = index;
     this.ruleUpdater = ruleUpdater;
     this.ruleCreator = ruleCreator;
index cfb221bb0bf2b47df92b8d56bba4580794f2babf..1d182f0722e06426d61d9482a7737ffbf1b9b1f8 100644 (file)
@@ -21,7 +21,6 @@ package org.sonar.server.rule.index;
 
 import com.google.common.base.Function;
 import com.google.common.base.Joiner;
-import com.google.common.base.Preconditions;
 import com.google.common.base.Predicate;
 import com.google.common.collect.Collections2;
 import com.google.common.collect.ImmutableList;
@@ -30,16 +29,16 @@ import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang.StringUtils;
 import org.elasticsearch.action.search.SearchRequestBuilder;
 import org.elasticsearch.action.search.SearchResponse;
-import org.elasticsearch.action.search.SearchScrollRequestBuilder;
 import org.elasticsearch.action.search.SearchType;
 import org.elasticsearch.common.unit.TimeValue;
 import org.elasticsearch.index.query.BoolFilterBuilder;
@@ -51,7 +50,6 @@ import org.elasticsearch.index.query.MatchQueryBuilder;
 import org.elasticsearch.index.query.QueryBuilder;
 import org.elasticsearch.index.query.QueryBuilders;
 import org.elasticsearch.index.query.SimpleQueryStringBuilder;
-import org.elasticsearch.search.SearchHit;
 import org.elasticsearch.search.aggregations.AggregationBuilder;
 import org.elasticsearch.search.aggregations.AggregationBuilders;
 import org.elasticsearch.search.aggregations.bucket.terms.Terms;
@@ -62,21 +60,21 @@ import org.elasticsearch.search.sort.SortOrder;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.rule.RuleStatus;
 import org.sonar.api.rule.Severity;
-import org.sonar.db.rule.RuleDto;
-import org.sonar.server.qualityprofile.index.ActiveRuleNormalizer;
-import org.sonar.server.rule.Rule;
-import org.sonar.server.search.BaseIndex;
-import org.sonar.server.search.IndexDefinition;
+import org.sonar.server.es.BaseIndex;
+import org.sonar.server.es.EsClient;
+import org.sonar.server.es.SearchIdResult;
+import org.sonar.server.es.SearchOptions;
 import org.sonar.server.search.IndexField;
-import org.sonar.server.search.QueryContext;
-import org.sonar.server.search.Result;
-import org.sonar.server.search.SearchClient;
 import org.sonar.server.search.StickyFacetBuilder;
 
-import static com.google.common.collect.Lists.newArrayList;
+import static org.sonar.server.es.EsUtils.SCROLL_TIME_IN_MINUTES;
+import static org.sonar.server.es.EsUtils.scrollIds;
 
-@Deprecated
-public class RuleIndex extends BaseIndex<Rule, RuleDto, RuleKey> {
+/**
+ * The unique entry-point to interact with Elasticsearch index "rules".
+ * All the requests are listed here.
+ */
+public class RuleIndex extends BaseIndex {
 
   public static final String FACET_LANGUAGES = "languages";
   public static final String FACET_TAGS = "tags";
@@ -92,104 +90,73 @@ public class RuleIndex extends BaseIndex<Rule, RuleDto, RuleKey> {
         Arrays.asList(RuleStatus.values()),
         new Function<RuleStatus, String>() {
           @Override
-          public String apply(RuleStatus input) {
+          public String apply(@Nonnull RuleStatus input) {
             return input.toString();
           }
         }),
       new Predicate<String>() {
         @Override
-        public boolean apply(String input) {
+        public boolean apply(@Nonnull String input) {
           return !RuleStatus.REMOVED.toString().equals(input);
         }
       }));
 
-  public RuleIndex(RuleNormalizer normalizer, SearchClient client) {
-    super(IndexDefinition.RULE, normalizer, client);
+  public RuleIndex(EsClient client) {
+    super(client);
   }
 
-  @Override
-  protected String getKeyValue(RuleKey key) {
-    return key.toString();
-  }
+  public SearchIdResult<RuleKey> search(RuleQuery query, SearchOptions options) {
+    SearchRequestBuilder esSearch = getClient()
+      .prepareSearch(RuleIndexDefinition.INDEX)
+      .setTypes(RuleIndexDefinition.TYPE_RULE);
 
-  @Override
-  protected Map mapKey() {
-    Map<String, Object> mapping = new HashMap<>();
-    mapping.put("path", RuleNormalizer.RuleField.KEY.field());
-    return mapping;
-  }
+    QueryBuilder qb = buildQuery(query);
+    Map<String, FilterBuilder> filters = buildFilters(query);
 
-  @Override
-  protected Map mapProperties() {
-    Map<String, Object> mapping = new HashMap<>();
-    for (IndexField field : RuleNormalizer.RuleField.ALL_FIELDS) {
-      mapping.put(field.field(), mapField(field));
-    }
-    return mapping;
-  }
-
-  private void setFields(QueryContext options, SearchRequestBuilder esSearch) {
-    /* integrate Option's Fields */
-    Set<String> fields = new HashSet<>();
-    if (!options.getFieldsToReturn().isEmpty()) {
-      for (String fieldToReturn : options.getFieldsToReturn()) {
-        if (!fieldToReturn.isEmpty()) {
-          fields.add(fieldToReturn);
-        }
-      }
-      // required field
-      fields.add(RuleNormalizer.RuleField.KEY.field());
-    } else {
-      for (IndexField indexField : RuleNormalizer.RuleField.ALL_FIELDS) {
-        fields.add(indexField.field());
+    if (!options.getFacets().isEmpty()) {
+      for (AggregationBuilder aggregation : getFacets(query, options, qb, filters).values()) {
+        esSearch.addAggregation(aggregation);
       }
     }
 
-    esSearch.setFetchSource(fields.toArray(new String[fields.size()]), null);
-  }
+    setSorting(query, esSearch);
+    setPagination(options, esSearch);
 
-  private void setSorting(RuleQuery query, SearchRequestBuilder esSearch) {
-    /* integrate Query Sort */
-    String queryText = query.getQueryText();
-    if (query.getSortField() != null) {
-      FieldSortBuilder sort = SortBuilders.fieldSort(query.getSortField());
-      if (query.isAscendingSort()) {
-        sort.order(SortOrder.ASC);
-      } else {
-        sort.order(SortOrder.DESC);
-      }
-      esSearch.addSort(sort);
-    } else if (queryText != null && !queryText.isEmpty()) {
-      esSearch.addSort(SortBuilders.scoreSort());
-    } else {
-      esSearch.addSort(RuleNormalizer.RuleField.UPDATED_AT.sortField(), SortOrder.DESC);
-      // deterministic sort when exactly the same updated_at (same millisecond)
-      esSearch.addSort(RuleNormalizer.RuleField.KEY.sortField()
-        , SortOrder.ASC);
+    BoolFilterBuilder fb = FilterBuilders.boolFilter();
+    for (FilterBuilder filterBuilder : filters.values()) {
+      fb.must(filterBuilder);
     }
-  }
 
-  protected void setPagination(QueryContext options, SearchRequestBuilder esSearch) {
-    esSearch.setFrom(options.getOffset());
-    esSearch.setSize(options.getLimit());
+    esSearch.setQuery(QueryBuilders.filteredQuery(qb, fb));
+    return new SearchIdResult<>(esSearch.get(), ToRuleKey.INSTANCE);
   }
 
-  private QueryBuilder termQuery(IndexField field, String query, float boost) {
-    return QueryBuilders.multiMatchQuery(query,
-      field.field(), field.field() + "." + IndexField.SEARCH_PARTIAL_SUFFIX)
-      .operator(MatchQueryBuilder.Operator.AND)
-      .boost(boost);
-  }
+  /**
+   * Return all keys matching the search query, without pagination nor facets
+   */
+  public Iterator<RuleKey> searchAll(RuleQuery query) {
+    SearchRequestBuilder esSearch = getClient()
+      .prepareSearch(RuleIndexDefinition.INDEX)
+      .setTypes(RuleIndexDefinition.TYPE_RULE)
+      .setSearchType(SearchType.SCAN)
+      .setScroll(TimeValue.timeValueMinutes(SCROLL_TIME_IN_MINUTES));
 
-  private QueryBuilder termAnyQuery(IndexField field, String query, float boost) {
-    return QueryBuilders.multiMatchQuery(query,
-      field.field(), field.field() + "." + IndexField.SEARCH_PARTIAL_SUFFIX)
-      .operator(MatchQueryBuilder.Operator.OR)
-      .boost(boost);
+    QueryBuilder qb = buildQuery(query);
+    Map<String, FilterBuilder> filters = buildFilters(query);
+    setSorting(query, esSearch);
+
+    BoolFilterBuilder fb = FilterBuilders.boolFilter();
+    for (FilterBuilder filterBuilder : filters.values()) {
+      fb.must(filterBuilder);
+    }
+
+    esSearch.setQuery(QueryBuilders.filteredQuery(qb, fb));
+    SearchResponse response = esSearch.get();
+    return scrollIds(getClient(), response.getScrollId(), ToRuleKey.INSTANCE);
   }
 
   /* Build main query (search based) */
-  protected QueryBuilder getQuery(RuleQuery query) {
+  private QueryBuilder buildQuery(RuleQuery query) {
 
     // No contextual query case
     String queryText = query.getQueryText();
@@ -203,70 +170,84 @@ public class RuleIndex extends BaseIndex<Rule, RuleDto, RuleKey> {
 
     // Human readable type of querying
     qb.should(QueryBuilders.simpleQueryStringQuery(query.getQueryText())
-      .field(RuleNormalizer.RuleField.NAME.field() + "." + IndexField.SEARCH_WORDS_SUFFIX, 20f)
-      .field(RuleNormalizer.RuleField.HTML_DESCRIPTION.field() + "." + IndexField.SEARCH_WORDS_SUFFIX, 3f)
+      .field(RuleIndexDefinition.FIELD_RULE_NAME + "." + BaseIndex.SEARCH_WORDS_SUFFIX, 20f)
+      .field(RuleIndexDefinition.FIELD_RULE_HTML_DESCRIPTION + "." + BaseIndex.SEARCH_WORDS_SUFFIX, 3f)
       .defaultOperator(SimpleQueryStringBuilder.Operator.AND)
       ).boost(20f);
 
     // Match and partial Match queries
-    qb.should(this.termQuery(RuleNormalizer.RuleField.KEY, queryString, 15f));
-    qb.should(this.termQuery(RuleNormalizer.RuleField._KEY, queryString, 35f));
-    qb.should(this.termQuery(RuleNormalizer.RuleField.LANGUAGE, queryString, 3f));
-    qb.should(this.termQuery(RuleNormalizer.RuleField.ALL_TAGS, queryString, 10f));
-    qb.should(this.termAnyQuery(RuleNormalizer.RuleField.ALL_TAGS, queryString, 1f));
+    qb.should(this.termQuery(RuleIndexDefinition.FIELD_RULE_KEY, queryString, 15f));
+    qb.should(this.termQuery(RuleIndexDefinition.FIELD_RULE_KEY_AS_LIST, queryString, 35f));
+    qb.should(this.termQuery(RuleIndexDefinition.FIELD_RULE_LANGUAGE, queryString, 3f));
+    qb.should(this.termQuery(RuleIndexDefinition.FIELD_RULE_ALL_TAGS, queryString, 10f));
+    qb.should(this.termAnyQuery(RuleIndexDefinition.FIELD_RULE_ALL_TAGS, queryString, 1f));
 
     return qb;
   }
 
+  private QueryBuilder termQuery(String field, String query, float boost) {
+    return QueryBuilders.multiMatchQuery(query,
+      field, field + "." + IndexField.SEARCH_PARTIAL_SUFFIX)
+      .operator(MatchQueryBuilder.Operator.AND)
+      .boost(boost);
+  }
+
+  private QueryBuilder termAnyQuery(String field, String query, float boost) {
+    return QueryBuilders.multiMatchQuery(query,
+      field, field + "." + IndexField.SEARCH_PARTIAL_SUFFIX)
+      .operator(MatchQueryBuilder.Operator.OR)
+      .boost(boost);
+  }
+
   /* Build main filter (match based) */
-  protected Map<String, FilterBuilder> getFilters(RuleQuery query, QueryContext options) {
+  private Map<String, FilterBuilder> buildFilters(RuleQuery query) {
 
     Map<String, FilterBuilder> filters = new HashMap<>();
 
     /* Add enforced filter on rules that are REMOVED */
-    filters.put(RuleNormalizer.RuleField.STATUS.field(),
+    filters.put(RuleIndexDefinition.FIELD_RULE_STATUS,
       FilterBuilders.boolFilter().mustNot(
-        FilterBuilders.termFilter(RuleNormalizer.RuleField.STATUS.field(),
+        FilterBuilders.termFilter(RuleIndexDefinition.FIELD_RULE_STATUS,
           RuleStatus.REMOVED.toString())));
 
     if (!StringUtils.isEmpty(query.getInternalKey())) {
-      filters.put(RuleNormalizer.RuleField.INTERNAL_KEY.field(),
-        FilterBuilders.termFilter(RuleNormalizer.RuleField.INTERNAL_KEY.field(), query.getInternalKey()));
+      filters.put(RuleIndexDefinition.FIELD_RULE_INTERNAL_KEY,
+        FilterBuilders.termFilter(RuleIndexDefinition.FIELD_RULE_INTERNAL_KEY, query.getInternalKey()));
     }
 
     if (!StringUtils.isEmpty(query.getRuleKey())) {
-      filters.put(RuleNormalizer.RuleField.RULE_KEY.field(),
-        FilterBuilders.termFilter(RuleNormalizer.RuleField.RULE_KEY.field(), query.getRuleKey()));
+      filters.put(RuleIndexDefinition.FIELD_RULE_RULE_KEY,
+        FilterBuilders.termFilter(RuleIndexDefinition.FIELD_RULE_RULE_KEY, query.getRuleKey()));
     }
 
     if (!CollectionUtils.isEmpty(query.getLanguages())) {
-      filters.put(RuleNormalizer.RuleField.LANGUAGE.field(),
-        FilterBuilders.termsFilter(RuleNormalizer.RuleField.LANGUAGE.field(), query.getLanguages()));
+      filters.put(RuleIndexDefinition.FIELD_RULE_LANGUAGE,
+        FilterBuilders.termsFilter(RuleIndexDefinition.FIELD_RULE_LANGUAGE, query.getLanguages()));
     }
 
     if (!CollectionUtils.isEmpty(query.getRepositories())) {
-      filters.put(RuleNormalizer.RuleField.REPOSITORY.field(),
-        FilterBuilders.termsFilter(RuleNormalizer.RuleField.REPOSITORY.field(), query.getRepositories()));
+      filters.put(RuleIndexDefinition.FIELD_RULE_REPOSITORY,
+        FilterBuilders.termsFilter(RuleIndexDefinition.FIELD_RULE_REPOSITORY, query.getRepositories()));
     }
 
     if (!CollectionUtils.isEmpty(query.getSeverities())) {
-      filters.put(RuleNormalizer.RuleField.SEVERITY.field(),
-        FilterBuilders.termsFilter(RuleNormalizer.RuleField.SEVERITY.field(), query.getSeverities()));
+      filters.put(RuleIndexDefinition.FIELD_RULE_SEVERITY,
+        FilterBuilders.termsFilter(RuleIndexDefinition.FIELD_RULE_SEVERITY, query.getSeverities()));
     }
 
     if (!StringUtils.isEmpty(query.getKey())) {
-      filters.put(RuleNormalizer.RuleField.KEY.field(),
-        FilterBuilders.termFilter(RuleNormalizer.RuleField.KEY.field(), query.getKey()));
+      filters.put(RuleIndexDefinition.FIELD_RULE_KEY,
+        FilterBuilders.termFilter(RuleIndexDefinition.FIELD_RULE_KEY, query.getKey()));
     }
 
     if (!CollectionUtils.isEmpty(query.getTags())) {
-      filters.put(RuleNormalizer.RuleField.ALL_TAGS.field(),
-        FilterBuilders.termsFilter(RuleNormalizer.RuleField.ALL_TAGS.field(), query.getTags()));
+      filters.put(RuleIndexDefinition.FIELD_RULE_ALL_TAGS,
+        FilterBuilders.termsFilter(RuleIndexDefinition.FIELD_RULE_ALL_TAGS, query.getTags()));
     }
 
-    if (query.getAvailableSince() != null) {
-      filters.put("availableSince", FilterBuilders.rangeFilter(RuleNormalizer.RuleField.CREATED_AT.field())
-        .gte(query.getAvailableSince()));
+    if (query.getAvailableSinceLong() != null) {
+      filters.put("availableSince", FilterBuilders.rangeFilter(RuleIndexDefinition.FIELD_RULE_CREATED_AT)
+        .gte(query.getAvailableSinceLong()));
     }
 
     Collection<RuleStatus> statusValues = query.getStatuses();
@@ -275,27 +256,27 @@ public class RuleIndex extends BaseIndex<Rule, RuleDto, RuleKey> {
       for (RuleStatus status : statusValues) {
         stringStatus.add(status.name());
       }
-      filters.put(RuleNormalizer.RuleField.STATUS.field(),
-        FilterBuilders.termsFilter(RuleNormalizer.RuleField.STATUS.field(), stringStatus));
+      filters.put(RuleIndexDefinition.FIELD_RULE_STATUS,
+        FilterBuilders.termsFilter(RuleIndexDefinition.FIELD_RULE_STATUS, stringStatus));
     }
 
     Boolean isTemplate = query.isTemplate();
     if (isTemplate != null) {
-      filters.put(RuleNormalizer.RuleField.IS_TEMPLATE.field(),
-        FilterBuilders.termFilter(RuleNormalizer.RuleField.IS_TEMPLATE.field(), Boolean.toString(isTemplate)));
+      filters.put(RuleIndexDefinition.FIELD_RULE_IS_TEMPLATE,
+        FilterBuilders.termFilter(RuleIndexDefinition.FIELD_RULE_IS_TEMPLATE, Boolean.toString(isTemplate)));
     }
 
     String template = query.templateKey();
     if (template != null) {
-      filters.put(RuleNormalizer.RuleField.TEMPLATE_KEY.field(),
-        FilterBuilders.termFilter(RuleNormalizer.RuleField.TEMPLATE_KEY.field(), template));
+      filters.put(RuleIndexDefinition.FIELD_RULE_TEMPLATE_KEY,
+        FilterBuilders.termFilter(RuleIndexDefinition.FIELD_RULE_TEMPLATE_KEY, template));
     }
 
     // ActiveRule Filter (profile and inheritance)
     BoolFilterBuilder childrenFilter = FilterBuilders.boolFilter();
-    this.addTermFilter(childrenFilter, ActiveRuleNormalizer.ActiveRuleField.PROFILE_KEY.field(), query.getQProfileKey());
-    this.addTermFilter(childrenFilter, ActiveRuleNormalizer.ActiveRuleField.INHERITANCE.field(), query.getInheritance());
-    this.addTermFilter(childrenFilter, ActiveRuleNormalizer.ActiveRuleField.SEVERITY.field(), query.getActiveSeverities());
+    addTermFilter(childrenFilter, RuleIndexDefinition.FIELD_ACTIVE_RULE_PROFILE_KEY, query.getQProfileKey());
+    addTermFilter(childrenFilter, RuleIndexDefinition.FIELD_ACTIVE_RULE_INHERITANCE, query.getInheritance());
+    addTermFilter(childrenFilter, RuleIndexDefinition.FIELD_ACTIVE_RULE_SEVERITY, query.getActiveSeverities());
 
     // ChildQuery
     FilterBuilder childQuery;
@@ -308,45 +289,84 @@ public class RuleIndex extends BaseIndex<Rule, RuleDto, RuleKey> {
     /** Implementation of activation query */
     if (Boolean.TRUE.equals(query.getActivation())) {
       filters.put("activation",
-        FilterBuilders.hasChildFilter(IndexDefinition.ACTIVE_RULE.getIndexType(),
+        FilterBuilders.hasChildFilter(RuleIndexDefinition.TYPE_ACTIVE_RULE,
           childQuery));
     } else if (Boolean.FALSE.equals(query.getActivation())) {
       filters.put("activation",
         FilterBuilders.boolFilter().mustNot(
-          FilterBuilders.hasChildFilter(IndexDefinition.ACTIVE_RULE.getIndexType(),
+          FilterBuilders.hasChildFilter(RuleIndexDefinition.TYPE_ACTIVE_RULE,
             childQuery)));
     }
 
     return filters;
   }
 
-  protected Map<String, AggregationBuilder> getFacets(RuleQuery query, QueryContext options, QueryBuilder queryBuilder, Map<String, FilterBuilder> filters) {
+  private BoolFilterBuilder addTermFilter(BoolFilterBuilder filter, String field, @Nullable Collection<String> values) {
+    if (values != null && !values.isEmpty()) {
+      BoolFilterBuilder valuesFilter = FilterBuilders.boolFilter();
+      for (String value : values) {
+        FilterBuilder valueFilter = FilterBuilders.termFilter(field, value);
+        valuesFilter.should(valueFilter);
+      }
+      filter.must(valuesFilter);
+    }
+    return filter;
+  }
+
+  private BoolFilterBuilder addTermFilter(BoolFilterBuilder filter, String field, @Nullable String value) {
+    if (value != null && !value.isEmpty()) {
+      filter.must(FilterBuilders.termFilter(field, value));
+    }
+    return filter;
+  }
+
+  private Map<String, AggregationBuilder> getFacets(RuleQuery query, SearchOptions options, QueryBuilder queryBuilder, Map<String, FilterBuilder> filters) {
     Map<String, AggregationBuilder> aggregations = new HashMap<>();
     StickyFacetBuilder stickyFacetBuilder = stickyFacetBuilder(queryBuilder, filters);
 
-    addDefaultFacets(query, options, queryBuilder, filters, aggregations, stickyFacetBuilder);
+    addDefaultFacets(query, options, aggregations, stickyFacetBuilder);
 
     addStatusFacetIfNeeded(options, aggregations, stickyFacetBuilder);
 
-    if (options.facets().contains(FACET_SEVERITIES)) {
+    if (options.getFacets().contains(FACET_SEVERITIES)) {
       aggregations.put(FACET_SEVERITIES,
-        stickyFacetBuilder.buildStickyFacet(RuleNormalizer.RuleField.SEVERITY.field(), FACET_SEVERITIES, Severity.ALL.toArray()));
+        stickyFacetBuilder.buildStickyFacet(RuleIndexDefinition.FIELD_RULE_SEVERITY, FACET_SEVERITIES, Severity.ALL.toArray()));
     }
 
     addActiveSeverityFacetIfNeeded(query, options, aggregations, stickyFacetBuilder);
     return aggregations;
+  }
 
+  private void addDefaultFacets(RuleQuery query, SearchOptions options, Map<String, AggregationBuilder> aggregations, StickyFacetBuilder stickyFacetBuilder) {
+    if (options.getFacets().contains(FACET_LANGUAGES) || options.getFacets().contains(FACET_OLD_DEFAULT)) {
+      Collection<String> languages = query.getLanguages();
+      aggregations.put(FACET_LANGUAGES,
+        stickyFacetBuilder.buildStickyFacet(RuleIndexDefinition.FIELD_RULE_LANGUAGE, FACET_LANGUAGES,
+          languages == null ? new String[0] : languages.toArray()));
+    }
+    if (options.getFacets().contains(FACET_TAGS) || options.getFacets().contains(FACET_OLD_DEFAULT)) {
+      Collection<String> tags = query.getTags();
+      aggregations.put(FACET_TAGS,
+        stickyFacetBuilder.buildStickyFacet(RuleIndexDefinition.FIELD_RULE_ALL_TAGS, FACET_TAGS,
+          tags == null ? new String[0] : tags.toArray()));
+    }
+    if (options.getFacets().contains("repositories") || options.getFacets().contains(FACET_OLD_DEFAULT)) {
+      Collection<String> repositories = query.getRepositories();
+      aggregations.put(FACET_REPOSITORIES,
+        stickyFacetBuilder.buildStickyFacet(RuleIndexDefinition.FIELD_RULE_REPOSITORY, FACET_REPOSITORIES,
+          repositories == null ? new String[0] : repositories.toArray()));
+    }
   }
 
-  private void addStatusFacetIfNeeded(QueryContext options, Map<String, AggregationBuilder> aggregations, StickyFacetBuilder stickyFacetBuilder) {
-    if (options.facets().contains(FACET_STATUSES)) {
-      BoolFilterBuilder facetFilter = stickyFacetBuilder.getStickyFacetFilter(RuleNormalizer.RuleField.STATUS.field());
+  private void addStatusFacetIfNeeded(SearchOptions options, Map<String, AggregationBuilder> aggregations, StickyFacetBuilder stickyFacetBuilder) {
+    if (options.getFacets().contains(FACET_STATUSES)) {
+      BoolFilterBuilder facetFilter = stickyFacetBuilder.getStickyFacetFilter(RuleIndexDefinition.FIELD_RULE_STATUS);
       AggregationBuilder statuses = AggregationBuilders.filter(FACET_STATUSES + "_filter")
         .filter(facetFilter)
         .subAggregation(
           AggregationBuilders
             .terms(FACET_STATUSES)
-            .field(RuleNormalizer.RuleField.STATUS.field())
+            .field(RuleIndexDefinition.FIELD_RULE_STATUS)
             .include(Joiner.on('|').join(ALL_STATUSES_EXCEPT_REMOVED))
             .exclude(RuleStatus.REMOVED.toString())
             .size(ALL_STATUSES_EXCEPT_REMOVED.size()));
@@ -355,19 +375,19 @@ public class RuleIndex extends BaseIndex<Rule, RuleDto, RuleKey> {
     }
   }
 
-  private void addActiveSeverityFacetIfNeeded(RuleQuery query, QueryContext options, Map<String, AggregationBuilder> aggregations, StickyFacetBuilder stickyFacetBuilder) {
-    if (options.facets().contains(FACET_ACTIVE_SEVERITIES)) {
+  private void addActiveSeverityFacetIfNeeded(RuleQuery query, SearchOptions options, Map<String, AggregationBuilder> aggregations, StickyFacetBuilder stickyFacetBuilder) {
+    if (options.getFacets().contains(FACET_ACTIVE_SEVERITIES)) {
       // We are building a children aggregation on active rules
       // so the rule filter has to be used as parent filter for active rules
       // from which we remove filters that concern active rules ("activation")
       HasParentFilterBuilder ruleFilter = FilterBuilders.hasParentFilter(
-        IndexDefinition.RULE.getIndexType(),
+        RuleIndexDefinition.TYPE_RULE,
         stickyFacetBuilder.getStickyFacetFilter("activation"));
 
       // Rebuilding the active rule filter without severities
       BoolFilterBuilder childrenFilter = FilterBuilders.boolFilter();
-      this.addTermFilter(childrenFilter, ActiveRuleNormalizer.ActiveRuleField.PROFILE_KEY.field(), query.getQProfileKey());
-      this.addTermFilter(childrenFilter, ActiveRuleNormalizer.ActiveRuleField.INHERITANCE.field(), query.getInheritance());
+      this.addTermFilter(childrenFilter, RuleIndexDefinition.FIELD_ACTIVE_RULE_PROFILE_KEY, query.getQProfileKey());
+      this.addTermFilter(childrenFilter, RuleIndexDefinition.FIELD_ACTIVE_RULE_INHERITANCE, query.getInheritance());
       FilterBuilder activeRuleFilter;
       if (childrenFilter.hasClauses()) {
         activeRuleFilter = childrenFilter.must(ruleFilter);
@@ -376,13 +396,13 @@ public class RuleIndex extends BaseIndex<Rule, RuleDto, RuleKey> {
       }
 
       AggregationBuilder activeSeverities = AggregationBuilders.children(FACET_ACTIVE_SEVERITIES + "_children")
-        .childType(IndexDefinition.ACTIVE_RULE.getIndexType())
+        .childType(RuleIndexDefinition.TYPE_ACTIVE_RULE)
         .subAggregation(AggregationBuilders.filter(FACET_ACTIVE_SEVERITIES + "_filter")
           .filter(activeRuleFilter)
           .subAggregation(
             AggregationBuilders
               .terms(FACET_ACTIVE_SEVERITIES)
-              .field(ActiveRuleNormalizer.ActiveRuleField.SEVERITY.field())
+              .field(RuleIndexDefinition.FIELD_ACTIVE_RULE_SEVERITY)
               .include(Joiner.on('|').join(Severity.ALL))
               .size(Severity.ALL.size())));
 
@@ -390,66 +410,41 @@ public class RuleIndex extends BaseIndex<Rule, RuleDto, RuleKey> {
     }
   }
 
-  protected void addDefaultFacets(RuleQuery query, QueryContext options, QueryBuilder queryBuilder, Map<String, FilterBuilder> filters,
-    Map<String, AggregationBuilder> aggregations, StickyFacetBuilder stickyFacetBuilder) {
-    if (options.facets().contains(FACET_LANGUAGES) || options.facets().contains(FACET_OLD_DEFAULT)) {
-      Collection<String> languages = query.getLanguages();
-      aggregations.put(FACET_LANGUAGES,
-        stickyFacetBuilder.buildStickyFacet(RuleNormalizer.RuleField.LANGUAGE.field(), FACET_LANGUAGES,
-          languages == null ? new String[0] : languages.toArray()));
-    }
-    if (options.facets().contains(FACET_TAGS) || options.facets().contains(FACET_OLD_DEFAULT)) {
-      Collection<String> tags = query.getTags();
-      aggregations.put(FACET_TAGS,
-        stickyFacetBuilder.buildStickyFacet(RuleNormalizer.RuleField.ALL_TAGS.field(), FACET_TAGS,
-          tags == null ? new String[0] : tags.toArray()));
-    }
-    if (options.facets().contains("repositories") || options.facets().contains(FACET_OLD_DEFAULT)) {
-      Collection<String> repositories = query.getRepositories();
-      aggregations.put(FACET_REPOSITORIES,
-        stickyFacetBuilder.buildStickyFacet(RuleNormalizer.RuleField.REPOSITORY.field(), FACET_REPOSITORIES,
-          repositories == null ? new String[0] : repositories.toArray()));
-    }
+  private StickyFacetBuilder stickyFacetBuilder(QueryBuilder query, Map<String, FilterBuilder> filters) {
+    return new StickyFacetBuilder(query, filters);
   }
 
-  public Result<Rule> search(RuleQuery query, QueryContext options) {
-    SearchRequestBuilder esSearch = getClient()
-      .prepareSearch(this.getIndexName())
-      .setTypes(this.getIndexType())
-      .setIndices(this.getIndexName());
-
-    if (options.isScroll()) {
-      esSearch.setSearchType(SearchType.SCAN);
-      esSearch.setScroll(TimeValue.timeValueMinutes(3));
-    }
-
-    QueryBuilder qb = this.getQuery(query);
-    Map<String, FilterBuilder> filters = this.getFilters(query, options);
-
-    if (options.isFacet()) {
-      for (AggregationBuilder aggregation : getFacets(query, options, qb, filters).values()) {
-        esSearch.addAggregation(aggregation);
+  private void setSorting(RuleQuery query, SearchRequestBuilder esSearch) {
+    /* integrate Query Sort */
+    String queryText = query.getQueryText();
+    if (query.getSortField() != null) {
+      FieldSortBuilder sort = SortBuilders.fieldSort(appendSortSuffixIfNeeded(query.getSortField()));
+      if (query.isAscendingSort()) {
+        sort.order(SortOrder.ASC);
+      } else {
+        sort.order(SortOrder.DESC);
       }
+      esSearch.addSort(sort);
+    } else if (queryText != null && !queryText.isEmpty()) {
+      esSearch.addSort(SortBuilders.scoreSort());
+    } else {
+      esSearch.addSort(appendSortSuffixIfNeeded(RuleIndexDefinition.FIELD_RULE_UPDATED_AT), SortOrder.DESC);
+      // deterministic sort when exactly the same updated_at (same millisecond)
+      esSearch.addSort(appendSortSuffixIfNeeded(RuleIndexDefinition.FIELD_RULE_KEY), SortOrder.ASC);
     }
+  }
 
-    setSorting(query, esSearch);
-    setPagination(options, esSearch);
-    setFields(options, esSearch);
-
-    BoolFilterBuilder fb = FilterBuilders.boolFilter();
-    for (FilterBuilder ffb : filters.values()) {
-      fb.must(ffb);
-    }
-
-    esSearch.setQuery(QueryBuilders.filteredQuery(qb, fb));
-    SearchResponse esResult = esSearch.get();
-    return new Result<>(this, esResult);
+  public static String appendSortSuffixIfNeeded(String field) {
+      return field +
+        ((field.equals(RuleIndexDefinition.FIELD_RULE_NAME)
+        || field.equals(RuleIndexDefinition.FIELD_RULE_KEY))
+          ? "." + BaseIndex.SORT_SUFFIX
+          : "");
   }
 
-  @Override
-  protected Rule toDoc(Map<String, Object> fields) {
-    Preconditions.checkNotNull(fields, "Cannot construct Rule with null response");
-    return new RuleDoc(fields);
+  private void setPagination(SearchOptions options, SearchRequestBuilder esSearch) {
+    esSearch.setFrom(options.getOffset());
+    esSearch.setSize(options.getLimit());
   }
 
   public Set<String> terms(String fields) {
@@ -468,7 +463,7 @@ public class RuleIndex extends BaseIndex<Rule, RuleDto, RuleKey> {
       terms.include(".*" + query + ".*");
     }
     SearchRequestBuilder request = this.getClient()
-      .prepareSearch(this.getIndexName())
+      .prepareSearch(RuleIndexDefinition.INDEX)
       .setQuery(QueryBuilders.matchAllQuery())
       .addAggregation(terms);
 
@@ -484,55 +479,13 @@ public class RuleIndex extends BaseIndex<Rule, RuleDto, RuleKey> {
     return tags;
   }
 
-  /**
-   * @deprecated please use getByKey(RuleKey key)
-   */
-  @Deprecated
-  @CheckForNull
-  public Rule getById(int id) {
-    SearchRequestBuilder request = getClient().prepareSearch(this.getIndexName())
-      .setTypes(this.getIndexType())
-      .setQuery(QueryBuilders.termQuery(RuleNormalizer.RuleField.ID.field(), id))
-      .setSize(1);
-    SearchResponse response = request.get();
-
-    SearchHit hit = response.getHits().getAt(0);
-    if (hit == null) {
-      return null;
-    } else {
-      return toDoc(hit.getSource());
-    }
-  }
+  private enum ToRuleKey implements Function<String, RuleKey> {
+    INSTANCE;
 
-  /**
-   * @deprecated please use getByKey(RuleKey key)
-   */
-  @Deprecated
-  public List<Rule> getByIds(Collection<Integer> ids) {
-    SearchRequestBuilder request = getClient().prepareSearch(this.getIndexName())
-      .setTypes(this.getIndexType())
-      .setSearchType(SearchType.SCAN)
-      .setScroll(TimeValue.timeValueSeconds(3L))
-      .setSize(100)
-      .setQuery(QueryBuilders.termsQuery(RuleNormalizer.RuleField.ID.field(), ids));
-    SearchResponse scrollResp = request.get();
-
-    List<Rule> rules = newArrayList();
-    while (true) {
-      SearchScrollRequestBuilder scrollRequest = getClient()
-        .prepareSearchScroll(scrollResp.getScrollId())
-        .setScroll(TimeValue.timeValueSeconds(3L));
-
-      scrollResp = scrollRequest.get();
-
-      for (SearchHit hit : scrollResp.getHits()) {
-        rules.add(toDoc(hit.getSource()));
-      }
-      // Break condition: No hits are returned
-      if (scrollResp.getHits().getHits().length == 0) {
-        break;
-      }
+    @Override
+    public RuleKey apply(@Nonnull String input) {
+      return RuleKey.parse(input);
     }
-    return rules;
   }
+
 }
diff --git a/server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleIndex2.java b/server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleIndex2.java
deleted file mode 100644 (file)
index 498cbc4..0000000
+++ /dev/null
@@ -1,491 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program 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.
- *
- * This program 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.rule.index;
-
-import com.google.common.base.Function;
-import com.google.common.base.Joiner;
-import com.google.common.base.Predicate;
-import com.google.common.collect.Collections2;
-import com.google.common.collect.ImmutableList;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import org.apache.commons.collections.CollectionUtils;
-import org.apache.commons.lang.StringUtils;
-import org.elasticsearch.action.search.SearchRequestBuilder;
-import org.elasticsearch.action.search.SearchResponse;
-import org.elasticsearch.action.search.SearchType;
-import org.elasticsearch.common.unit.TimeValue;
-import org.elasticsearch.index.query.BoolFilterBuilder;
-import org.elasticsearch.index.query.BoolQueryBuilder;
-import org.elasticsearch.index.query.FilterBuilder;
-import org.elasticsearch.index.query.FilterBuilders;
-import org.elasticsearch.index.query.HasParentFilterBuilder;
-import org.elasticsearch.index.query.MatchQueryBuilder;
-import org.elasticsearch.index.query.QueryBuilder;
-import org.elasticsearch.index.query.QueryBuilders;
-import org.elasticsearch.index.query.SimpleQueryStringBuilder;
-import org.elasticsearch.search.aggregations.AggregationBuilder;
-import org.elasticsearch.search.aggregations.AggregationBuilders;
-import org.elasticsearch.search.aggregations.bucket.terms.Terms;
-import org.elasticsearch.search.aggregations.bucket.terms.TermsBuilder;
-import org.elasticsearch.search.sort.FieldSortBuilder;
-import org.elasticsearch.search.sort.SortBuilders;
-import org.elasticsearch.search.sort.SortOrder;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rule.RuleStatus;
-import org.sonar.api.rule.Severity;
-import org.sonar.server.es.BaseIndex;
-import org.sonar.server.es.EsClient;
-import org.sonar.server.es.SearchIdResult;
-import org.sonar.server.es.SearchOptions;
-import org.sonar.server.search.IndexField;
-import org.sonar.server.search.StickyFacetBuilder;
-
-import static org.sonar.server.es.EsUtils.SCROLL_TIME_IN_MINUTES;
-import static org.sonar.server.es.EsUtils.scrollIds;
-
-/**
- * The unique entry-point to interact with Elasticsearch index "rules".
- * All the requests are listed here.
- */
-public class RuleIndex2 extends BaseIndex {
-
-  public static final String FACET_LANGUAGES = "languages";
-  public static final String FACET_TAGS = "tags";
-  public static final String FACET_REPOSITORIES = "repositories";
-  public static final String FACET_SEVERITIES = "severities";
-  public static final String FACET_ACTIVE_SEVERITIES = "active_severities";
-  public static final String FACET_STATUSES = "statuses";
-  public static final String FACET_OLD_DEFAULT = "true";
-
-  public static final List<String> ALL_STATUSES_EXCEPT_REMOVED = ImmutableList.copyOf(
-    Collections2.filter(
-      Collections2.transform(
-        Arrays.asList(RuleStatus.values()),
-        new Function<RuleStatus, String>() {
-          @Override
-          public String apply(@Nonnull RuleStatus input) {
-            return input.toString();
-          }
-        }),
-      new Predicate<String>() {
-        @Override
-        public boolean apply(@Nonnull String input) {
-          return !RuleStatus.REMOVED.toString().equals(input);
-        }
-      }));
-
-  public RuleIndex2(EsClient client) {
-    super(client);
-  }
-
-  public SearchIdResult<RuleKey> search(RuleQuery query, SearchOptions options) {
-    SearchRequestBuilder esSearch = getClient()
-      .prepareSearch(RuleIndexDefinition.INDEX)
-      .setTypes(RuleIndexDefinition.TYPE_RULE);
-
-    QueryBuilder qb = buildQuery(query);
-    Map<String, FilterBuilder> filters = buildFilters(query);
-
-    if (!options.getFacets().isEmpty()) {
-      for (AggregationBuilder aggregation : getFacets(query, options, qb, filters).values()) {
-        esSearch.addAggregation(aggregation);
-      }
-    }
-
-    setSorting(query, esSearch);
-    setPagination(options, esSearch);
-
-    BoolFilterBuilder fb = FilterBuilders.boolFilter();
-    for (FilterBuilder filterBuilder : filters.values()) {
-      fb.must(filterBuilder);
-    }
-
-    esSearch.setQuery(QueryBuilders.filteredQuery(qb, fb));
-    return new SearchIdResult<>(esSearch.get(), ToRuleKey.INSTANCE);
-  }
-
-  /**
-   * Return all keys matching the search query, without pagination nor facets
-   */
-  public Iterator<RuleKey> searchAll(RuleQuery query) {
-    SearchRequestBuilder esSearch = getClient()
-      .prepareSearch(RuleIndexDefinition.INDEX)
-      .setTypes(RuleIndexDefinition.TYPE_RULE)
-      .setSearchType(SearchType.SCAN)
-      .setScroll(TimeValue.timeValueMinutes(SCROLL_TIME_IN_MINUTES));
-
-    QueryBuilder qb = buildQuery(query);
-    Map<String, FilterBuilder> filters = buildFilters(query);
-    setSorting(query, esSearch);
-
-    BoolFilterBuilder fb = FilterBuilders.boolFilter();
-    for (FilterBuilder filterBuilder : filters.values()) {
-      fb.must(filterBuilder);
-    }
-
-    esSearch.setQuery(QueryBuilders.filteredQuery(qb, fb));
-    SearchResponse response = esSearch.get();
-    return scrollIds(getClient(), response.getScrollId(), ToRuleKey.INSTANCE);
-  }
-
-  /* Build main query (search based) */
-  private QueryBuilder buildQuery(RuleQuery query) {
-
-    // No contextual query case
-    String queryText = query.getQueryText();
-    if (queryText == null || queryText.isEmpty()) {
-      return QueryBuilders.matchAllQuery();
-    }
-
-    // Build RuleBased contextual query
-    BoolQueryBuilder qb = QueryBuilders.boolQuery();
-    String queryString = query.getQueryText();
-
-    // Human readable type of querying
-    qb.should(QueryBuilders.simpleQueryStringQuery(query.getQueryText())
-      .field(RuleIndexDefinition.FIELD_RULE_NAME + "." + BaseIndex.SEARCH_WORDS_SUFFIX, 20f)
-      .field(RuleIndexDefinition.FIELD_RULE_HTML_DESCRIPTION + "." + BaseIndex.SEARCH_WORDS_SUFFIX, 3f)
-      .defaultOperator(SimpleQueryStringBuilder.Operator.AND)
-      ).boost(20f);
-
-    // Match and partial Match queries
-    qb.should(this.termQuery(RuleIndexDefinition.FIELD_RULE_KEY, queryString, 15f));
-    qb.should(this.termQuery(RuleIndexDefinition.FIELD_RULE_KEY_AS_LIST, queryString, 35f));
-    qb.should(this.termQuery(RuleIndexDefinition.FIELD_RULE_LANGUAGE, queryString, 3f));
-    qb.should(this.termQuery(RuleIndexDefinition.FIELD_RULE_ALL_TAGS, queryString, 10f));
-    qb.should(this.termAnyQuery(RuleIndexDefinition.FIELD_RULE_ALL_TAGS, queryString, 1f));
-
-    return qb;
-  }
-
-  private QueryBuilder termQuery(String field, String query, float boost) {
-    return QueryBuilders.multiMatchQuery(query,
-      field, field + "." + IndexField.SEARCH_PARTIAL_SUFFIX)
-      .operator(MatchQueryBuilder.Operator.AND)
-      .boost(boost);
-  }
-
-  private QueryBuilder termAnyQuery(String field, String query, float boost) {
-    return QueryBuilders.multiMatchQuery(query,
-      field, field + "." + IndexField.SEARCH_PARTIAL_SUFFIX)
-      .operator(MatchQueryBuilder.Operator.OR)
-      .boost(boost);
-  }
-
-  /* Build main filter (match based) */
-  private Map<String, FilterBuilder> buildFilters(RuleQuery query) {
-
-    Map<String, FilterBuilder> filters = new HashMap<>();
-
-    /* Add enforced filter on rules that are REMOVED */
-    filters.put(RuleIndexDefinition.FIELD_RULE_STATUS,
-      FilterBuilders.boolFilter().mustNot(
-        FilterBuilders.termFilter(RuleIndexDefinition.FIELD_RULE_STATUS,
-          RuleStatus.REMOVED.toString())));
-
-    if (!StringUtils.isEmpty(query.getInternalKey())) {
-      filters.put(RuleIndexDefinition.FIELD_RULE_INTERNAL_KEY,
-        FilterBuilders.termFilter(RuleIndexDefinition.FIELD_RULE_INTERNAL_KEY, query.getInternalKey()));
-    }
-
-    if (!StringUtils.isEmpty(query.getRuleKey())) {
-      filters.put(RuleIndexDefinition.FIELD_RULE_RULE_KEY,
-        FilterBuilders.termFilter(RuleIndexDefinition.FIELD_RULE_RULE_KEY, query.getRuleKey()));
-    }
-
-    if (!CollectionUtils.isEmpty(query.getLanguages())) {
-      filters.put(RuleIndexDefinition.FIELD_RULE_LANGUAGE,
-        FilterBuilders.termsFilter(RuleIndexDefinition.FIELD_RULE_LANGUAGE, query.getLanguages()));
-    }
-
-    if (!CollectionUtils.isEmpty(query.getRepositories())) {
-      filters.put(RuleIndexDefinition.FIELD_RULE_REPOSITORY,
-        FilterBuilders.termsFilter(RuleIndexDefinition.FIELD_RULE_REPOSITORY, query.getRepositories()));
-    }
-
-    if (!CollectionUtils.isEmpty(query.getSeverities())) {
-      filters.put(RuleIndexDefinition.FIELD_RULE_SEVERITY,
-        FilterBuilders.termsFilter(RuleIndexDefinition.FIELD_RULE_SEVERITY, query.getSeverities()));
-    }
-
-    if (!StringUtils.isEmpty(query.getKey())) {
-      filters.put(RuleIndexDefinition.FIELD_RULE_KEY,
-        FilterBuilders.termFilter(RuleIndexDefinition.FIELD_RULE_KEY, query.getKey()));
-    }
-
-    if (!CollectionUtils.isEmpty(query.getTags())) {
-      filters.put(RuleIndexDefinition.FIELD_RULE_ALL_TAGS,
-        FilterBuilders.termsFilter(RuleIndexDefinition.FIELD_RULE_ALL_TAGS, query.getTags()));
-    }
-
-    if (query.getAvailableSinceLong() != null) {
-      filters.put("availableSince", FilterBuilders.rangeFilter(RuleIndexDefinition.FIELD_RULE_CREATED_AT)
-        .gte(query.getAvailableSinceLong()));
-    }
-
-    Collection<RuleStatus> statusValues = query.getStatuses();
-    if (statusValues != null && !statusValues.isEmpty()) {
-      Collection<String> stringStatus = new ArrayList<>();
-      for (RuleStatus status : statusValues) {
-        stringStatus.add(status.name());
-      }
-      filters.put(RuleIndexDefinition.FIELD_RULE_STATUS,
-        FilterBuilders.termsFilter(RuleIndexDefinition.FIELD_RULE_STATUS, stringStatus));
-    }
-
-    Boolean isTemplate = query.isTemplate();
-    if (isTemplate != null) {
-      filters.put(RuleIndexDefinition.FIELD_RULE_IS_TEMPLATE,
-        FilterBuilders.termFilter(RuleIndexDefinition.FIELD_RULE_IS_TEMPLATE, Boolean.toString(isTemplate)));
-    }
-
-    String template = query.templateKey();
-    if (template != null) {
-      filters.put(RuleIndexDefinition.FIELD_RULE_TEMPLATE_KEY,
-        FilterBuilders.termFilter(RuleIndexDefinition.FIELD_RULE_TEMPLATE_KEY, template));
-    }
-
-    // ActiveRule Filter (profile and inheritance)
-    BoolFilterBuilder childrenFilter = FilterBuilders.boolFilter();
-    addTermFilter(childrenFilter, RuleIndexDefinition.FIELD_ACTIVE_RULE_PROFILE_KEY, query.getQProfileKey());
-    addTermFilter(childrenFilter, RuleIndexDefinition.FIELD_ACTIVE_RULE_INHERITANCE, query.getInheritance());
-    addTermFilter(childrenFilter, RuleIndexDefinition.FIELD_ACTIVE_RULE_SEVERITY, query.getActiveSeverities());
-
-    // ChildQuery
-    FilterBuilder childQuery;
-    if (childrenFilter.hasClauses()) {
-      childQuery = childrenFilter;
-    } else {
-      childQuery = FilterBuilders.matchAllFilter();
-    }
-
-    /** Implementation of activation query */
-    if (Boolean.TRUE.equals(query.getActivation())) {
-      filters.put("activation",
-        FilterBuilders.hasChildFilter(RuleIndexDefinition.TYPE_ACTIVE_RULE,
-          childQuery));
-    } else if (Boolean.FALSE.equals(query.getActivation())) {
-      filters.put("activation",
-        FilterBuilders.boolFilter().mustNot(
-          FilterBuilders.hasChildFilter(RuleIndexDefinition.TYPE_ACTIVE_RULE,
-            childQuery)));
-    }
-
-    return filters;
-  }
-
-  private BoolFilterBuilder addTermFilter(BoolFilterBuilder filter, String field, @Nullable Collection<String> values) {
-    if (values != null && !values.isEmpty()) {
-      BoolFilterBuilder valuesFilter = FilterBuilders.boolFilter();
-      for (String value : values) {
-        FilterBuilder valueFilter = FilterBuilders.termFilter(field, value);
-        valuesFilter.should(valueFilter);
-      }
-      filter.must(valuesFilter);
-    }
-    return filter;
-  }
-
-  private BoolFilterBuilder addTermFilter(BoolFilterBuilder filter, String field, @Nullable String value) {
-    if (value != null && !value.isEmpty()) {
-      filter.must(FilterBuilders.termFilter(field, value));
-    }
-    return filter;
-  }
-
-  private Map<String, AggregationBuilder> getFacets(RuleQuery query, SearchOptions options, QueryBuilder queryBuilder, Map<String, FilterBuilder> filters) {
-    Map<String, AggregationBuilder> aggregations = new HashMap<>();
-    StickyFacetBuilder stickyFacetBuilder = stickyFacetBuilder(queryBuilder, filters);
-
-    addDefaultFacets(query, options, aggregations, stickyFacetBuilder);
-
-    addStatusFacetIfNeeded(options, aggregations, stickyFacetBuilder);
-
-    if (options.getFacets().contains(FACET_SEVERITIES)) {
-      aggregations.put(FACET_SEVERITIES,
-        stickyFacetBuilder.buildStickyFacet(RuleIndexDefinition.FIELD_RULE_SEVERITY, FACET_SEVERITIES, Severity.ALL.toArray()));
-    }
-
-    addActiveSeverityFacetIfNeeded(query, options, aggregations, stickyFacetBuilder);
-    return aggregations;
-  }
-
-  private void addDefaultFacets(RuleQuery query, SearchOptions options, Map<String, AggregationBuilder> aggregations, StickyFacetBuilder stickyFacetBuilder) {
-    if (options.getFacets().contains(FACET_LANGUAGES) || options.getFacets().contains(FACET_OLD_DEFAULT)) {
-      Collection<String> languages = query.getLanguages();
-      aggregations.put(FACET_LANGUAGES,
-        stickyFacetBuilder.buildStickyFacet(RuleIndexDefinition.FIELD_RULE_LANGUAGE, FACET_LANGUAGES,
-          languages == null ? new String[0] : languages.toArray()));
-    }
-    if (options.getFacets().contains(FACET_TAGS) || options.getFacets().contains(FACET_OLD_DEFAULT)) {
-      Collection<String> tags = query.getTags();
-      aggregations.put(FACET_TAGS,
-        stickyFacetBuilder.buildStickyFacet(RuleIndexDefinition.FIELD_RULE_ALL_TAGS, FACET_TAGS,
-          tags == null ? new String[0] : tags.toArray()));
-    }
-    if (options.getFacets().contains("repositories") || options.getFacets().contains(FACET_OLD_DEFAULT)) {
-      Collection<String> repositories = query.getRepositories();
-      aggregations.put(FACET_REPOSITORIES,
-        stickyFacetBuilder.buildStickyFacet(RuleIndexDefinition.FIELD_RULE_REPOSITORY, FACET_REPOSITORIES,
-          repositories == null ? new String[0] : repositories.toArray()));
-    }
-  }
-
-  private void addStatusFacetIfNeeded(SearchOptions options, Map<String, AggregationBuilder> aggregations, StickyFacetBuilder stickyFacetBuilder) {
-    if (options.getFacets().contains(FACET_STATUSES)) {
-      BoolFilterBuilder facetFilter = stickyFacetBuilder.getStickyFacetFilter(RuleIndexDefinition.FIELD_RULE_STATUS);
-      AggregationBuilder statuses = AggregationBuilders.filter(FACET_STATUSES + "_filter")
-        .filter(facetFilter)
-        .subAggregation(
-          AggregationBuilders
-            .terms(FACET_STATUSES)
-            .field(RuleIndexDefinition.FIELD_RULE_STATUS)
-            .include(Joiner.on('|').join(ALL_STATUSES_EXCEPT_REMOVED))
-            .exclude(RuleStatus.REMOVED.toString())
-            .size(ALL_STATUSES_EXCEPT_REMOVED.size()));
-
-      aggregations.put(FACET_STATUSES, AggregationBuilders.global(FACET_STATUSES).subAggregation(statuses));
-    }
-  }
-
-  private void addActiveSeverityFacetIfNeeded(RuleQuery query, SearchOptions options, Map<String, AggregationBuilder> aggregations, StickyFacetBuilder stickyFacetBuilder) {
-    if (options.getFacets().contains(FACET_ACTIVE_SEVERITIES)) {
-      // We are building a children aggregation on active rules
-      // so the rule filter has to be used as parent filter for active rules
-      // from which we remove filters that concern active rules ("activation")
-      HasParentFilterBuilder ruleFilter = FilterBuilders.hasParentFilter(
-        RuleIndexDefinition.TYPE_RULE,
-        stickyFacetBuilder.getStickyFacetFilter("activation"));
-
-      // Rebuilding the active rule filter without severities
-      BoolFilterBuilder childrenFilter = FilterBuilders.boolFilter();
-      this.addTermFilter(childrenFilter, RuleIndexDefinition.FIELD_ACTIVE_RULE_PROFILE_KEY, query.getQProfileKey());
-      this.addTermFilter(childrenFilter, RuleIndexDefinition.FIELD_ACTIVE_RULE_INHERITANCE, query.getInheritance());
-      FilterBuilder activeRuleFilter;
-      if (childrenFilter.hasClauses()) {
-        activeRuleFilter = childrenFilter.must(ruleFilter);
-      } else {
-        activeRuleFilter = ruleFilter;
-      }
-
-      AggregationBuilder activeSeverities = AggregationBuilders.children(FACET_ACTIVE_SEVERITIES + "_children")
-        .childType(RuleIndexDefinition.TYPE_ACTIVE_RULE)
-        .subAggregation(AggregationBuilders.filter(FACET_ACTIVE_SEVERITIES + "_filter")
-          .filter(activeRuleFilter)
-          .subAggregation(
-            AggregationBuilders
-              .terms(FACET_ACTIVE_SEVERITIES)
-              .field(RuleIndexDefinition.FIELD_ACTIVE_RULE_SEVERITY)
-              .include(Joiner.on('|').join(Severity.ALL))
-              .size(Severity.ALL.size())));
-
-      aggregations.put(FACET_ACTIVE_SEVERITIES, AggregationBuilders.global(FACET_ACTIVE_SEVERITIES).subAggregation(activeSeverities));
-    }
-  }
-
-  private StickyFacetBuilder stickyFacetBuilder(QueryBuilder query, Map<String, FilterBuilder> filters) {
-    return new StickyFacetBuilder(query, filters);
-  }
-
-  private void setSorting(RuleQuery query, SearchRequestBuilder esSearch) {
-    /* integrate Query Sort */
-    String queryText = query.getQueryText();
-    if (query.getSortField() != null) {
-      FieldSortBuilder sort = SortBuilders.fieldSort(appendSortSuffixIfNeeded(query.getSortField()));
-      if (query.isAscendingSort()) {
-        sort.order(SortOrder.ASC);
-      } else {
-        sort.order(SortOrder.DESC);
-      }
-      esSearch.addSort(sort);
-    } else if (queryText != null && !queryText.isEmpty()) {
-      esSearch.addSort(SortBuilders.scoreSort());
-    } else {
-      esSearch.addSort(appendSortSuffixIfNeeded(RuleIndexDefinition.FIELD_RULE_UPDATED_AT), SortOrder.DESC);
-      // deterministic sort when exactly the same updated_at (same millisecond)
-      esSearch.addSort(appendSortSuffixIfNeeded(RuleIndexDefinition.FIELD_RULE_KEY), SortOrder.ASC);
-    }
-  }
-
-  public static String appendSortSuffixIfNeeded(String field) {
-      return field +
-        ((field.equals(RuleIndexDefinition.FIELD_RULE_NAME)
-        || field.equals(RuleIndexDefinition.FIELD_RULE_KEY))
-          ? "." + BaseIndex.SORT_SUFFIX
-          : "");
-  }
-
-  private void setPagination(SearchOptions options, SearchRequestBuilder esSearch) {
-    esSearch.setFrom(options.getOffset());
-    esSearch.setSize(options.getLimit());
-  }
-
-  public Set<String> terms(String fields) {
-    return terms(fields, null, Integer.MAX_VALUE);
-  }
-
-  public Set<String> terms(String fields, @Nullable String query, int size) {
-    Set<String> tags = new HashSet<>();
-    String key = "_ref";
-
-    TermsBuilder terms = AggregationBuilders.terms(key)
-      .field(fields)
-      .size(size)
-      .minDocCount(1);
-    if (query != null) {
-      terms.include(".*" + query + ".*");
-    }
-    SearchRequestBuilder request = this.getClient()
-      .prepareSearch(RuleIndexDefinition.INDEX)
-      .setQuery(QueryBuilders.matchAllQuery())
-      .addAggregation(terms);
-
-    SearchResponse esResponse = request.get();
-
-    Terms aggregation = esResponse.getAggregations().get(key);
-
-    if (aggregation != null) {
-      for (Terms.Bucket value : aggregation.getBuckets()) {
-        tags.add(value.getKey());
-      }
-    }
-    return tags;
-  }
-
-  private enum ToRuleKey implements Function<String, RuleKey> {
-    INSTANCE;
-
-    @Override
-    public RuleKey apply(@Nonnull String input) {
-      return RuleKey.parse(input);
-    }
-  }
-
-}
index 217b025d873af9edd0820790536d83fadf2c46a3..fdd7c5ff68320375073cd3878745c43c871af274 100644 (file)
@@ -57,7 +57,7 @@ import org.sonar.server.es.Facets;
 import org.sonar.server.es.SearchIdResult;
 import org.sonar.server.qualityprofile.ActiveRule;
 import org.sonar.server.rule.Rule;
-import org.sonar.server.rule.index.RuleIndex2;
+import org.sonar.server.rule.index.RuleIndex;
 import org.sonar.server.rule.index.RuleIndexDefinition;
 import org.sonar.server.rule.index.RuleQuery;
 import org.sonar.server.search.ws.SearchOptions;
@@ -65,14 +65,14 @@ import org.sonarqube.ws.Common;
 import org.sonarqube.ws.Rules.SearchResponse;
 
 import static com.google.common.collect.FluentIterable.from;
-import static org.sonar.server.rule.index.RuleIndex2.ALL_STATUSES_EXCEPT_REMOVED;
-import static org.sonar.server.rule.index.RuleIndex2.FACET_ACTIVE_SEVERITIES;
-import static org.sonar.server.rule.index.RuleIndex2.FACET_LANGUAGES;
-import static org.sonar.server.rule.index.RuleIndex2.FACET_OLD_DEFAULT;
-import static org.sonar.server.rule.index.RuleIndex2.FACET_REPOSITORIES;
-import static org.sonar.server.rule.index.RuleIndex2.FACET_SEVERITIES;
-import static org.sonar.server.rule.index.RuleIndex2.FACET_STATUSES;
-import static org.sonar.server.rule.index.RuleIndex2.FACET_TAGS;
+import static org.sonar.server.rule.index.RuleIndex.ALL_STATUSES_EXCEPT_REMOVED;
+import static org.sonar.server.rule.index.RuleIndex.FACET_ACTIVE_SEVERITIES;
+import static org.sonar.server.rule.index.RuleIndex.FACET_LANGUAGES;
+import static org.sonar.server.rule.index.RuleIndex.FACET_OLD_DEFAULT;
+import static org.sonar.server.rule.index.RuleIndex.FACET_REPOSITORIES;
+import static org.sonar.server.rule.index.RuleIndex.FACET_SEVERITIES;
+import static org.sonar.server.rule.index.RuleIndex.FACET_STATUSES;
+import static org.sonar.server.rule.index.RuleIndex.FACET_TAGS;
 import static org.sonar.server.ws.WsUtils.writeProtobuf;
 
 /**
@@ -100,12 +100,12 @@ public class SearchAction implements RulesWsAction {
   private static final Collection<String> DEFAULT_FACETS = ImmutableSet.of(PARAM_LANGUAGES, PARAM_REPOSITORIES, "tags");
 
   private final DbClient dbClient;
-  private final RuleIndex2 ruleIndex;
+  private final RuleIndex ruleIndex;
   private final ActiveRuleCompleter activeRuleCompleter;
   private final RuleMapping mapping;
   private final RuleMapper mapper;
 
-  public SearchAction(RuleIndex2 ruleIndex, ActiveRuleCompleter activeRuleCompleter, RuleMapping mapping, DbClient dbClient, RuleMapper mapper) {
+  public SearchAction(RuleIndex ruleIndex, ActiveRuleCompleter activeRuleCompleter, RuleMapping mapping, DbClient dbClient, RuleMapper mapper) {
     this.ruleIndex = ruleIndex;
     this.activeRuleCompleter = activeRuleCompleter;
     this.mapping = mapping;
@@ -336,7 +336,7 @@ public class SearchAction implements RulesWsAction {
     org.sonar.server.es.SearchOptions searchQueryContext = mapping.newQueryOptions(SearchOptions.create(request))
       .setLimit(context.getLimit())
       .setOffset(context.getOffset());
-    if (context.getFacets().contains(RuleIndex2.FACET_OLD_DEFAULT)) {
+    if (context.getFacets().contains(RuleIndex.FACET_OLD_DEFAULT)) {
       searchQueryContext.addFacets(DEFAULT_FACETS);
     } else {
       searchQueryContext.addFacets(context.getFacets());
index 9cbe9a8cf1a6fb967fa35c06bd3439b2d7bf67ff..9c130568ebc262969ba4516d62ca02430d3d2c0b 100644 (file)
@@ -40,7 +40,7 @@ import org.sonar.db.rule.RuleDto;
 import org.sonar.db.rule.RuleParamDto;
 import org.sonar.db.rule.RuleTesting;
 import org.sonar.server.qualityprofile.index.ActiveRuleDoc;
-import org.sonar.server.qualityprofile.index.ActiveRuleIndex2;
+import org.sonar.server.qualityprofile.index.ActiveRuleIndex;
 import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
 import org.sonar.server.rule.index.RuleIndexer;
 import org.sonar.server.tester.ServerTester;
@@ -58,7 +58,7 @@ public class QProfileCopierMediumTest {
 
   DbClient db;
   DbSession dbSession;
-  ActiveRuleIndex2 index;
+  ActiveRuleIndex index;
   RuleActivator ruleActivator;
   QProfileCopier copier;
   RuleIndexer ruleIndexer;
@@ -70,7 +70,7 @@ public class QProfileCopierMediumTest {
     db = tester.get(DbClient.class);
     dbSession = db.openSession(false);
     ruleActivator = tester.get(RuleActivator.class);
-    index = tester.get(ActiveRuleIndex2.class);
+    index = tester.get(ActiveRuleIndex.class);
     copier = tester.get(QProfileCopier.class);
     ruleIndexer = tester.get(RuleIndexer.class);
     ruleIndexer.setEnabled(true);
index 7567c3b52309627ab8f135a20a6e0edf6467eecf..245e133f75a3e22ba3a5e3310a782618ccf8c8cc 100644 (file)
@@ -38,7 +38,7 @@ import org.sonar.db.rule.RuleParamDto;
 import org.sonar.db.rule.RuleTesting;
 import org.sonar.server.exceptions.BadRequestException;
 import org.sonar.server.exceptions.NotFoundException;
-import org.sonar.server.qualityprofile.index.ActiveRuleIndex2;
+import org.sonar.server.qualityprofile.index.ActiveRuleIndex;
 import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
 import org.sonar.server.rule.index.RuleIndexer;
 import org.sonar.server.tester.MockUserSession;
@@ -62,7 +62,7 @@ public class QProfileFactoryMediumTest {
 
   DbClient db;
   DbSession dbSession;
-  ActiveRuleIndex2 activeRuleIndex;
+  ActiveRuleIndex activeRuleIndex;
   ActiveRuleIndexer activeRuleIndexer;
   RuleIndexer ruleIndexer;
   QProfileFactory factory;
@@ -73,7 +73,7 @@ public class QProfileFactoryMediumTest {
     db = tester.get(DbClient.class);
     dbSession = db.openSession(false);
     factory = tester.get(QProfileFactory.class);
-    activeRuleIndex = tester.get(ActiveRuleIndex2.class);
+    activeRuleIndex = tester.get(ActiveRuleIndex.class);
     activeRuleIndexer = tester.get(ActiveRuleIndexer.class);
     activeRuleIndexer.setEnabled(true);
     ruleIndexer = tester.get(RuleIndexer.class);
index 92e052ca286292c4652fc65224fc63e014845c76..41fbdb61e786e5e09b1c1782f85cb047937a6c63 100644 (file)
@@ -43,7 +43,7 @@ import org.sonar.db.qualityprofile.ActiveRuleParamDto;
 import org.sonar.db.qualityprofile.QualityProfileDao;
 import org.sonar.db.qualityprofile.QualityProfileDto;
 import org.sonar.server.platform.Platform;
-import org.sonar.server.qualityprofile.index.ActiveRuleIndex2;
+import org.sonar.server.qualityprofile.index.ActiveRuleIndex;
 import org.sonar.server.tester.ServerTester;
 import org.sonar.server.tester.UserSessionRule;
 
@@ -149,7 +149,7 @@ public class QProfileResetMediumTest {
     // Severity and parameter value come back to origin after reset
     activeRuleDto = tester.get(ActiveRuleDao.class).selectOrFailByKey(dbSession, activeRuleKey);
     assertThat(activeRuleDto.getSeverityString()).isEqualTo(CRITICAL);
-    ActiveRule activeRule = tester.get(ActiveRuleIndex2.class).getNullableByKey(activeRuleKey);
+    ActiveRule activeRule = tester.get(ActiveRuleIndex.class).getNullableByKey(activeRuleKey);
     assertThat(activeRule.severity()).isEqualTo(CRITICAL);
 
     activeRuleParamDtos = tester.get(ActiveRuleDao.class).selectParamsByActiveRuleKey(dbSession, activeRuleKey);
index 6c892422c05bbefb00d98389faf319cb00389ae9..9977ea4288b6ee5525d0c4a105a54df9a650c852 100644 (file)
@@ -43,7 +43,7 @@ import org.sonar.db.qualityprofile.QualityProfileDao;
 import org.sonar.db.qualityprofile.QualityProfileDto;
 import org.sonar.server.es.SearchOptions;
 import org.sonar.server.platform.Platform;
-import org.sonar.server.rule.index.RuleIndex2;
+import org.sonar.server.rule.index.RuleIndex;
 import org.sonar.server.rule.index.RuleQuery;
 import org.sonar.server.tester.ServerTester;
 
@@ -88,7 +88,7 @@ public class RegisterQualityProfilesMediumTest {
     assertThat(activeRuleDao.selectByKey(dbSession, activeRuleKey)).isPresent();
 
     // Check in ES
-    assertThat(tester.get(RuleIndex2.class).search(new RuleQuery().setActivation(true), new SearchOptions()).getIds()).containsOnly(ruleKey, RuleKey.of("xoo", "x2"));
+    assertThat(tester.get(RuleIndex.class).search(new RuleQuery().setActivation(true), new SearchOptions()).getIds()).containsOnly(ruleKey, RuleKey.of("xoo", "x2"));
 
     tester.get(Platform.class).restart();
 
@@ -101,7 +101,7 @@ public class RegisterQualityProfilesMediumTest {
     assertThat(activeRule.getSeverityString()).isEqualTo(Severity.CRITICAL);
 
     // Check in ES
-    assertThat(tester.get(RuleIndex2.class).search(new RuleQuery().setActivation(true), new SearchOptions()).getIds()).containsOnly(ruleKey, RuleKey.of("xoo", "x2"));
+    assertThat(tester.get(RuleIndex.class).search(new RuleQuery().setActivation(true), new SearchOptions()).getIds()).containsOnly(ruleKey, RuleKey.of("xoo", "x2"));
 
     // TODO
     // Check ActiveRuleParameters in DB
index 28724162f817995812ff193cec5e9e1bec92a2a0..5f213e685ef2a28d198400a1a701c808612a7141 100644 (file)
@@ -46,9 +46,9 @@ import org.sonar.server.es.SearchOptions;
 import org.sonar.server.exceptions.BadRequestException;
 import org.sonar.server.exceptions.Message;
 import org.sonar.server.qualityprofile.index.ActiveRuleDoc;
-import org.sonar.server.qualityprofile.index.ActiveRuleIndex2;
+import org.sonar.server.qualityprofile.index.ActiveRuleIndex;
 import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
-import org.sonar.server.rule.index.RuleIndex2;
+import org.sonar.server.rule.index.RuleIndex;
 import org.sonar.server.rule.index.RuleIndexer;
 import org.sonar.server.rule.index.RuleQuery;
 import org.sonar.server.search.QueryContext;
@@ -95,7 +95,7 @@ public class RuleActivatorMediumTest {
 
   RuleIndexer ruleIndexer;
 
-  ActiveRuleIndex2 activeRuleIndex;
+  ActiveRuleIndex activeRuleIndex;
   ActiveRuleIndexer activeRuleIndexer;
 
   QualityProfileDto profileDto;
@@ -106,7 +106,7 @@ public class RuleActivatorMediumTest {
     db = tester.get(DbClient.class);
     dbSession = db.openSession(false);
     ruleActivator = tester.get(RuleActivator.class);
-    activeRuleIndex = tester.get(ActiveRuleIndex2.class);
+    activeRuleIndex = tester.get(ActiveRuleIndex.class);
     activeRuleIndexer = tester.get(ActiveRuleIndexer.class);
     activeRuleIndexer.setEnabled(true);
     ruleIndexer = tester.get(RuleIndexer.class);
@@ -876,7 +876,7 @@ public class RuleActivatorMediumTest {
 
     // 0. No active rules so far (base case) and plenty rules available
     verifyZeroActiveRules(XOO_P1_KEY);
-    assertThat(tester.get(RuleIndex2.class)
+    assertThat(tester.get(RuleIndex.class)
       .search(new RuleQuery().setRepositories(Arrays.asList("bulk")), new SearchOptions()).getTotal())
       .isEqualTo(bulkSize);
 
diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/index/ActiveRuleIndex2Test.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/index/ActiveRuleIndex2Test.java
deleted file mode 100644 (file)
index 28db5d4..0000000
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program 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.
- *
- * This program 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.index;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Multimap;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import org.junit.Before;
-import org.junit.ClassRule;
-import org.junit.Test;
-import org.sonar.api.config.Settings;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rule.RuleStatus;
-import org.sonar.db.qualityprofile.ActiveRuleKey;
-import org.sonar.db.rule.RuleTesting;
-import org.sonar.server.es.EsTester;
-import org.sonar.server.qualityprofile.ActiveRule;
-import org.sonar.server.rule.index.RuleDoc;
-import org.sonar.server.rule.index.RuleDocTesting;
-import org.sonar.server.rule.index.RuleIndexDefinition;
-import org.sonar.server.rule.index.RuleIndexer;
-import org.sonar.server.search.FacetValue;
-
-import static java.util.Arrays.asList;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.entry;
-import static org.sonar.api.rule.Severity.BLOCKER;
-import static org.sonar.api.rule.Severity.MAJOR;
-import static org.sonar.api.rule.Severity.MINOR;
-import static org.sonar.server.qualityprofile.ActiveRule.Inheritance.INHERITED;
-import static org.sonar.server.qualityprofile.ActiveRule.Inheritance.OVERRIDES;
-import static org.sonar.server.rule.index.RuleDocTesting.newDoc;
-import static org.sonar.server.rule.index.RuleIndexDefinition.INDEX;
-import static org.sonar.server.rule.index.RuleIndexDefinition.TYPE_ACTIVE_RULE;
-
-public class ActiveRuleIndex2Test {
-
-  static final RuleKey RULE_KEY_1 = RuleTesting.XOO_X1;
-  static final RuleKey RULE_KEY_2 = RuleTesting.XOO_X2;
-
-  static final String QUALITY_PROFILE_KEY1 = "qp1";
-  static final String QUALITY_PROFILE_KEY2 = "qp2";
-
-  @ClassRule
-  public static EsTester tester = new EsTester().addDefinitions(new RuleIndexDefinition(new Settings()));
-
-  ActiveRuleIndex2 index;
-
-  ActiveRuleIndexer activeRuleIndexer;
-  RuleIndexer ruleIndexer;
-
-  @Before
-  public void setUp() {
-    tester.truncateIndices();
-    activeRuleIndexer = new ActiveRuleIndexer(null, tester.client());
-    ruleIndexer = new RuleIndexer(null, tester.client());
-    index = new ActiveRuleIndex2(tester.client());
-  }
-
-  @Test
-  public void count_all_by_quality_profile_key() {
-    indexRules(RuleDocTesting.newDoc(RULE_KEY_1));
-
-    indexActiveRules(
-      ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_1)),
-      ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY2, RULE_KEY_1)));
-
-    // 0. Test base case
-    assertThat(tester.countDocuments(INDEX, TYPE_ACTIVE_RULE)).isEqualTo(2);
-
-    // 1. Assert by term aggregation;
-    assertThat(index.countAllByQualityProfileKey()).containsOnly(entry(QUALITY_PROFILE_KEY1, 1L), entry(QUALITY_PROFILE_KEY2, 1L));
-  }
-
-  @Test
-  public void stats_for_all() {
-    indexRules(
-      newDoc(RULE_KEY_1),
-      newDoc(RULE_KEY_2));
-
-    ActiveRuleKey activeRuleKey1 = ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_1);
-    ActiveRuleKey activeRuleKey2 = ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_2);
-
-    indexActiveRules(
-      ActiveRuleDocTesting.newDoc(activeRuleKey1).setSeverity(BLOCKER),
-      ActiveRuleDocTesting.newDoc(activeRuleKey2).setSeverity(MINOR),
-      // Profile 2 is a child a profile 1
-      ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY2, RULE_KEY_1)).setSeverity(MAJOR)
-        .setParentKey(activeRuleKey1.toString()).setInheritance(INHERITED.name()),
-      ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY2, RULE_KEY_2)).setSeverity(BLOCKER)
-        .setParentKey(activeRuleKey2.toString()).setInheritance(OVERRIDES.name()));
-
-    // 0. Test base case
-    assertThat(tester.countDocuments(INDEX, TYPE_ACTIVE_RULE)).isEqualTo(4);
-
-    // 1. Assert by term aggregation;
-    Map<String, Multimap<String, FacetValue>> stats = index.getStatsByProfileKeys(ImmutableList.of(QUALITY_PROFILE_KEY1, QUALITY_PROFILE_KEY2));
-    assertThat(stats).hasSize(2);
-  }
-
-  /**
-   * SONAR-5844
-   */
-  @Test
-  public void stats_for_all_with_lof_of_profiles() {
-    indexRules(RuleDocTesting.newDoc(RULE_KEY_1), RuleDocTesting.newDoc(RULE_KEY_2));
-
-    indexActiveRules(
-      ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_1)),
-      ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY2, RULE_KEY_1)));
-
-    List<String> profileKeys = new ArrayList<>();
-    List<ActiveRuleDoc> docs = new ArrayList<>();
-    for (int i = 0; i < 30; i++) {
-      String profileKey = "profile-" + i;
-      profileKeys.add(profileKey);
-      docs.add(ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(profileKey, RULE_KEY_1)).setSeverity(BLOCKER));
-      docs.add(ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(profileKey, RULE_KEY_2)).setSeverity(MAJOR));
-    }
-    indexActiveRules(docs.toArray(new ActiveRuleDoc[]{}));
-
-    Map<String, Multimap<String, FacetValue>> stats = index.getStatsByProfileKeys(profileKeys);
-    assertThat(stats).hasSize(30);
-  }
-
-  @Test
-  public void get_by_key() {
-    indexRules(RuleDocTesting.newDoc(RULE_KEY_1));
-    ActiveRuleKey key = ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_1);
-    indexActiveRules(ActiveRuleDocTesting.newDoc(key));
-
-    assertThat(index.getNullableByKey(key)).isNotNull();
-    assertThat(index.getNullableByKey(ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_2))).isNull();
-  }
-
-  @Test
-  public void find_active_rules() {
-    indexRules(
-      RuleDocTesting.newDoc(RULE_KEY_1),
-      RuleDocTesting.newDoc(RULE_KEY_2),
-      RuleDocTesting.newDoc(RuleKey.of("xoo", "removed")).setStatus(RuleStatus.REMOVED.name())
-    );
-
-    indexActiveRules(
-      ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_1)),
-      ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_2)),
-      ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY2, RULE_KEY_2)),
-      // Removed rule can still be activated for instance when removing the checkstyle plugin, active rules related on checkstyle are not
-      // removed
-      // because if the plugin is re-install, quality profiles using these rule are not changed.
-      ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY2, RuleKey.of("xoo", "removed")))
-    );
-
-    // 1. find by rule key
-
-    // in es
-    List<ActiveRule> activeRules = index.findByRule(RULE_KEY_1);
-    assertThat(activeRules).hasSize(1);
-    assertThat(activeRules.get(0).key().ruleKey()).isEqualTo(RULE_KEY_1);
-
-    activeRules = index.findByRule(RULE_KEY_2);
-    assertThat(activeRules).hasSize(2);
-    assertThat(activeRules.get(0).key().ruleKey()).isEqualTo(RULE_KEY_2);
-
-    activeRules = index.findByRule(RuleKey.of("unknown", "unknown"));
-    assertThat(activeRules).isEmpty();
-
-    // 2. find by profile
-    List<ActiveRuleDoc> activeRuleDocs = Lists.newArrayList(index.findByProfile(QUALITY_PROFILE_KEY1));
-    assertThat(activeRuleDocs).hasSize(2);
-    assertThat(activeRuleDocs.get(0).key().qProfile()).isEqualTo(QUALITY_PROFILE_KEY1);
-    assertThat(activeRuleDocs.get(1).key().qProfile()).isEqualTo(QUALITY_PROFILE_KEY1);
-
-    activeRuleDocs = Lists.newArrayList(index.findByProfile(QUALITY_PROFILE_KEY2));
-    assertThat(activeRuleDocs).hasSize(1);
-    assertThat(activeRuleDocs.get(0).key().qProfile()).isEqualTo(QUALITY_PROFILE_KEY2);
-
-    activeRuleDocs = Lists.newArrayList(index.findByProfile("unknown"));
-    assertThat(activeRuleDocs).isEmpty();
-  }
-
-  @Test
-  public void find_many_active_rules_by_profile() {
-    int nb = 150;
-    RuleDoc[] ruleDocs = new RuleDoc[nb];
-    ActiveRuleDoc[] activeRuleDocs = new ActiveRuleDoc[nb];
-    for (int i = 0; i < nb; i++) {
-      RuleKey ruleKey = RuleKey.of("xoo", "S00" + i);
-      ruleDocs[i] = RuleDocTesting.newDoc(ruleKey);
-      activeRuleDocs[i] = ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY1, ruleKey));
-    }
-    indexRules(ruleDocs);
-    indexActiveRules(activeRuleDocs);
-
-    // verify index
-    assertThat(index.findByProfile(QUALITY_PROFILE_KEY1)).hasSize(nb);
-  }
-
-  @Test
-  public void find_many_active_rules_by_rule() {
-    indexRules(RuleDocTesting.newDoc(RULE_KEY_1));
-
-    int nb = 150;
-    ActiveRuleDoc[] activeRuleDocs = new ActiveRuleDoc[nb];
-    for (int i = 0; i < nb; i++) {
-      activeRuleDocs[i] = ActiveRuleDocTesting.newDoc(ActiveRuleKey.of("qp" + i, RULE_KEY_1));
-    }
-    indexActiveRules(activeRuleDocs);
-
-    // verify index
-    assertThat(index.findByRule(RULE_KEY_1)).hasSize(nb);
-  }
-
-  private void indexActiveRules(ActiveRuleDoc... docs) {
-    activeRuleIndexer.index(asList(docs).iterator());
-  }
-
-  private void indexRules(RuleDoc... rules) {
-    ruleIndexer.index(asList(rules).iterator());
-  }
-
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/index/ActiveRuleIndexTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/index/ActiveRuleIndexTest.java
new file mode 100644 (file)
index 0000000..8274fb8
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program 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.index;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Multimap;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.sonar.api.config.Settings;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rule.RuleStatus;
+import org.sonar.db.qualityprofile.ActiveRuleKey;
+import org.sonar.db.rule.RuleTesting;
+import org.sonar.server.es.EsTester;
+import org.sonar.server.qualityprofile.ActiveRule;
+import org.sonar.server.rule.index.RuleDoc;
+import org.sonar.server.rule.index.RuleDocTesting;
+import org.sonar.server.rule.index.RuleIndexDefinition;
+import org.sonar.server.rule.index.RuleIndexer;
+import org.sonar.server.search.FacetValue;
+
+import static java.util.Arrays.asList;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.entry;
+import static org.sonar.api.rule.Severity.BLOCKER;
+import static org.sonar.api.rule.Severity.MAJOR;
+import static org.sonar.api.rule.Severity.MINOR;
+import static org.sonar.server.qualityprofile.ActiveRule.Inheritance.INHERITED;
+import static org.sonar.server.qualityprofile.ActiveRule.Inheritance.OVERRIDES;
+import static org.sonar.server.rule.index.RuleDocTesting.newDoc;
+import static org.sonar.server.rule.index.RuleIndexDefinition.INDEX;
+import static org.sonar.server.rule.index.RuleIndexDefinition.TYPE_ACTIVE_RULE;
+
+public class ActiveRuleIndexTest {
+
+  static final RuleKey RULE_KEY_1 = RuleTesting.XOO_X1;
+  static final RuleKey RULE_KEY_2 = RuleTesting.XOO_X2;
+
+  static final String QUALITY_PROFILE_KEY1 = "qp1";
+  static final String QUALITY_PROFILE_KEY2 = "qp2";
+
+  @ClassRule
+  public static EsTester tester = new EsTester().addDefinitions(new RuleIndexDefinition(new Settings()));
+
+  ActiveRuleIndex index;
+
+  ActiveRuleIndexer activeRuleIndexer;
+  RuleIndexer ruleIndexer;
+
+  @Before
+  public void setUp() {
+    tester.truncateIndices();
+    activeRuleIndexer = new ActiveRuleIndexer(null, tester.client());
+    ruleIndexer = new RuleIndexer(null, tester.client());
+    index = new ActiveRuleIndex(tester.client());
+  }
+
+  @Test
+  public void count_all_by_quality_profile_key() {
+    indexRules(RuleDocTesting.newDoc(RULE_KEY_1));
+
+    indexActiveRules(
+      ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_1)),
+      ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY2, RULE_KEY_1)));
+
+    // 0. Test base case
+    assertThat(tester.countDocuments(INDEX, TYPE_ACTIVE_RULE)).isEqualTo(2);
+
+    // 1. Assert by term aggregation;
+    assertThat(index.countAllByQualityProfileKey()).containsOnly(entry(QUALITY_PROFILE_KEY1, 1L), entry(QUALITY_PROFILE_KEY2, 1L));
+  }
+
+  @Test
+  public void stats_for_all() {
+    indexRules(
+      newDoc(RULE_KEY_1),
+      newDoc(RULE_KEY_2));
+
+    ActiveRuleKey activeRuleKey1 = ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_1);
+    ActiveRuleKey activeRuleKey2 = ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_2);
+
+    indexActiveRules(
+      ActiveRuleDocTesting.newDoc(activeRuleKey1).setSeverity(BLOCKER),
+      ActiveRuleDocTesting.newDoc(activeRuleKey2).setSeverity(MINOR),
+      // Profile 2 is a child a profile 1
+      ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY2, RULE_KEY_1)).setSeverity(MAJOR)
+        .setParentKey(activeRuleKey1.toString()).setInheritance(INHERITED.name()),
+      ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY2, RULE_KEY_2)).setSeverity(BLOCKER)
+        .setParentKey(activeRuleKey2.toString()).setInheritance(OVERRIDES.name()));
+
+    // 0. Test base case
+    assertThat(tester.countDocuments(INDEX, TYPE_ACTIVE_RULE)).isEqualTo(4);
+
+    // 1. Assert by term aggregation;
+    Map<String, Multimap<String, FacetValue>> stats = index.getStatsByProfileKeys(ImmutableList.of(QUALITY_PROFILE_KEY1, QUALITY_PROFILE_KEY2));
+    assertThat(stats).hasSize(2);
+  }
+
+  /**
+   * SONAR-5844
+   */
+  @Test
+  public void stats_for_all_with_lof_of_profiles() {
+    indexRules(RuleDocTesting.newDoc(RULE_KEY_1), RuleDocTesting.newDoc(RULE_KEY_2));
+
+    indexActiveRules(
+      ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_1)),
+      ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY2, RULE_KEY_1)));
+
+    List<String> profileKeys = new ArrayList<>();
+    List<ActiveRuleDoc> docs = new ArrayList<>();
+    for (int i = 0; i < 30; i++) {
+      String profileKey = "profile-" + i;
+      profileKeys.add(profileKey);
+      docs.add(ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(profileKey, RULE_KEY_1)).setSeverity(BLOCKER));
+      docs.add(ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(profileKey, RULE_KEY_2)).setSeverity(MAJOR));
+    }
+    indexActiveRules(docs.toArray(new ActiveRuleDoc[]{}));
+
+    Map<String, Multimap<String, FacetValue>> stats = index.getStatsByProfileKeys(profileKeys);
+    assertThat(stats).hasSize(30);
+  }
+
+  @Test
+  public void get_by_key() {
+    indexRules(RuleDocTesting.newDoc(RULE_KEY_1));
+    ActiveRuleKey key = ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_1);
+    indexActiveRules(ActiveRuleDocTesting.newDoc(key));
+
+    assertThat(index.getNullableByKey(key)).isNotNull();
+    assertThat(index.getNullableByKey(ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_2))).isNull();
+  }
+
+  @Test
+  public void find_active_rules() {
+    indexRules(
+      RuleDocTesting.newDoc(RULE_KEY_1),
+      RuleDocTesting.newDoc(RULE_KEY_2),
+      RuleDocTesting.newDoc(RuleKey.of("xoo", "removed")).setStatus(RuleStatus.REMOVED.name())
+    );
+
+    indexActiveRules(
+      ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_1)),
+      ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_2)),
+      ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY2, RULE_KEY_2)),
+      // Removed rule can still be activated for instance when removing the checkstyle plugin, active rules related on checkstyle are not
+      // removed
+      // because if the plugin is re-install, quality profiles using these rule are not changed.
+      ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY2, RuleKey.of("xoo", "removed")))
+    );
+
+    // 1. find by rule key
+
+    // in es
+    List<ActiveRule> activeRules = index.findByRule(RULE_KEY_1);
+    assertThat(activeRules).hasSize(1);
+    assertThat(activeRules.get(0).key().ruleKey()).isEqualTo(RULE_KEY_1);
+
+    activeRules = index.findByRule(RULE_KEY_2);
+    assertThat(activeRules).hasSize(2);
+    assertThat(activeRules.get(0).key().ruleKey()).isEqualTo(RULE_KEY_2);
+
+    activeRules = index.findByRule(RuleKey.of("unknown", "unknown"));
+    assertThat(activeRules).isEmpty();
+
+    // 2. find by profile
+    List<ActiveRuleDoc> activeRuleDocs = Lists.newArrayList(index.findByProfile(QUALITY_PROFILE_KEY1));
+    assertThat(activeRuleDocs).hasSize(2);
+    assertThat(activeRuleDocs.get(0).key().qProfile()).isEqualTo(QUALITY_PROFILE_KEY1);
+    assertThat(activeRuleDocs.get(1).key().qProfile()).isEqualTo(QUALITY_PROFILE_KEY1);
+
+    activeRuleDocs = Lists.newArrayList(index.findByProfile(QUALITY_PROFILE_KEY2));
+    assertThat(activeRuleDocs).hasSize(1);
+    assertThat(activeRuleDocs.get(0).key().qProfile()).isEqualTo(QUALITY_PROFILE_KEY2);
+
+    activeRuleDocs = Lists.newArrayList(index.findByProfile("unknown"));
+    assertThat(activeRuleDocs).isEmpty();
+  }
+
+  @Test
+  public void find_many_active_rules_by_profile() {
+    int nb = 150;
+    RuleDoc[] ruleDocs = new RuleDoc[nb];
+    ActiveRuleDoc[] activeRuleDocs = new ActiveRuleDoc[nb];
+    for (int i = 0; i < nb; i++) {
+      RuleKey ruleKey = RuleKey.of("xoo", "S00" + i);
+      ruleDocs[i] = RuleDocTesting.newDoc(ruleKey);
+      activeRuleDocs[i] = ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY1, ruleKey));
+    }
+    indexRules(ruleDocs);
+    indexActiveRules(activeRuleDocs);
+
+    // verify index
+    assertThat(index.findByProfile(QUALITY_PROFILE_KEY1)).hasSize(nb);
+  }
+
+  @Test
+  public void find_many_active_rules_by_rule() {
+    indexRules(RuleDocTesting.newDoc(RULE_KEY_1));
+
+    int nb = 150;
+    ActiveRuleDoc[] activeRuleDocs = new ActiveRuleDoc[nb];
+    for (int i = 0; i < nb; i++) {
+      activeRuleDocs[i] = ActiveRuleDocTesting.newDoc(ActiveRuleKey.of("qp" + i, RULE_KEY_1));
+    }
+    indexActiveRules(activeRuleDocs);
+
+    // verify index
+    assertThat(index.findByRule(RULE_KEY_1)).hasSize(nb);
+  }
+
+  private void indexActiveRules(ActiveRuleDoc... docs) {
+    activeRuleIndexer.index(asList(docs).iterator());
+  }
+
+  private void indexRules(RuleDoc... rules) {
+    ruleIndexer.index(asList(rules).iterator());
+  }
+
+}
index e51107c878d3fdbb59eb5333c303b8e4b6ec4853..ddc8b9d7cbf6d2d689daefe01a734fffc5f35c9c 100644 (file)
@@ -41,7 +41,7 @@ import org.sonar.server.qualityprofile.QProfileName;
 import org.sonar.server.qualityprofile.QProfileTesting;
 import org.sonar.server.qualityprofile.RuleActivator;
 import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
-import org.sonar.server.rule.index.RuleIndex2;
+import org.sonar.server.rule.index.RuleIndex;
 import org.sonar.server.rule.index.RuleIndexer;
 import org.sonar.server.rule.index.RuleQuery;
 import org.sonar.server.tester.ServerTester;
@@ -64,7 +64,7 @@ public class ChangeParentActionMediumTest {
   WsTester wsTester;
   RuleIndexer ruleIndexer;
   ActiveRuleIndexer activeRuleIndexer;
-  RuleIndex2 ruleIndex;
+  RuleIndex ruleIndex;
 
   @Before
   public void setUp() {
@@ -77,7 +77,7 @@ public class ChangeParentActionMediumTest {
     ruleIndexer.setEnabled(true);
     activeRuleIndexer = tester.get(ActiveRuleIndexer.class);
     activeRuleIndexer.setEnabled(true);
-    ruleIndex = tester.get(RuleIndex2.class);
+    ruleIndex = tester.get(RuleIndex.class);
     userSessionRule.login("gandalf").setGlobalPermissions(GlobalPermissions.QUALITY_PROFILE_ADMIN);
   }
 
index d2cbc287147951b6b66ee7c40f6f386f5f1598d8..a641ab0d04864efb77ea71ec234ea86111bbc169 100644 (file)
@@ -47,8 +47,8 @@ import org.sonar.server.qualityprofile.QProfileFactory;
 import org.sonar.server.qualityprofile.QProfileLoader;
 import org.sonar.server.qualityprofile.QProfileTesting;
 import org.sonar.server.qualityprofile.index.ActiveRuleDoc;
-import org.sonar.server.qualityprofile.index.ActiveRuleIndex2;
-import org.sonar.server.rule.index.RuleIndex2;
+import org.sonar.server.qualityprofile.index.ActiveRuleIndex;
+import org.sonar.server.rule.index.RuleIndex;
 import org.sonar.server.ws.WsTester;
 import org.sonar.server.ws.WsTester.Result;
 
@@ -86,10 +86,10 @@ public class ExportActionTest {
     ProfileExporter exporter1 = newExporter("polop");
     ProfileExporter exporter2 = newExporter("palap");
 
-    ActiveRuleIndex2 activeRuleIndex = mock(ActiveRuleIndex2.class);
+    ActiveRuleIndex activeRuleIndex = mock(ActiveRuleIndex.class);
     when(activeRuleIndex.findByProfile(Matchers.anyString())).thenReturn(Sets.<ActiveRuleDoc>newHashSet().iterator());
 
-    exporters = new QProfileExporters(new QProfileLoader(dbClient, activeRuleIndex, mock(RuleIndex2.class)), null, null, new ProfileExporter[] {exporter1, exporter2}, null);
+    exporters = new QProfileExporters(new QProfileLoader(dbClient, activeRuleIndex, mock(RuleIndex.class)), null, null, new ProfileExporter[] {exporter1, exporter2}, null);
     wsTester = new WsTester(new QProfilesWs(mock(RuleActivationActions.class),
       mock(BulkRuleActivationActions.class),
       mock(ProjectAssociationActions.class),
index db80ffe0266d5ebac0b6e61994d56a2cb36a1bde..919d00838966f2ab3e4d7ca00a2d49b37761b3b3 100644 (file)
@@ -43,9 +43,9 @@ import org.sonar.server.exceptions.NotFoundException;
 import org.sonar.server.qualityprofile.QProfileFactory;
 import org.sonar.server.qualityprofile.QProfileName;
 import org.sonar.server.qualityprofile.QProfileTesting;
-import org.sonar.server.qualityprofile.index.ActiveRuleIndex2;
+import org.sonar.server.qualityprofile.index.ActiveRuleIndex;
 import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
-import org.sonar.server.rule.index.RuleIndex2;
+import org.sonar.server.rule.index.RuleIndex;
 import org.sonar.server.rule.index.RuleIndexer;
 import org.sonar.server.rule.index.RuleQuery;
 import org.sonar.server.rule.ws.SearchAction;
@@ -361,7 +361,7 @@ public class QProfilesWsMediumTest {
     assertThat(db.activeRuleDao().selectByProfileKey(session, profile.getKey())).hasSize(0);
 
     // 2. Assert ActiveRule with BLOCKER severity
-    assertThat(tester.get(RuleIndex2.class).search(
+    assertThat(tester.get(RuleIndex.class).search(
       new RuleQuery().setSeverities(ImmutableSet.of("BLOCKER")),
       new SearchOptions()).getIds()).hasSize(2);
 
@@ -373,7 +373,7 @@ public class QProfilesWsMediumTest {
     session.commit();
 
     // 2. Assert ActiveRule with MINOR severity
-    assertThat(tester.get(ActiveRuleIndex2.class).findByRule(rule0.getKey()).get(0).severity()).isEqualTo("MINOR");
+    assertThat(tester.get(ActiveRuleIndex.class).findByRule(rule0.getKey()).get(0).severity()).isEqualTo("MINOR");
 
   }
 
index e7de12119a9e3aba1e11ca65f7a124d68ca2825a..0648192121a529d0987d2fcc15b1902db1828117 100644 (file)
@@ -50,7 +50,7 @@ import org.sonar.server.platform.Platform;
 import org.sonar.server.qualityprofile.QProfileService;
 import org.sonar.server.qualityprofile.QProfileTesting;
 import org.sonar.server.qualityprofile.RuleActivation;
-import org.sonar.server.rule.index.RuleIndex2;
+import org.sonar.server.rule.index.RuleIndex;
 import org.sonar.server.rule.index.RuleQuery;
 import org.sonar.server.tester.ServerTester;
 import org.sonar.server.tester.UserSessionRule;
@@ -75,7 +75,7 @@ public class RegisterRulesMediumTest {
   DbClient db = TESTER.get(DbClient.class);
   DbSession dbSession = TESTER.get(DbClient.class).openSession(false);
 
-  RuleIndex2 ruleIndex = TESTER.get(RuleIndex2.class);
+  RuleIndex ruleIndex = TESTER.get(RuleIndex.class);
   RuleDao ruleDao = db.ruleDao();
 
   @Before
@@ -100,7 +100,7 @@ public class RegisterRulesMediumTest {
     db = TESTER.get(DbClient.class);
     dbSession = TESTER.get(DbClient.class).openSession(false);
     dbSession.clearCache();
-    ruleIndex = TESTER.get(RuleIndex2.class);
+    ruleIndex = TESTER.get(RuleIndex.class);
   }
 
   @Test
index 57aa3b0d02b0eab85f54f7801a1b515db9f8e1ca..f6be4c25a73ca49e9fee2e7d713e53d0189f56e7 100644 (file)
@@ -42,7 +42,7 @@ import org.sonar.db.rule.RuleParamDto;
 import org.sonar.server.es.EsTester;
 import org.sonar.server.es.SearchOptions;
 import org.sonar.server.qualityprofile.RuleActivator;
-import org.sonar.server.rule.index.RuleIndex2;
+import org.sonar.server.rule.index.RuleIndex;
 import org.sonar.server.rule.index.RuleIndexDefinition;
 import org.sonar.server.rule.index.RuleIndexer;
 import org.sonar.server.rule.index.RuleQuery;
@@ -79,7 +79,7 @@ public class RegisterRulesTest {
 
   RuleIndexer ruleIndexer;
 
-  RuleIndex2 ruleIndex;
+  RuleIndex ruleIndex;
 
   @Before
   public void before() {
@@ -87,7 +87,7 @@ public class RegisterRulesTest {
     when(system.now()).thenReturn(DATE1.getTime());
     ruleIndexer = new RuleIndexer(dbClient, esTester.client());
     ruleIndexer.setEnabled(true);
-    ruleIndex = new RuleIndex2(esTester.client());
+    ruleIndex = new RuleIndex(esTester.client());
   }
 
   @Test
index a3ccbff4b1182c63e9f0dea8528eeb5e3fe03936..086f4b2939724eeab55577adf11e9652a588f2bc 100644 (file)
@@ -41,7 +41,7 @@ import org.sonar.db.rule.RuleParamDto;
 import org.sonar.db.rule.RuleTesting;
 import org.sonar.server.es.SearchOptions;
 import org.sonar.server.exceptions.BadRequestException;
-import org.sonar.server.rule.index.RuleIndex2;
+import org.sonar.server.rule.index.RuleIndex;
 import org.sonar.server.rule.index.RuleIndexer;
 import org.sonar.server.rule.index.RuleQuery;
 import org.sonar.server.tester.ServerTester;
@@ -63,7 +63,7 @@ public class RuleCreatorMediumTest {
   DbClient db = tester.get(DbClient.class);
   RuleDao dao = tester.get(RuleDao.class);
   RuleCreator creator = tester.get(RuleCreator.class);
-  RuleIndex2 ruleIndex = tester.get(RuleIndex2.class);
+  RuleIndex ruleIndex = tester.get(RuleIndex.class);
   RuleIndexer ruleIndexer;
 
   @Before
index 5dc32ed171d505c2c20d3a86142cf8f20ffff6a0..e72bf59befc1237008e6f638a68e0ca3d220a05a 100644 (file)
@@ -39,8 +39,8 @@ import org.sonar.server.qualityprofile.QProfileTesting;
 import org.sonar.server.qualityprofile.RuleActivation;
 import org.sonar.server.qualityprofile.RuleActivator;
 import org.sonar.server.qualityprofile.index.ActiveRuleDoc;
-import org.sonar.server.qualityprofile.index.ActiveRuleIndex2;
-import org.sonar.server.rule.index.RuleIndex2;
+import org.sonar.server.qualityprofile.index.ActiveRuleIndex;
+import org.sonar.server.rule.index.RuleIndex;
 import org.sonar.server.rule.index.RuleQuery;
 import org.sonar.server.tester.ServerTester;
 import org.sonar.server.tester.UserSessionRule;
@@ -58,7 +58,7 @@ public class RuleDeleterMediumTest {
 
   DbClient db = tester.get(DbClient.class);
   RuleDao dao = tester.get(RuleDao.class);
-  RuleIndex2 index = tester.get(RuleIndex2.class);
+  RuleIndex index = tester.get(RuleIndex.class);
   RuleDeleter deleter = tester.get(RuleDeleter.class);
   DbSession dbSession = tester.get(DbClient.class).openSession(false);
 
@@ -100,7 +100,7 @@ public class RuleDeleterMediumTest {
     assertThat(customRuleReloaded.getStatus()).isEqualTo(RuleStatus.REMOVED);
 
     // Verify there's no more active rule from custom rule
-    List<ActiveRuleDoc> activeRules = Lists.newArrayList(tester.get(ActiveRuleIndex2.class).findByProfile(profileDto.getKey()));
+    List<ActiveRuleDoc> activeRules = Lists.newArrayList(tester.get(ActiveRuleIndex.class).findByProfile(profileDto.getKey()));
     assertThat(activeRules).isEmpty();
 
     // Verify in index
index 97d06418153bcc08faaf63e7fe134b7e22a6a3d1..098a7f4c222fbbd1a66efe7616678d8760fbe57f 100644 (file)
@@ -37,7 +37,7 @@ import org.sonar.db.rule.RuleDao;
 import org.sonar.db.rule.RuleDto;
 import org.sonar.db.rule.RuleTesting;
 import org.sonar.server.exceptions.UnauthorizedException;
-import org.sonar.server.rule.index.RuleIndex2;
+import org.sonar.server.rule.index.RuleIndex;
 import org.sonar.server.rule.index.RuleIndexDefinition;
 import org.sonar.server.rule.index.RuleIndexer;
 import org.sonar.server.tester.ServerTester;
@@ -54,7 +54,7 @@ public class RuleServiceMediumTest {
   public UserSessionRule userSessionRule = UserSessionRule.forServerTester(tester);
 
   RuleDao dao = tester.get(RuleDao.class);
-  RuleIndex2 index = tester.get(RuleIndex2.class);
+  RuleIndex index = tester.get(RuleIndex.class);
   RuleService service = tester.get(RuleService.class);
   DbSession dbSession;
   RuleIndexer ruleIndexer;
index 59c3f74888cadb0be4a60abc4363e869dc2dcf89..9cbc02b16a1073396cd91149faf936108b2c3dab 100644 (file)
@@ -51,7 +51,7 @@ import org.sonar.server.es.SearchOptions;
 import org.sonar.server.qualityprofile.QProfileTesting;
 import org.sonar.server.qualityprofile.RuleActivation;
 import org.sonar.server.qualityprofile.RuleActivator;
-import org.sonar.server.rule.index.RuleIndex2;
+import org.sonar.server.rule.index.RuleIndex;
 import org.sonar.server.rule.index.RuleQuery;
 import org.sonar.server.tester.ServerTester;
 import org.sonar.server.tester.UserSessionRule;
@@ -73,7 +73,7 @@ public class RuleUpdaterMediumTest {
   DbClient db = tester.get(DbClient.class);
   RuleDao ruleDao = tester.get(RuleDao.class);
   DbSession dbSession = db.openSession(false);
-  RuleIndex2 ruleIndex = tester.get(RuleIndex2.class);
+  RuleIndex ruleIndex = tester.get(RuleIndex.class);
 
   RuleUpdater underTest = tester.get(RuleUpdater.class);
 
diff --git a/server/sonar-server/src/test/java/org/sonar/server/rule/index/RuleIndex2Test.java b/server/sonar-server/src/test/java/org/sonar/server/rule/index/RuleIndex2Test.java
deleted file mode 100644 (file)
index 5884898..0000000
+++ /dev/null
@@ -1,703 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program 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.
- *
- * This program 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.rule.index;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import org.junit.Before;
-import org.junit.ClassRule;
-import org.junit.Test;
-import org.sonar.api.config.Settings;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rule.RuleStatus;
-import org.sonar.db.qualityprofile.ActiveRuleKey;
-import org.sonar.db.rule.RuleTesting;
-import org.sonar.server.es.EsTester;
-import org.sonar.server.es.SearchIdResult;
-import org.sonar.server.es.SearchOptions;
-import org.sonar.server.qualityprofile.index.ActiveRuleDoc;
-import org.sonar.server.qualityprofile.index.ActiveRuleDocTesting;
-import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
-
-import static java.util.Arrays.asList;
-import static java.util.Collections.singleton;
-import static java.util.Collections.singletonList;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.data.MapEntry.entry;
-import static org.junit.Assert.fail;
-import static org.sonar.api.rule.Severity.BLOCKER;
-import static org.sonar.api.rule.Severity.CRITICAL;
-import static org.sonar.api.rule.Severity.INFO;
-import static org.sonar.api.rule.Severity.MAJOR;
-import static org.sonar.api.rule.Severity.MINOR;
-import static org.sonar.server.qualityprofile.ActiveRule.Inheritance.INHERITED;
-import static org.sonar.server.qualityprofile.ActiveRule.Inheritance.OVERRIDES;
-import static org.sonar.server.rule.index.RuleDocTesting.newDoc;
-import static org.sonar.server.rule.index.RuleIndex2.FACET_LANGUAGES;
-import static org.sonar.server.rule.index.RuleIndex2.FACET_REPOSITORIES;
-import static org.sonar.server.rule.index.RuleIndex2.FACET_TAGS;
-import static org.sonar.server.rule.index.RuleIndexDefinition.INDEX;
-import static org.sonar.server.rule.index.RuleIndexDefinition.TYPE_ACTIVE_RULE;
-
-public class RuleIndex2Test {
-
-  static final RuleKey RULE_KEY_1 = RuleTesting.XOO_X1;
-  static final RuleKey RULE_KEY_2 = RuleTesting.XOO_X2;
-  static final RuleKey RULE_KEY_3 = RuleTesting.XOO_X3;
-  static final RuleKey RULE_KEY_4 = RuleKey.of("xoo", "x4");
-
-  static final String QUALITY_PROFILE_KEY1 = "qp1";
-  static final String QUALITY_PROFILE_KEY2 = "qp2";
-
-  @ClassRule
-  public static EsTester tester = new EsTester().addDefinitions(new RuleIndexDefinition(new Settings()));
-
-  RuleIndex2 index;
-
-  RuleIndexer ruleIndexer;
-  ActiveRuleIndexer activeRuleIndexer;
-
-  @Before
-  public void setUp() {
-    tester.truncateIndices();
-    ruleIndexer = new RuleIndexer(null, tester.client());
-    activeRuleIndexer = new ActiveRuleIndexer(null, tester.client());
-    index = new RuleIndex2(tester.client());
-  }
-
-  @Test
-  public void search_all_rules() {
-    indexRules(
-      newDoc(RuleKey.of("javascript", "S001")),
-      newDoc(RuleKey.of("java", "S002")));
-
-    SearchIdResult results = index.search(new RuleQuery(), new SearchOptions());
-
-    assertThat(results.getTotal()).isEqualTo(2);
-    assertThat(results.getIds()).hasSize(2);
-  }
-
-  @Test
-  public void search_key_by_query() {
-    indexRules(
-      newDoc(RuleKey.of("javascript", "X001")),
-      newDoc(RuleKey.of("cobol", "X001")),
-      newDoc(RuleKey.of("php", "S002")));
-
-    // key
-    RuleQuery query = new RuleQuery().setQueryText("X001");
-    assertThat(index.search(query, new SearchOptions()).getIds()).hasSize(2);
-
-    // partial key does not match
-    query = new RuleQuery().setQueryText("X00");
-    assertThat(index.search(query, new SearchOptions()).getIds()).isEmpty();
-
-    // repo:key -> nice-to-have !
-    query = new RuleQuery().setQueryText("javascript:X001");
-    assertThat(index.search(query, new SearchOptions()).getIds()).hasSize(1);
-  }
-
-  @Test
-  public void filter_by_key() {
-    indexRules(
-      newDoc(RuleKey.of("javascript", "X001")),
-      newDoc(RuleKey.of("cobol", "X001")),
-      newDoc(RuleKey.of("php", "S002")));
-
-    // key
-    RuleQuery query = new RuleQuery().setKey(RuleKey.of("javascript", "X001").toString());
-
-    assertThat(index.search(query, new SearchOptions()).getIds()).hasSize(1);
-
-    // partial key does not match
-    query = new RuleQuery().setKey("X001");
-    assertThat(index.search(query, new SearchOptions()).getIds()).isEmpty();
-  }
-
-  @Test
-  public void search_name_by_query() {
-    indexRules(newDoc(RuleKey.of("javascript", "S001"))
-      .setName("testing the partial match and matching of rule"));
-
-    // substring
-    RuleQuery query = new RuleQuery().setQueryText("test");
-    assertThat(index.search(query, new SearchOptions()).getIds()).hasSize(1);
-
-    // substring
-    query = new RuleQuery().setQueryText("partial match");
-    assertThat(index.search(query, new SearchOptions()).getIds()).hasSize(1);
-
-    // case-insensitive
-    query = new RuleQuery().setQueryText("TESTING");
-    assertThat(index.search(query, new SearchOptions()).getIds()).hasSize(1);
-
-    // not found
-    query = new RuleQuery().setQueryText("not present");
-    assertThat(index.search(query, new SearchOptions()).getIds()).isEmpty();
-  }
-
-  @Test
-  public void search_name_with_protected_chars() {
-    String nameWithProtectedChars = "ja#va&sc\"r:ipt";
-
-    indexRules(newDoc(RuleKey.of("javascript", "S001"))
-      .setName(nameWithProtectedChars));
-
-    RuleQuery protectedCharsQuery = new RuleQuery().setQueryText(nameWithProtectedChars);
-    List<RuleKey> results = index.search(protectedCharsQuery, new SearchOptions()).getIds();
-    assertThat(results).containsOnly(RuleKey.of("javascript", "S001"));
-  }
-
-  @Test
-  public void search_by_any_of_repositories() {
-    indexRules(
-      newDoc(RuleKey.of("findbugs", "S001")),
-      newDoc(RuleKey.of("pmd", "S002")));
-
-    RuleQuery query = new RuleQuery().setRepositories(asList("checkstyle", "pmd"));
-    SearchIdResult results = index.search(query, new SearchOptions());
-    assertThat(results.getIds()).containsOnly(RuleKey.of("pmd", "S002"));
-
-    // no results
-    query = new RuleQuery().setRepositories(singletonList("checkstyle"));
-    assertThat(index.search(query, new SearchOptions()).getIds()).isEmpty();
-
-    // empty list => no filter
-    query = new RuleQuery().setRepositories(Collections.<String>emptyList());
-    assertThat(index.search(query, new SearchOptions()).getIds()).hasSize(2);
-  }
-
-  @Test
-  public void search_by_tag() {
-    indexRules(
-      newDoc(RuleKey.of("java", "S001")).setAllTags(singleton("tag1")),
-      newDoc(RuleKey.of("java", "S002")).setAllTags(singleton("tag2")));
-
-    // find all
-    RuleQuery query = new RuleQuery();
-    assertThat(index.search(query, new SearchOptions()).getIds()).hasSize(2);
-
-    // tag1 in query
-    query = new RuleQuery().setQueryText("tag1");
-    assertThat(index.search(query, new SearchOptions()).getIds()).containsOnly(RuleKey.of("java", "S001"));
-
-    // tag1 and tag2 in query
-    query = new RuleQuery().setQueryText("tag1 tag2");
-    assertThat(index.search(query, new SearchOptions()).getIds()).hasSize(2);
-
-    // tag2 in filter
-    query = new RuleQuery().setTags(ImmutableSet.of("tag2"));
-    assertThat(index.search(query, new SearchOptions()).getIds()).containsOnly(RuleKey.of("java", "S002"));
-
-    // tag2 in filter and tag1 tag2 in query
-    query = new RuleQuery().setTags(ImmutableSet.of("tag2")).setQueryText("tag1");
-    assertThat(index.search(query, new SearchOptions()).getIds()).hasSize(0);
-
-    // tag2 in filter and tag1 in query
-    query = new RuleQuery().setTags(ImmutableSet.of("tag2")).setQueryText("tag1 tag2");
-    assertThat(index.search(query, new SearchOptions()).getIds()).containsOnly(RuleKey.of("java", "S002"));
-
-    // null list => no filter
-    query = new RuleQuery().setTags(Collections.<String>emptySet());
-    assertThat(index.search(query, new SearchOptions()).getIds()).hasSize(2);
-
-    // null list => no filter
-    query = new RuleQuery().setTags(null);
-    assertThat(index.search(query, new SearchOptions()).getIds()).hasSize(2);
-  }
-
-  @Test
-  public void search_by_is_template() {
-    indexRules(
-      newDoc(RuleKey.of("java", "S001")).setIsTemplate(false),
-      newDoc(RuleKey.of("java", "S002")).setIsTemplate(true));
-
-    // find all
-    RuleQuery query = new RuleQuery();
-    SearchIdResult results = index.search(query, new SearchOptions());
-    assertThat(results.getIds()).hasSize(2);
-
-    // Only template
-    query = new RuleQuery().setIsTemplate(true);
-    results = index.search(query, new SearchOptions());
-    assertThat(results.getIds()).containsOnly(RuleKey.of("java", "S002"));
-
-    // Only not template
-    query = new RuleQuery().setIsTemplate(false);
-    results = index.search(query, new SearchOptions());
-    assertThat(results.getIds()).containsOnly(RuleKey.of("java", "S001"));
-
-    // null => no filter
-    query = new RuleQuery().setIsTemplate(null);
-    assertThat(index.search(query, new SearchOptions()).getIds()).hasSize(2);
-  }
-
-  @Test
-  public void search_by_template_key() {
-    indexRules(
-      newDoc(RuleKey.of("java", "S001")).setIsTemplate(true),
-      newDoc(RuleKey.of("java", "S001_MY_CUSTOM")).setTemplateKey("java:S001"));
-
-    // find all
-    RuleQuery query = new RuleQuery();
-    SearchIdResult results = index.search(query, new SearchOptions());
-    assertThat(results.getIds()).hasSize(2);
-
-    // Only custom rule
-    query = new RuleQuery().setTemplateKey("java:S001");
-    results = index.search(query, new SearchOptions());
-    assertThat(results.getIds()).containsOnly(RuleKey.of("java", "S001_MY_CUSTOM"));
-
-    // null => no filter
-    query = new RuleQuery().setTemplateKey(null);
-    assertThat(index.search(query, new SearchOptions()).getIds()).hasSize(2);
-  }
-
-  @Test
-  public void search_by_any_of_languages() {
-    indexRules(
-      newDoc(RuleKey.of("java", "S001")).setLanguage("java"),
-      newDoc(RuleKey.of("javascript", "S002")).setLanguage("js"));
-
-    RuleQuery query = new RuleQuery().setLanguages(asList("cobol", "js"));
-    SearchIdResult results = index.search(query, new SearchOptions());
-    assertThat(results.getIds()).containsOnly(RuleKey.of("javascript", "S002"));
-
-    // no results
-    query = new RuleQuery().setLanguages(singletonList("cpp"));
-    assertThat(index.search(query, new SearchOptions()).getIds()).isEmpty();
-
-    // empty list => no filter
-    query = new RuleQuery().setLanguages(Collections.<String>emptyList());
-    assertThat(index.search(query, new SearchOptions()).getIds()).hasSize(2);
-
-    // null list => no filter
-    query = new RuleQuery().setLanguages(null);
-    assertThat(index.search(query, new SearchOptions()).getIds()).hasSize(2);
-  }
-
-  @Test
-  public void search_by_any_of_severities() {
-    indexRules(
-      newDoc(RuleKey.of("java", "S001")).setSeverity(BLOCKER),
-      newDoc(RuleKey.of("java", "S002")).setSeverity(INFO));
-
-    RuleQuery query = new RuleQuery().setSeverities(asList(INFO, MINOR));
-    SearchIdResult results = index.search(query, new SearchOptions());
-    assertThat(results.getIds()).containsOnly(RuleKey.of("java", "S002"));
-
-    // no results
-    query = new RuleQuery().setSeverities(singletonList(MINOR));
-    assertThat(index.search(query, new SearchOptions()).getIds()).isEmpty();
-
-    // empty list => no filter
-    query = new RuleQuery().setSeverities(Collections.<String>emptyList());
-    assertThat(index.search(query, new SearchOptions()).getIds()).hasSize(2);
-
-    // null list => no filter
-    query = new RuleQuery().setSeverities();
-    assertThat(index.search(query, new SearchOptions()).getIds()).hasSize(2);
-  }
-
-  @Test
-  public void search_by_any_of_statuses() {
-    indexRules(
-      newDoc(RuleKey.of("java", "S001")).setStatus(RuleStatus.BETA.name()),
-      newDoc(RuleKey.of("java", "S002")).setStatus(RuleStatus.READY.name()));
-
-    RuleQuery query = new RuleQuery().setStatuses(asList(RuleStatus.DEPRECATED, RuleStatus.READY));
-    SearchIdResult<RuleKey> results = index.search(query, new SearchOptions());
-    assertThat(results.getIds()).containsOnly(RuleKey.of("java", "S002"));
-
-    // no results
-    query = new RuleQuery().setStatuses(singletonList(RuleStatus.DEPRECATED));
-    assertThat(index.search(query, new SearchOptions()).getIds()).isEmpty();
-
-    // empty list => no filter
-    query = new RuleQuery().setStatuses(Collections.<RuleStatus>emptyList());
-    assertThat(index.search(query, new SearchOptions()).getIds()).hasSize(2);
-
-    // null list => no filter
-    query = new RuleQuery().setStatuses(null);
-    assertThat(index.search(query, new SearchOptions()).getIds()).hasSize(2);
-  }
-
-  @Test
-  public void search_by_profile() throws InterruptedException {
-    indexRules(
-      newDoc(RULE_KEY_1),
-      newDoc(RULE_KEY_2),
-      newDoc(RULE_KEY_3));
-
-    indexActiveRules(
-      ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_1)),
-      ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY2, RULE_KEY_1)),
-      ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_2)));
-
-    assertThat(tester.countDocuments(INDEX, TYPE_ACTIVE_RULE)).isEqualTo(3);
-
-    // 1. get all active rules.
-    assertThat(index.search(new RuleQuery().setActivation(true), new SearchOptions()).getIds())
-      .containsOnly(RULE_KEY_1, RULE_KEY_2);
-
-    // 2. get all inactive rules.
-    assertThat(index.search(new RuleQuery().setActivation(false), new SearchOptions()).getIds())
-      .containsOnly(RULE_KEY_3);
-
-    // 3. get all rules not active on profile
-    assertThat(index.search(new RuleQuery().setActivation(false).setQProfileKey(QUALITY_PROFILE_KEY2), new SearchOptions()).getIds())
-      .containsOnly(RULE_KEY_2, RULE_KEY_3);
-
-    // 4. get all active rules on profile
-    assertThat(index.search(new RuleQuery().setActivation(true).setQProfileKey(QUALITY_PROFILE_KEY2), new SearchOptions()).getIds())
-      .containsOnly(RULE_KEY_1);
-  }
-
-  @Test
-  public void search_by_profile_and_inheritance() {
-    indexRules(
-      newDoc(RULE_KEY_1),
-      newDoc(RULE_KEY_2),
-      newDoc(RULE_KEY_3),
-      newDoc(RULE_KEY_4));
-
-    ActiveRuleKey activeRuleKey1 = ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_1);
-    ActiveRuleKey activeRuleKey2 = ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_2);
-    ActiveRuleKey activeRuleKey3 = ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_3);
-
-    indexActiveRules(
-      ActiveRuleDocTesting.newDoc(activeRuleKey1),
-      ActiveRuleDocTesting.newDoc(activeRuleKey2),
-      ActiveRuleDocTesting.newDoc(activeRuleKey3),
-      // Profile 2 is a child a profile 1
-      ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY2, RULE_KEY_1))
-        .setParentKey(activeRuleKey1.toString()).setInheritance(INHERITED.name()),
-      ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY2, RULE_KEY_2))
-        .setParentKey(activeRuleKey2.toString()).setInheritance(OVERRIDES.name()),
-      ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY2, RULE_KEY_3))
-        .setParentKey(activeRuleKey3.toString()).setInheritance(INHERITED.name()));
-
-    // 0. get all rules
-    assertThat(index.search(new RuleQuery(), new SearchOptions()).getIds())
-      .hasSize(4);
-
-    // 1. get all active rules
-    assertThat(index.search(new RuleQuery()
-      .setActivation(true), new SearchOptions()).getIds())
-      .hasSize(3);
-
-    // 2. get all inactive rules.
-    assertThat(index.search(new RuleQuery()
-      .setActivation(false), new SearchOptions()).getIds())
-      .containsOnly(RULE_KEY_4);
-
-    // 3. get Inherited Rules on profile1
-    assertThat(index.search(new RuleQuery().setActivation(true)
-      .setQProfileKey(QUALITY_PROFILE_KEY1)
-      .setInheritance(ImmutableSet.of(INHERITED.name())),
-      new SearchOptions()).getIds())
-      .isEmpty();
-
-    // 4. get Inherited Rules on profile2
-    assertThat(index.search(new RuleQuery().setActivation(true)
-      .setQProfileKey(QUALITY_PROFILE_KEY2)
-      .setInheritance(ImmutableSet.of(INHERITED.name())),
-      new SearchOptions()).getIds())
-      .hasSize(2);
-
-    // 5. get Overridden Rules on profile1
-    assertThat(index.search(new RuleQuery().setActivation(true)
-      .setQProfileKey(QUALITY_PROFILE_KEY1)
-      .setInheritance(ImmutableSet.of(OVERRIDES.name())),
-      new SearchOptions()).getIds())
-      .isEmpty();
-
-    // 6. get Overridden Rules on profile2
-    assertThat(index.search(new RuleQuery().setActivation(true)
-      .setQProfileKey(QUALITY_PROFILE_KEY2)
-      .setInheritance(ImmutableSet.of(OVERRIDES.name())),
-      new SearchOptions()).getIds())
-      .hasSize(1);
-
-    // 7. get Inherited AND Overridden Rules on profile1
-    assertThat(index.search(new RuleQuery().setActivation(true)
-      .setQProfileKey(QUALITY_PROFILE_KEY1)
-      .setInheritance(ImmutableSet.of(INHERITED.name(), OVERRIDES.name())),
-      new SearchOptions()).getIds())
-      .isEmpty();
-
-    // 8. get Inherited AND Overridden Rules on profile2
-    assertThat(index.search(new RuleQuery().setActivation(true)
-      .setQProfileKey(QUALITY_PROFILE_KEY2)
-      .setInheritance(ImmutableSet.of(INHERITED.name(), OVERRIDES.name())),
-      new SearchOptions()).getIds())
-      .hasSize(3);
-  }
-
-  @Test
-  public void search_by_profile_and_active_severity() {
-    indexRules(
-      newDoc(RULE_KEY_1).setSeverity(MAJOR),
-      newDoc(RULE_KEY_2).setSeverity(MINOR),
-      newDoc(RULE_KEY_3).setSeverity(INFO));
-
-    indexActiveRules(
-      ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_1)).setSeverity(BLOCKER),
-      ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY2, RULE_KEY_1)).setSeverity(BLOCKER),
-      ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_2)).setSeverity(CRITICAL));
-
-    // 1. get all active rules.
-    assertThat(index.search(new RuleQuery().setActivation(true).setQProfileKey(QUALITY_PROFILE_KEY1), new SearchOptions()).getIds())
-      .hasSize(2);
-
-    // 2. get rules with active severity critical.
-    SearchIdResult<RuleKey> result = index.search(new RuleQuery().setActivation(true)
-      .setQProfileKey(QUALITY_PROFILE_KEY1).setActiveSeverities(singletonList(CRITICAL)),
-      new SearchOptions().addFacets(singletonList(RuleIndex2.FACET_ACTIVE_SEVERITIES)));
-    assertThat(result.getIds()).containsOnly(RULE_KEY_2);
-
-    // check stickyness of active severity facet
-    assertThat(result.getFacets().get(RuleIndex2.FACET_ACTIVE_SEVERITIES)).containsOnly(entry(BLOCKER, 1L), entry(CRITICAL, 1L));
-
-    // 3. count activation severities of all active rules
-    result = index.search(new RuleQuery(), new SearchOptions().addFacets(singletonList(RuleIndex2.FACET_ACTIVE_SEVERITIES)));
-    assertThat(result.getIds()).hasSize(3);
-    assertThat(result.getFacets().get(RuleIndex2.FACET_ACTIVE_SEVERITIES)).containsOnly(entry(BLOCKER, 2L), entry(CRITICAL, 1L));
-  }
-
-  @Test
-  public void all_tags() {
-    indexRules(
-      newDoc(RuleKey.of("java", "S001")).setAllTags(asList("tag1", "sys1", "sys2")),
-      newDoc(RuleKey.of("java", "S002")).setAllTags(asList("tag2")));
-
-    assertThat(index.terms(RuleIndexDefinition.FIELD_RULE_ALL_TAGS, null, 10)).containsOnly("tag1", "tag2", "sys1", "sys2");
-  }
-
-  @Test
-  public void available_since() throws InterruptedException {
-    indexRules(
-      newDoc(RuleKey.of("java", "S001")).setCreatedAt(1000L),
-      newDoc(RuleKey.of("java", "S002")).setCreatedAt(2000L));
-
-    // 0. find all rules;
-    assertThat(index.search(new RuleQuery(), new SearchOptions()).getIds()).hasSize(2);
-
-    // 1. find all rules available since a date;
-    RuleQuery availableSinceQuery = new RuleQuery().setAvailableSince(2000L);
-    assertThat(index.search(availableSinceQuery, new SearchOptions()).getIds()).containsOnly(RuleKey.of("java", "S002"));
-
-    // 2. find no new rules since tomorrow.
-    RuleQuery availableSinceNowQuery = new RuleQuery().setAvailableSince(3000L);
-    assertThat(index.search(availableSinceNowQuery, new SearchOptions()).getIds()).hasSize(0);
-  }
-
-  @Test
-  public void global_facet_on_repositories_and_tags() {
-    indexRules(
-      newDoc(RuleKey.of("php", "S001")).setAllTags(singletonList("sysTag")),
-      newDoc(RuleKey.of("php", "S002")).setAllTags(singletonList("tag1")),
-      newDoc(RuleKey.of("javascript", "S002")).setAllTags(asList("tag1", "tag2")));
-
-    // should not have any facet!
-    RuleQuery query = new RuleQuery();
-    SearchIdResult result = index.search(query, new SearchOptions());
-    assertThat(result.getFacets().getAll()).isEmpty();
-
-    // should not have any facet on non matching query!
-    result = index.search(new RuleQuery().setQueryText("aeiou"), new SearchOptions().addFacets(singletonList("repositories")));
-    assertThat(result.getFacets().getAll()).hasSize(1);
-    assertThat(result.getFacets().getAll().get("repositories")).isEmpty();
-
-    // Repositories Facet is preset
-    result = index.search(query, new SearchOptions().addFacets(asList("repositories", "tags")));
-    assertThat(result.getFacets()).isNotNull();
-    assertThat(result.getFacets().getAll()).hasSize(2);
-
-    // Verify the value of a given facet
-    Map<String, Long> repoFacets = result.getFacets().get("repositories");
-    assertThat(repoFacets).containsOnly(entry("php", 2L), entry("javascript", 1L));
-
-    // Check that tag facet has both Tags and SystemTags values
-    Map<String, Long> tagFacets = result.getFacets().get("tags");
-    assertThat(tagFacets).containsOnly(entry("tag1", 2L), entry("sysTag", 1L), entry("tag2", 1L));
-  }
-
-  @Test
-  public void sticky_facets() {
-    indexRules(
-      newDoc(RuleKey.of("xoo", "S001")).setLanguage("java").setAllTags(Collections.<String>emptyList()),
-      newDoc(RuleKey.of("xoo", "S002")).setLanguage("java").setAllTags(Collections.<String>emptyList()),
-      newDoc(RuleKey.of("xoo", "S003")).setLanguage("java").setAllTags(asList("T1", "T2")),
-      newDoc(RuleKey.of("xoo", "S011")).setLanguage("cobol").setAllTags(Collections.<String>emptyList()),
-      newDoc(RuleKey.of("xoo", "S012")).setLanguage("cobol").setAllTags(Collections.<String>emptyList()),
-      newDoc(RuleKey.of("foo", "S013")).setLanguage("cobol").setAllTags(asList("T3", "T4")),
-      newDoc(RuleKey.of("foo", "S111")).setLanguage("cpp").setAllTags(Collections.<String>emptyList()),
-      newDoc(RuleKey.of("foo", "S112")).setLanguage("cpp").setAllTags(Collections.<String>emptyList()),
-      newDoc(RuleKey.of("foo", "S113")).setLanguage("cpp").setAllTags(asList("T2", "T3")));
-
-    // 0 assert Base
-    assertThat(index.search(new RuleQuery(), new SearchOptions()).getIds()).hasSize(9);
-
-    // 1 Facet with no filters at all
-    SearchIdResult result = index.search(new RuleQuery(), new SearchOptions().addFacets(asList("languages", "repositories", "tags")));
-    assertThat(result.getFacets().getAll()).hasSize(3);
-    assertThat(result.getFacets().getAll().get(FACET_LANGUAGES).keySet()).containsOnly("cpp", "java", "cobol");
-    assertThat(result.getFacets().getAll().get(FACET_REPOSITORIES).keySet()).containsOnly("xoo", "foo");
-    assertThat(result.getFacets().getAll().get(FACET_TAGS).keySet()).containsOnly("T1", "T2", "T3", "T4");
-
-    // 2 Facet with a language filter
-    // -- lang facet should still have all language
-    result = index.search(new RuleQuery().setLanguages(ImmutableList.of("cpp"))
-      , new SearchOptions().addFacets(asList("languages", "repositories", "tags")));
-    assertThat(result.getIds()).hasSize(3);
-    assertThat(result.getFacets().getAll()).hasSize(3);
-    assertThat(result.getFacets().get(FACET_LANGUAGES).keySet()).containsOnly("cpp", "java", "cobol");
-
-    // 3 facet with 2 filters
-    // -- lang facet for tag T2
-    // -- tag facet for lang cpp
-    // -- repository for cpp & T2
-    result = index.search(new RuleQuery()
-      .setLanguages(ImmutableList.of("cpp"))
-      .setTags(ImmutableList.of("T2"))
-      , new SearchOptions().addFacets(asList("languages", "repositories", "tags")));
-    assertThat(result.getIds()).hasSize(1);
-    assertThat(result.getFacets().getAll()).hasSize(3);
-    assertThat(result.getFacets().get(FACET_LANGUAGES).keySet()).containsOnly("cpp", "java");
-    assertThat(result.getFacets().get(FACET_REPOSITORIES).keySet()).containsOnly("foo");
-    assertThat(result.getFacets().get(FACET_TAGS).keySet()).containsOnly("T2", "T3");
-
-    // 4 facet with 2 filters
-    // -- lang facet for tag T2
-    // -- tag facet for lang cpp & java
-    // -- repository for (cpp || java) & T2
-    result = index.search(new RuleQuery()
-      .setLanguages(ImmutableList.of("cpp", "java"))
-      .setTags(ImmutableList.of("T2"))
-      , new SearchOptions().addFacets(asList("languages", "repositories", "tags")));
-    assertThat(result.getIds()).hasSize(2);
-    assertThat(result.getFacets().getAll()).hasSize(3);
-    assertThat(result.getFacets().get(FACET_LANGUAGES).keySet()).containsOnly("cpp", "java");
-    assertThat(result.getFacets().get(FACET_REPOSITORIES).keySet()).containsOnly("foo", "xoo");
-    assertThat(result.getFacets().get(FACET_TAGS).keySet()).containsOnly("T1", "T2", "T3");
-  }
-
-  @Test
-  public void sort_by_name() {
-    indexRules(
-      newDoc(RuleKey.of("java", "S001")).setName("abcd"),
-      newDoc(RuleKey.of("java", "S002")).setName("ABC"),
-      newDoc(RuleKey.of("java", "S003")).setName("FGH"));
-
-    // ascending
-    RuleQuery query = new RuleQuery().setSortField(RuleIndexDefinition.FIELD_RULE_NAME);
-    SearchIdResult<RuleKey> results = index.search(query, new SearchOptions());
-    assertThat(results.getIds()).containsExactly(RuleKey.of("java", "S002"), RuleKey.of("java", "S001"), RuleKey.of("java", "S003"));
-
-    // descending
-    query = new RuleQuery().setSortField(RuleIndexDefinition.FIELD_RULE_NAME).setAscendingSort(false);
-    results = index.search(query, new SearchOptions());
-    assertThat(results.getIds()).containsExactly(RuleKey.of("java", "S003"), RuleKey.of("java", "S001"), RuleKey.of("java", "S002"));
-  }
-
-  @Test
-  public void default_sort_is_by_updated_at_desc() {
-    indexRules(
-      newDoc(RuleKey.of("java", "S001")).setCreatedAt(1000L).setUpdatedAt(1000L),
-      newDoc(RuleKey.of("java", "S002")).setCreatedAt(1000L).setUpdatedAt(3000L),
-      newDoc(RuleKey.of("java", "S003")).setCreatedAt(1000L).setUpdatedAt(2000L));
-
-    SearchIdResult<RuleKey> results = index.search(new RuleQuery(), new SearchOptions());
-    assertThat(results.getIds()).containsExactly(RuleKey.of("java", "S002"), RuleKey.of("java", "S003"), RuleKey.of("java", "S001"));
-  }
-
-  @Test
-  public void fail_sort_by_language() {
-    try {
-      // Sorting on a field not tagged as sortable
-      new RuleQuery().setSortField(RuleIndexDefinition.FIELD_RULE_LANGUAGE);
-      fail();
-    } catch (IllegalStateException e) {
-      assertThat(e).hasMessage("Field 'lang' is not sortable");
-    }
-  }
-
-  @Test
-  public void paging() {
-    indexRules(
-      newDoc(RuleKey.of("java", "S001")),
-      newDoc(RuleKey.of("java", "S002")),
-      newDoc(RuleKey.of("java", "S003")));
-
-    // from 0 to 1 included
-    SearchOptions options = new SearchOptions();
-    options.setOffset(0).setLimit(2);
-    SearchIdResult results = index.search(new RuleQuery(), options);
-    assertThat(results.getTotal()).isEqualTo(3);
-    assertThat(results.getIds()).hasSize(2);
-
-    // from 0 to 9 included
-    options.setOffset(0).setLimit(10);
-    results = index.search(new RuleQuery(), options);
-    assertThat(results.getTotal()).isEqualTo(3);
-    assertThat(results.getIds()).hasSize(3);
-
-    // from 2 to 11 included
-    options.setOffset(2).setLimit(10);
-    results = index.search(new RuleQuery(), options);
-    assertThat(results.getTotal()).isEqualTo(3);
-    assertThat(results.getIds()).hasSize(1);
-
-    // from 2 to 11 included
-    options.setOffset(2).setLimit(0);
-    results = index.search(new RuleQuery(), options);
-    assertThat(results.getTotal()).isEqualTo(3);
-    assertThat(results.getIds()).hasSize(1);
-  }
-
-  @Test
-  public void search_all_keys_by_query() {
-    indexRules(
-      newDoc(RuleKey.of("javascript", "X001")),
-      newDoc(RuleKey.of("cobol", "X001")),
-      newDoc(RuleKey.of("php", "S002")));
-
-    // key
-    assertThat(index.searchAll(new RuleQuery().setQueryText("X001"))).hasSize(2);
-
-    // partial key does not match
-    assertThat(index.searchAll(new RuleQuery().setQueryText("X00"))).isEmpty();
-
-    // repo:key -> nice-to-have !
-    assertThat(index.searchAll(new RuleQuery().setQueryText("javascript:X001"))).hasSize(1);
-  }
-
-  private void indexRules(RuleDoc... rules) {
-    ruleIndexer.index(asList(rules).iterator());
-  }
-
-  private void indexActiveRules(ActiveRuleDoc... docs) {
-    activeRuleIndexer.index(asList(docs).iterator());
-  }
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/rule/index/RuleIndexTest.java b/server/sonar-server/src/test/java/org/sonar/server/rule/index/RuleIndexTest.java
new file mode 100644 (file)
index 0000000..7c1c9d9
--- /dev/null
@@ -0,0 +1,703 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program 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.rule.index;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.sonar.api.config.Settings;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rule.RuleStatus;
+import org.sonar.db.qualityprofile.ActiveRuleKey;
+import org.sonar.db.rule.RuleTesting;
+import org.sonar.server.es.EsTester;
+import org.sonar.server.es.SearchIdResult;
+import org.sonar.server.es.SearchOptions;
+import org.sonar.server.qualityprofile.index.ActiveRuleDoc;
+import org.sonar.server.qualityprofile.index.ActiveRuleDocTesting;
+import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
+
+import static java.util.Arrays.asList;
+import static java.util.Collections.singleton;
+import static java.util.Collections.singletonList;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.data.MapEntry.entry;
+import static org.junit.Assert.fail;
+import static org.sonar.api.rule.Severity.BLOCKER;
+import static org.sonar.api.rule.Severity.CRITICAL;
+import static org.sonar.api.rule.Severity.INFO;
+import static org.sonar.api.rule.Severity.MAJOR;
+import static org.sonar.api.rule.Severity.MINOR;
+import static org.sonar.server.qualityprofile.ActiveRule.Inheritance.INHERITED;
+import static org.sonar.server.qualityprofile.ActiveRule.Inheritance.OVERRIDES;
+import static org.sonar.server.rule.index.RuleDocTesting.newDoc;
+import static org.sonar.server.rule.index.RuleIndex.FACET_LANGUAGES;
+import static org.sonar.server.rule.index.RuleIndex.FACET_REPOSITORIES;
+import static org.sonar.server.rule.index.RuleIndex.FACET_TAGS;
+import static org.sonar.server.rule.index.RuleIndexDefinition.INDEX;
+import static org.sonar.server.rule.index.RuleIndexDefinition.TYPE_ACTIVE_RULE;
+
+public class RuleIndexTest {
+
+  static final RuleKey RULE_KEY_1 = RuleTesting.XOO_X1;
+  static final RuleKey RULE_KEY_2 = RuleTesting.XOO_X2;
+  static final RuleKey RULE_KEY_3 = RuleTesting.XOO_X3;
+  static final RuleKey RULE_KEY_4 = RuleKey.of("xoo", "x4");
+
+  static final String QUALITY_PROFILE_KEY1 = "qp1";
+  static final String QUALITY_PROFILE_KEY2 = "qp2";
+
+  @ClassRule
+  public static EsTester tester = new EsTester().addDefinitions(new RuleIndexDefinition(new Settings()));
+
+  RuleIndex index;
+
+  RuleIndexer ruleIndexer;
+  ActiveRuleIndexer activeRuleIndexer;
+
+  @Before
+  public void setUp() {
+    tester.truncateIndices();
+    ruleIndexer = new RuleIndexer(null, tester.client());
+    activeRuleIndexer = new ActiveRuleIndexer(null, tester.client());
+    index = new RuleIndex(tester.client());
+  }
+
+  @Test
+  public void search_all_rules() {
+    indexRules(
+      newDoc(RuleKey.of("javascript", "S001")),
+      newDoc(RuleKey.of("java", "S002")));
+
+    SearchIdResult results = index.search(new RuleQuery(), new SearchOptions());
+
+    assertThat(results.getTotal()).isEqualTo(2);
+    assertThat(results.getIds()).hasSize(2);
+  }
+
+  @Test
+  public void search_key_by_query() {
+    indexRules(
+      newDoc(RuleKey.of("javascript", "X001")),
+      newDoc(RuleKey.of("cobol", "X001")),
+      newDoc(RuleKey.of("php", "S002")));
+
+    // key
+    RuleQuery query = new RuleQuery().setQueryText("X001");
+    assertThat(index.search(query, new SearchOptions()).getIds()).hasSize(2);
+
+    // partial key does not match
+    query = new RuleQuery().setQueryText("X00");
+    assertThat(index.search(query, new SearchOptions()).getIds()).isEmpty();
+
+    // repo:key -> nice-to-have !
+    query = new RuleQuery().setQueryText("javascript:X001");
+    assertThat(index.search(query, new SearchOptions()).getIds()).hasSize(1);
+  }
+
+  @Test
+  public void filter_by_key() {
+    indexRules(
+      newDoc(RuleKey.of("javascript", "X001")),
+      newDoc(RuleKey.of("cobol", "X001")),
+      newDoc(RuleKey.of("php", "S002")));
+
+    // key
+    RuleQuery query = new RuleQuery().setKey(RuleKey.of("javascript", "X001").toString());
+
+    assertThat(index.search(query, new SearchOptions()).getIds()).hasSize(1);
+
+    // partial key does not match
+    query = new RuleQuery().setKey("X001");
+    assertThat(index.search(query, new SearchOptions()).getIds()).isEmpty();
+  }
+
+  @Test
+  public void search_name_by_query() {
+    indexRules(newDoc(RuleKey.of("javascript", "S001"))
+      .setName("testing the partial match and matching of rule"));
+
+    // substring
+    RuleQuery query = new RuleQuery().setQueryText("test");
+    assertThat(index.search(query, new SearchOptions()).getIds()).hasSize(1);
+
+    // substring
+    query = new RuleQuery().setQueryText("partial match");
+    assertThat(index.search(query, new SearchOptions()).getIds()).hasSize(1);
+
+    // case-insensitive
+    query = new RuleQuery().setQueryText("TESTING");
+    assertThat(index.search(query, new SearchOptions()).getIds()).hasSize(1);
+
+    // not found
+    query = new RuleQuery().setQueryText("not present");
+    assertThat(index.search(query, new SearchOptions()).getIds()).isEmpty();
+  }
+
+  @Test
+  public void search_name_with_protected_chars() {
+    String nameWithProtectedChars = "ja#va&sc\"r:ipt";
+
+    indexRules(newDoc(RuleKey.of("javascript", "S001"))
+      .setName(nameWithProtectedChars));
+
+    RuleQuery protectedCharsQuery = new RuleQuery().setQueryText(nameWithProtectedChars);
+    List<RuleKey> results = index.search(protectedCharsQuery, new SearchOptions()).getIds();
+    assertThat(results).containsOnly(RuleKey.of("javascript", "S001"));
+  }
+
+  @Test
+  public void search_by_any_of_repositories() {
+    indexRules(
+      newDoc(RuleKey.of("findbugs", "S001")),
+      newDoc(RuleKey.of("pmd", "S002")));
+
+    RuleQuery query = new RuleQuery().setRepositories(asList("checkstyle", "pmd"));
+    SearchIdResult results = index.search(query, new SearchOptions());
+    assertThat(results.getIds()).containsOnly(RuleKey.of("pmd", "S002"));
+
+    // no results
+    query = new RuleQuery().setRepositories(singletonList("checkstyle"));
+    assertThat(index.search(query, new SearchOptions()).getIds()).isEmpty();
+
+    // empty list => no filter
+    query = new RuleQuery().setRepositories(Collections.<String>emptyList());
+    assertThat(index.search(query, new SearchOptions()).getIds()).hasSize(2);
+  }
+
+  @Test
+  public void search_by_tag() {
+    indexRules(
+      newDoc(RuleKey.of("java", "S001")).setAllTags(singleton("tag1")),
+      newDoc(RuleKey.of("java", "S002")).setAllTags(singleton("tag2")));
+
+    // find all
+    RuleQuery query = new RuleQuery();
+    assertThat(index.search(query, new SearchOptions()).getIds()).hasSize(2);
+
+    // tag1 in query
+    query = new RuleQuery().setQueryText("tag1");
+    assertThat(index.search(query, new SearchOptions()).getIds()).containsOnly(RuleKey.of("java", "S001"));
+
+    // tag1 and tag2 in query
+    query = new RuleQuery().setQueryText("tag1 tag2");
+    assertThat(index.search(query, new SearchOptions()).getIds()).hasSize(2);
+
+    // tag2 in filter
+    query = new RuleQuery().setTags(ImmutableSet.of("tag2"));
+    assertThat(index.search(query, new SearchOptions()).getIds()).containsOnly(RuleKey.of("java", "S002"));
+
+    // tag2 in filter and tag1 tag2 in query
+    query = new RuleQuery().setTags(ImmutableSet.of("tag2")).setQueryText("tag1");
+    assertThat(index.search(query, new SearchOptions()).getIds()).hasSize(0);
+
+    // tag2 in filter and tag1 in query
+    query = new RuleQuery().setTags(ImmutableSet.of("tag2")).setQueryText("tag1 tag2");
+    assertThat(index.search(query, new SearchOptions()).getIds()).containsOnly(RuleKey.of("java", "S002"));
+
+    // null list => no filter
+    query = new RuleQuery().setTags(Collections.<String>emptySet());
+    assertThat(index.search(query, new SearchOptions()).getIds()).hasSize(2);
+
+    // null list => no filter
+    query = new RuleQuery().setTags(null);
+    assertThat(index.search(query, new SearchOptions()).getIds()).hasSize(2);
+  }
+
+  @Test
+  public void search_by_is_template() {
+    indexRules(
+      newDoc(RuleKey.of("java", "S001")).setIsTemplate(false),
+      newDoc(RuleKey.of("java", "S002")).setIsTemplate(true));
+
+    // find all
+    RuleQuery query = new RuleQuery();
+    SearchIdResult results = index.search(query, new SearchOptions());
+    assertThat(results.getIds()).hasSize(2);
+
+    // Only template
+    query = new RuleQuery().setIsTemplate(true);
+    results = index.search(query, new SearchOptions());
+    assertThat(results.getIds()).containsOnly(RuleKey.of("java", "S002"));
+
+    // Only not template
+    query = new RuleQuery().setIsTemplate(false);
+    results = index.search(query, new SearchOptions());
+    assertThat(results.getIds()).containsOnly(RuleKey.of("java", "S001"));
+
+    // null => no filter
+    query = new RuleQuery().setIsTemplate(null);
+    assertThat(index.search(query, new SearchOptions()).getIds()).hasSize(2);
+  }
+
+  @Test
+  public void search_by_template_key() {
+    indexRules(
+      newDoc(RuleKey.of("java", "S001")).setIsTemplate(true),
+      newDoc(RuleKey.of("java", "S001_MY_CUSTOM")).setTemplateKey("java:S001"));
+
+    // find all
+    RuleQuery query = new RuleQuery();
+    SearchIdResult results = index.search(query, new SearchOptions());
+    assertThat(results.getIds()).hasSize(2);
+
+    // Only custom rule
+    query = new RuleQuery().setTemplateKey("java:S001");
+    results = index.search(query, new SearchOptions());
+    assertThat(results.getIds()).containsOnly(RuleKey.of("java", "S001_MY_CUSTOM"));
+
+    // null => no filter
+    query = new RuleQuery().setTemplateKey(null);
+    assertThat(index.search(query, new SearchOptions()).getIds()).hasSize(2);
+  }
+
+  @Test
+  public void search_by_any_of_languages() {
+    indexRules(
+      newDoc(RuleKey.of("java", "S001")).setLanguage("java"),
+      newDoc(RuleKey.of("javascript", "S002")).setLanguage("js"));
+
+    RuleQuery query = new RuleQuery().setLanguages(asList("cobol", "js"));
+    SearchIdResult results = index.search(query, new SearchOptions());
+    assertThat(results.getIds()).containsOnly(RuleKey.of("javascript", "S002"));
+
+    // no results
+    query = new RuleQuery().setLanguages(singletonList("cpp"));
+    assertThat(index.search(query, new SearchOptions()).getIds()).isEmpty();
+
+    // empty list => no filter
+    query = new RuleQuery().setLanguages(Collections.<String>emptyList());
+    assertThat(index.search(query, new SearchOptions()).getIds()).hasSize(2);
+
+    // null list => no filter
+    query = new RuleQuery().setLanguages(null);
+    assertThat(index.search(query, new SearchOptions()).getIds()).hasSize(2);
+  }
+
+  @Test
+  public void search_by_any_of_severities() {
+    indexRules(
+      newDoc(RuleKey.of("java", "S001")).setSeverity(BLOCKER),
+      newDoc(RuleKey.of("java", "S002")).setSeverity(INFO));
+
+    RuleQuery query = new RuleQuery().setSeverities(asList(INFO, MINOR));
+    SearchIdResult results = index.search(query, new SearchOptions());
+    assertThat(results.getIds()).containsOnly(RuleKey.of("java", "S002"));
+
+    // no results
+    query = new RuleQuery().setSeverities(singletonList(MINOR));
+    assertThat(index.search(query, new SearchOptions()).getIds()).isEmpty();
+
+    // empty list => no filter
+    query = new RuleQuery().setSeverities(Collections.<String>emptyList());
+    assertThat(index.search(query, new SearchOptions()).getIds()).hasSize(2);
+
+    // null list => no filter
+    query = new RuleQuery().setSeverities();
+    assertThat(index.search(query, new SearchOptions()).getIds()).hasSize(2);
+  }
+
+  @Test
+  public void search_by_any_of_statuses() {
+    indexRules(
+      newDoc(RuleKey.of("java", "S001")).setStatus(RuleStatus.BETA.name()),
+      newDoc(RuleKey.of("java", "S002")).setStatus(RuleStatus.READY.name()));
+
+    RuleQuery query = new RuleQuery().setStatuses(asList(RuleStatus.DEPRECATED, RuleStatus.READY));
+    SearchIdResult<RuleKey> results = index.search(query, new SearchOptions());
+    assertThat(results.getIds()).containsOnly(RuleKey.of("java", "S002"));
+
+    // no results
+    query = new RuleQuery().setStatuses(singletonList(RuleStatus.DEPRECATED));
+    assertThat(index.search(query, new SearchOptions()).getIds()).isEmpty();
+
+    // empty list => no filter
+    query = new RuleQuery().setStatuses(Collections.<RuleStatus>emptyList());
+    assertThat(index.search(query, new SearchOptions()).getIds()).hasSize(2);
+
+    // null list => no filter
+    query = new RuleQuery().setStatuses(null);
+    assertThat(index.search(query, new SearchOptions()).getIds()).hasSize(2);
+  }
+
+  @Test
+  public void search_by_profile() throws InterruptedException {
+    indexRules(
+      newDoc(RULE_KEY_1),
+      newDoc(RULE_KEY_2),
+      newDoc(RULE_KEY_3));
+
+    indexActiveRules(
+      ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_1)),
+      ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY2, RULE_KEY_1)),
+      ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_2)));
+
+    assertThat(tester.countDocuments(INDEX, TYPE_ACTIVE_RULE)).isEqualTo(3);
+
+    // 1. get all active rules.
+    assertThat(index.search(new RuleQuery().setActivation(true), new SearchOptions()).getIds())
+      .containsOnly(RULE_KEY_1, RULE_KEY_2);
+
+    // 2. get all inactive rules.
+    assertThat(index.search(new RuleQuery().setActivation(false), new SearchOptions()).getIds())
+      .containsOnly(RULE_KEY_3);
+
+    // 3. get all rules not active on profile
+    assertThat(index.search(new RuleQuery().setActivation(false).setQProfileKey(QUALITY_PROFILE_KEY2), new SearchOptions()).getIds())
+      .containsOnly(RULE_KEY_2, RULE_KEY_3);
+
+    // 4. get all active rules on profile
+    assertThat(index.search(new RuleQuery().setActivation(true).setQProfileKey(QUALITY_PROFILE_KEY2), new SearchOptions()).getIds())
+      .containsOnly(RULE_KEY_1);
+  }
+
+  @Test
+  public void search_by_profile_and_inheritance() {
+    indexRules(
+      newDoc(RULE_KEY_1),
+      newDoc(RULE_KEY_2),
+      newDoc(RULE_KEY_3),
+      newDoc(RULE_KEY_4));
+
+    ActiveRuleKey activeRuleKey1 = ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_1);
+    ActiveRuleKey activeRuleKey2 = ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_2);
+    ActiveRuleKey activeRuleKey3 = ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_3);
+
+    indexActiveRules(
+      ActiveRuleDocTesting.newDoc(activeRuleKey1),
+      ActiveRuleDocTesting.newDoc(activeRuleKey2),
+      ActiveRuleDocTesting.newDoc(activeRuleKey3),
+      // Profile 2 is a child a profile 1
+      ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY2, RULE_KEY_1))
+        .setParentKey(activeRuleKey1.toString()).setInheritance(INHERITED.name()),
+      ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY2, RULE_KEY_2))
+        .setParentKey(activeRuleKey2.toString()).setInheritance(OVERRIDES.name()),
+      ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY2, RULE_KEY_3))
+        .setParentKey(activeRuleKey3.toString()).setInheritance(INHERITED.name()));
+
+    // 0. get all rules
+    assertThat(index.search(new RuleQuery(), new SearchOptions()).getIds())
+      .hasSize(4);
+
+    // 1. get all active rules
+    assertThat(index.search(new RuleQuery()
+      .setActivation(true), new SearchOptions()).getIds())
+      .hasSize(3);
+
+    // 2. get all inactive rules.
+    assertThat(index.search(new RuleQuery()
+      .setActivation(false), new SearchOptions()).getIds())
+      .containsOnly(RULE_KEY_4);
+
+    // 3. get Inherited Rules on profile1
+    assertThat(index.search(new RuleQuery().setActivation(true)
+      .setQProfileKey(QUALITY_PROFILE_KEY1)
+      .setInheritance(ImmutableSet.of(INHERITED.name())),
+      new SearchOptions()).getIds())
+      .isEmpty();
+
+    // 4. get Inherited Rules on profile2
+    assertThat(index.search(new RuleQuery().setActivation(true)
+      .setQProfileKey(QUALITY_PROFILE_KEY2)
+      .setInheritance(ImmutableSet.of(INHERITED.name())),
+      new SearchOptions()).getIds())
+      .hasSize(2);
+
+    // 5. get Overridden Rules on profile1
+    assertThat(index.search(new RuleQuery().setActivation(true)
+      .setQProfileKey(QUALITY_PROFILE_KEY1)
+      .setInheritance(ImmutableSet.of(OVERRIDES.name())),
+      new SearchOptions()).getIds())
+      .isEmpty();
+
+    // 6. get Overridden Rules on profile2
+    assertThat(index.search(new RuleQuery().setActivation(true)
+      .setQProfileKey(QUALITY_PROFILE_KEY2)
+      .setInheritance(ImmutableSet.of(OVERRIDES.name())),
+      new SearchOptions()).getIds())
+      .hasSize(1);
+
+    // 7. get Inherited AND Overridden Rules on profile1
+    assertThat(index.search(new RuleQuery().setActivation(true)
+      .setQProfileKey(QUALITY_PROFILE_KEY1)
+      .setInheritance(ImmutableSet.of(INHERITED.name(), OVERRIDES.name())),
+      new SearchOptions()).getIds())
+      .isEmpty();
+
+    // 8. get Inherited AND Overridden Rules on profile2
+    assertThat(index.search(new RuleQuery().setActivation(true)
+      .setQProfileKey(QUALITY_PROFILE_KEY2)
+      .setInheritance(ImmutableSet.of(INHERITED.name(), OVERRIDES.name())),
+      new SearchOptions()).getIds())
+      .hasSize(3);
+  }
+
+  @Test
+  public void search_by_profile_and_active_severity() {
+    indexRules(
+      newDoc(RULE_KEY_1).setSeverity(MAJOR),
+      newDoc(RULE_KEY_2).setSeverity(MINOR),
+      newDoc(RULE_KEY_3).setSeverity(INFO));
+
+    indexActiveRules(
+      ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_1)).setSeverity(BLOCKER),
+      ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY2, RULE_KEY_1)).setSeverity(BLOCKER),
+      ActiveRuleDocTesting.newDoc(ActiveRuleKey.of(QUALITY_PROFILE_KEY1, RULE_KEY_2)).setSeverity(CRITICAL));
+
+    // 1. get all active rules.
+    assertThat(index.search(new RuleQuery().setActivation(true).setQProfileKey(QUALITY_PROFILE_KEY1), new SearchOptions()).getIds())
+      .hasSize(2);
+
+    // 2. get rules with active severity critical.
+    SearchIdResult<RuleKey> result = index.search(new RuleQuery().setActivation(true)
+      .setQProfileKey(QUALITY_PROFILE_KEY1).setActiveSeverities(singletonList(CRITICAL)),
+      new SearchOptions().addFacets(singletonList(RuleIndex.FACET_ACTIVE_SEVERITIES)));
+    assertThat(result.getIds()).containsOnly(RULE_KEY_2);
+
+    // check stickyness of active severity facet
+    assertThat(result.getFacets().get(RuleIndex.FACET_ACTIVE_SEVERITIES)).containsOnly(entry(BLOCKER, 1L), entry(CRITICAL, 1L));
+
+    // 3. count activation severities of all active rules
+    result = index.search(new RuleQuery(), new SearchOptions().addFacets(singletonList(RuleIndex.FACET_ACTIVE_SEVERITIES)));
+    assertThat(result.getIds()).hasSize(3);
+    assertThat(result.getFacets().get(RuleIndex.FACET_ACTIVE_SEVERITIES)).containsOnly(entry(BLOCKER, 2L), entry(CRITICAL, 1L));
+  }
+
+  @Test
+  public void all_tags() {
+    indexRules(
+      newDoc(RuleKey.of("java", "S001")).setAllTags(asList("tag1", "sys1", "sys2")),
+      newDoc(RuleKey.of("java", "S002")).setAllTags(asList("tag2")));
+
+    assertThat(index.terms(RuleIndexDefinition.FIELD_RULE_ALL_TAGS, null, 10)).containsOnly("tag1", "tag2", "sys1", "sys2");
+  }
+
+  @Test
+  public void available_since() throws InterruptedException {
+    indexRules(
+      newDoc(RuleKey.of("java", "S001")).setCreatedAt(1000L),
+      newDoc(RuleKey.of("java", "S002")).setCreatedAt(2000L));
+
+    // 0. find all rules;
+    assertThat(index.search(new RuleQuery(), new SearchOptions()).getIds()).hasSize(2);
+
+    // 1. find all rules available since a date;
+    RuleQuery availableSinceQuery = new RuleQuery().setAvailableSince(2000L);
+    assertThat(index.search(availableSinceQuery, new SearchOptions()).getIds()).containsOnly(RuleKey.of("java", "S002"));
+
+    // 2. find no new rules since tomorrow.
+    RuleQuery availableSinceNowQuery = new RuleQuery().setAvailableSince(3000L);
+    assertThat(index.search(availableSinceNowQuery, new SearchOptions()).getIds()).hasSize(0);
+  }
+
+  @Test
+  public void global_facet_on_repositories_and_tags() {
+    indexRules(
+      newDoc(RuleKey.of("php", "S001")).setAllTags(singletonList("sysTag")),
+      newDoc(RuleKey.of("php", "S002")).setAllTags(singletonList("tag1")),
+      newDoc(RuleKey.of("javascript", "S002")).setAllTags(asList("tag1", "tag2")));
+
+    // should not have any facet!
+    RuleQuery query = new RuleQuery();
+    SearchIdResult result = index.search(query, new SearchOptions());
+    assertThat(result.getFacets().getAll()).isEmpty();
+
+    // should not have any facet on non matching query!
+    result = index.search(new RuleQuery().setQueryText("aeiou"), new SearchOptions().addFacets(singletonList("repositories")));
+    assertThat(result.getFacets().getAll()).hasSize(1);
+    assertThat(result.getFacets().getAll().get("repositories")).isEmpty();
+
+    // Repositories Facet is preset
+    result = index.search(query, new SearchOptions().addFacets(asList("repositories", "tags")));
+    assertThat(result.getFacets()).isNotNull();
+    assertThat(result.getFacets().getAll()).hasSize(2);
+
+    // Verify the value of a given facet
+    Map<String, Long> repoFacets = result.getFacets().get("repositories");
+    assertThat(repoFacets).containsOnly(entry("php", 2L), entry("javascript", 1L));
+
+    // Check that tag facet has both Tags and SystemTags values
+    Map<String, Long> tagFacets = result.getFacets().get("tags");
+    assertThat(tagFacets).containsOnly(entry("tag1", 2L), entry("sysTag", 1L), entry("tag2", 1L));
+  }
+
+  @Test
+  public void sticky_facets() {
+    indexRules(
+      newDoc(RuleKey.of("xoo", "S001")).setLanguage("java").setAllTags(Collections.<String>emptyList()),
+      newDoc(RuleKey.of("xoo", "S002")).setLanguage("java").setAllTags(Collections.<String>emptyList()),
+      newDoc(RuleKey.of("xoo", "S003")).setLanguage("java").setAllTags(asList("T1", "T2")),
+      newDoc(RuleKey.of("xoo", "S011")).setLanguage("cobol").setAllTags(Collections.<String>emptyList()),
+      newDoc(RuleKey.of("xoo", "S012")).setLanguage("cobol").setAllTags(Collections.<String>emptyList()),
+      newDoc(RuleKey.of("foo", "S013")).setLanguage("cobol").setAllTags(asList("T3", "T4")),
+      newDoc(RuleKey.of("foo", "S111")).setLanguage("cpp").setAllTags(Collections.<String>emptyList()),
+      newDoc(RuleKey.of("foo", "S112")).setLanguage("cpp").setAllTags(Collections.<String>emptyList()),
+      newDoc(RuleKey.of("foo", "S113")).setLanguage("cpp").setAllTags(asList("T2", "T3")));
+
+    // 0 assert Base
+    assertThat(index.search(new RuleQuery(), new SearchOptions()).getIds()).hasSize(9);
+
+    // 1 Facet with no filters at all
+    SearchIdResult result = index.search(new RuleQuery(), new SearchOptions().addFacets(asList("languages", "repositories", "tags")));
+    assertThat(result.getFacets().getAll()).hasSize(3);
+    assertThat(result.getFacets().getAll().get(FACET_LANGUAGES).keySet()).containsOnly("cpp", "java", "cobol");
+    assertThat(result.getFacets().getAll().get(FACET_REPOSITORIES).keySet()).containsOnly("xoo", "foo");
+    assertThat(result.getFacets().getAll().get(FACET_TAGS).keySet()).containsOnly("T1", "T2", "T3", "T4");
+
+    // 2 Facet with a language filter
+    // -- lang facet should still have all language
+    result = index.search(new RuleQuery().setLanguages(ImmutableList.of("cpp"))
+      , new SearchOptions().addFacets(asList("languages", "repositories", "tags")));
+    assertThat(result.getIds()).hasSize(3);
+    assertThat(result.getFacets().getAll()).hasSize(3);
+    assertThat(result.getFacets().get(FACET_LANGUAGES).keySet()).containsOnly("cpp", "java", "cobol");
+
+    // 3 facet with 2 filters
+    // -- lang facet for tag T2
+    // -- tag facet for lang cpp
+    // -- repository for cpp & T2
+    result = index.search(new RuleQuery()
+      .setLanguages(ImmutableList.of("cpp"))
+      .setTags(ImmutableList.of("T2"))
+      , new SearchOptions().addFacets(asList("languages", "repositories", "tags")));
+    assertThat(result.getIds()).hasSize(1);
+    assertThat(result.getFacets().getAll()).hasSize(3);
+    assertThat(result.getFacets().get(FACET_LANGUAGES).keySet()).containsOnly("cpp", "java");
+    assertThat(result.getFacets().get(FACET_REPOSITORIES).keySet()).containsOnly("foo");
+    assertThat(result.getFacets().get(FACET_TAGS).keySet()).containsOnly("T2", "T3");
+
+    // 4 facet with 2 filters
+    // -- lang facet for tag T2
+    // -- tag facet for lang cpp & java
+    // -- repository for (cpp || java) & T2
+    result = index.search(new RuleQuery()
+      .setLanguages(ImmutableList.of("cpp", "java"))
+      .setTags(ImmutableList.of("T2"))
+      , new SearchOptions().addFacets(asList("languages", "repositories", "tags")));
+    assertThat(result.getIds()).hasSize(2);
+    assertThat(result.getFacets().getAll()).hasSize(3);
+    assertThat(result.getFacets().get(FACET_LANGUAGES).keySet()).containsOnly("cpp", "java");
+    assertThat(result.getFacets().get(FACET_REPOSITORIES).keySet()).containsOnly("foo", "xoo");
+    assertThat(result.getFacets().get(FACET_TAGS).keySet()).containsOnly("T1", "T2", "T3");
+  }
+
+  @Test
+  public void sort_by_name() {
+    indexRules(
+      newDoc(RuleKey.of("java", "S001")).setName("abcd"),
+      newDoc(RuleKey.of("java", "S002")).setName("ABC"),
+      newDoc(RuleKey.of("java", "S003")).setName("FGH"));
+
+    // ascending
+    RuleQuery query = new RuleQuery().setSortField(RuleIndexDefinition.FIELD_RULE_NAME);
+    SearchIdResult<RuleKey> results = index.search(query, new SearchOptions());
+    assertThat(results.getIds()).containsExactly(RuleKey.of("java", "S002"), RuleKey.of("java", "S001"), RuleKey.of("java", "S003"));
+
+    // descending
+    query = new RuleQuery().setSortField(RuleIndexDefinition.FIELD_RULE_NAME).setAscendingSort(false);
+    results = index.search(query, new SearchOptions());
+    assertThat(results.getIds()).containsExactly(RuleKey.of("java", "S003"), RuleKey.of("java", "S001"), RuleKey.of("java", "S002"));
+  }
+
+  @Test
+  public void default_sort_is_by_updated_at_desc() {
+    indexRules(
+      newDoc(RuleKey.of("java", "S001")).setCreatedAt(1000L).setUpdatedAt(1000L),
+      newDoc(RuleKey.of("java", "S002")).setCreatedAt(1000L).setUpdatedAt(3000L),
+      newDoc(RuleKey.of("java", "S003")).setCreatedAt(1000L).setUpdatedAt(2000L));
+
+    SearchIdResult<RuleKey> results = index.search(new RuleQuery(), new SearchOptions());
+    assertThat(results.getIds()).containsExactly(RuleKey.of("java", "S002"), RuleKey.of("java", "S003"), RuleKey.of("java", "S001"));
+  }
+
+  @Test
+  public void fail_sort_by_language() {
+    try {
+      // Sorting on a field not tagged as sortable
+      new RuleQuery().setSortField(RuleIndexDefinition.FIELD_RULE_LANGUAGE);
+      fail();
+    } catch (IllegalStateException e) {
+      assertThat(e).hasMessage("Field 'lang' is not sortable");
+    }
+  }
+
+  @Test
+  public void paging() {
+    indexRules(
+      newDoc(RuleKey.of("java", "S001")),
+      newDoc(RuleKey.of("java", "S002")),
+      newDoc(RuleKey.of("java", "S003")));
+
+    // from 0 to 1 included
+    SearchOptions options = new SearchOptions();
+    options.setOffset(0).setLimit(2);
+    SearchIdResult results = index.search(new RuleQuery(), options);
+    assertThat(results.getTotal()).isEqualTo(3);
+    assertThat(results.getIds()).hasSize(2);
+
+    // from 0 to 9 included
+    options.setOffset(0).setLimit(10);
+    results = index.search(new RuleQuery(), options);
+    assertThat(results.getTotal()).isEqualTo(3);
+    assertThat(results.getIds()).hasSize(3);
+
+    // from 2 to 11 included
+    options.setOffset(2).setLimit(10);
+    results = index.search(new RuleQuery(), options);
+    assertThat(results.getTotal()).isEqualTo(3);
+    assertThat(results.getIds()).hasSize(1);
+
+    // from 2 to 11 included
+    options.setOffset(2).setLimit(0);
+    results = index.search(new RuleQuery(), options);
+    assertThat(results.getTotal()).isEqualTo(3);
+    assertThat(results.getIds()).hasSize(1);
+  }
+
+  @Test
+  public void search_all_keys_by_query() {
+    indexRules(
+      newDoc(RuleKey.of("javascript", "X001")),
+      newDoc(RuleKey.of("cobol", "X001")),
+      newDoc(RuleKey.of("php", "S002")));
+
+    // key
+    assertThat(index.searchAll(new RuleQuery().setQueryText("X001"))).hasSize(2);
+
+    // partial key does not match
+    assertThat(index.searchAll(new RuleQuery().setQueryText("X00"))).isEmpty();
+
+    // repo:key -> nice-to-have !
+    assertThat(index.searchAll(new RuleQuery().setQueryText("javascript:X001"))).hasSize(1);
+  }
+
+  private void indexRules(RuleDoc... rules) {
+    ruleIndexer.index(asList(rules).iterator());
+  }
+
+  private void indexActiveRules(ActiveRuleDoc... docs) {
+    activeRuleIndexer.index(asList(docs).iterator());
+  }
+}