]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6089 Only clear lookup cache of current View
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Thu, 5 Feb 2015 07:31:59 +0000 (08:31 +0100)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Thu, 5 Feb 2015 15:46:29 +0000 (16:46 +0100)
18 files changed:
server/sonar-server/src/main/java/org/sonar/server/es/EsClient.java
server/sonar-server/src/main/java/org/sonar/server/es/request/ProxyClearCacheRequestBuilder.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueDoc.java
server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndex.java
server/sonar-server/src/main/java/org/sonar/server/platform/BackendCleanup.java
server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleDoc.java
server/sonar-server/src/main/java/org/sonar/server/source/index/SourceLineDoc.java
server/sonar-server/src/main/java/org/sonar/server/user/index/UserDoc.java
server/sonar-server/src/main/java/org/sonar/server/view/index/ViewIndexer.java
server/sonar-server/src/test/java/org/sonar/server/component/ComponentTesting.java
server/sonar-server/src/test/java/org/sonar/server/computation/step/IndexViewsStepMediumTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/computation/step/PurgeRemovedViewsStepTest.java
server/sonar-server/src/test/java/org/sonar/server/es/EsTester.java
server/sonar-server/src/test/java/org/sonar/server/es/request/ProxyClearCacheRequestBuilderTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/platform/BackendCleanupMediumTest.java
server/sonar-server/src/test/java/org/sonar/server/view/index/ViewIndexerMediumTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/view/index/ViewIndexerTest.java
server/sonar-server/src/test/resources/org/sonar/server/platform/BackendCleanupMediumTest/shared.xml [new file with mode: 0644]

index 2508fd64191f7a4a2b5706392a3fa7595d39a38c..f20f3fdc7d3a276e474304b18667719af5781315 100644 (file)
@@ -25,6 +25,7 @@ import org.elasticsearch.action.admin.cluster.node.stats.NodesStatsRequestBuilde
 import org.elasticsearch.action.admin.cluster.state.ClusterStateRequestBuilder;
 import org.elasticsearch.action.admin.cluster.stats.ClusterStatsRequestBuilder;
 import org.elasticsearch.action.admin.cluster.stats.ClusterStatsResponse;
+import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheRequestBuilder;
 import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder;
 import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsRequestBuilder;
 import org.elasticsearch.action.admin.indices.flush.FlushRequestBuilder;
@@ -48,25 +49,7 @@ import org.elasticsearch.search.aggregations.AggregationBuilders;
 import org.elasticsearch.search.aggregations.metrics.max.Max;
 import org.picocontainer.Startable;
 import org.sonar.core.profiling.Profiling;
-import org.sonar.server.es.request.ProxyBulkRequestBuilder;
-import org.sonar.server.es.request.ProxyClusterHealthRequestBuilder;
-import org.sonar.server.es.request.ProxyClusterStateRequestBuilder;
-import org.sonar.server.es.request.ProxyClusterStatsRequestBuilder;
-import org.sonar.server.es.request.ProxyCountRequestBuilder;
-import org.sonar.server.es.request.ProxyCreateIndexRequestBuilder;
-import org.sonar.server.es.request.ProxyDeleteByQueryRequestBuilder;
-import org.sonar.server.es.request.ProxyDeleteRequestBuilder;
-import org.sonar.server.es.request.ProxyFlushRequestBuilder;
-import org.sonar.server.es.request.ProxyGetRequestBuilder;
-import org.sonar.server.es.request.ProxyIndexRequestBuilder;
-import org.sonar.server.es.request.ProxyIndicesExistsRequestBuilder;
-import org.sonar.server.es.request.ProxyIndicesStatsRequestBuilder;
-import org.sonar.server.es.request.ProxyMultiGetRequestBuilder;
-import org.sonar.server.es.request.ProxyNodesStatsRequestBuilder;
-import org.sonar.server.es.request.ProxyPutMappingRequestBuilder;
-import org.sonar.server.es.request.ProxyRefreshRequestBuilder;
-import org.sonar.server.es.request.ProxySearchRequestBuilder;
-import org.sonar.server.es.request.ProxySearchScrollRequestBuilder;
+import org.sonar.server.es.request.*;
 import org.sonar.server.search.ClusterHealth;
 import org.sonar.server.search.SearchClient;
 
@@ -178,7 +161,6 @@ public class EsClient implements Startable {
     return new ProxyDeleteRequestBuilder(profiling, client, index).setType(type).setId(id);
   }
 
-
   public DeleteByQueryRequestBuilder prepareDeleteByQuery(String... indices) {
     return new ProxyDeleteByQueryRequestBuilder(client, profiling).setIndices(indices);
   }
@@ -194,6 +176,9 @@ public class EsClient implements Startable {
       .setWaitForMerge(true);
   }
 
+  public ClearIndicesCacheRequestBuilder prepareClearCache(String... indices) {
+    return new ProxyClearCacheRequestBuilder(client, profiling).setIndices(indices);
+  }
 
   public long getLastUpdatedAt(String indexName, String typeName) {
     SearchRequestBuilder request = prepareSearch(indexName)
diff --git a/server/sonar-server/src/main/java/org/sonar/server/es/request/ProxyClearCacheRequestBuilder.java b/server/sonar-server/src/main/java/org/sonar/server/es/request/ProxyClearCacheRequestBuilder.java
new file mode 100644 (file)
index 0000000..298f2ea
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.server.es.request;
+
+import org.apache.commons.lang.StringUtils;
+import org.elasticsearch.action.ListenableActionFuture;
+import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheRequestBuilder;
+import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheResponse;
+import org.elasticsearch.client.Client;
+import org.elasticsearch.common.unit.TimeValue;
+import org.sonar.core.profiling.Profiling;
+import org.sonar.core.profiling.StopWatch;
+
+public class ProxyClearCacheRequestBuilder extends ClearIndicesCacheRequestBuilder {
+
+  private final Profiling profiling;
+
+  public ProxyClearCacheRequestBuilder(Client client, Profiling profiling) {
+    super(client.admin().indices());
+    this.profiling = profiling;
+  }
+
+  @Override
+  public ClearIndicesCacheResponse get() {
+    StopWatch fullProfile = profiling.start("clear cache", Profiling.Level.FULL);
+    try {
+      return super.execute().actionGet();
+    } catch (Exception e) {
+      throw new IllegalStateException(String.format("Fail to execute %s", toString()), e);
+    } finally {
+      if (profiling.isProfilingEnabled(Profiling.Level.FULL)) {
+        fullProfile.stop("%s", toString());
+      }
+    }
+  }
+
+  @Override
+  public ClearIndicesCacheResponse get(TimeValue timeout) {
+    throw new IllegalStateException("Not yet implemented");
+  }
+
+  @Override
+  public ClearIndicesCacheResponse get(String timeout) {
+    throw new IllegalStateException("Not yet implemented");
+  }
+
+  @Override
+  public ListenableActionFuture<ClearIndicesCacheResponse> execute() {
+    throw new UnsupportedOperationException("execute() should not be called as it's used for asynchronous");
+  }
+
+  @Override
+  public String toString() {
+    StringBuilder message = new StringBuilder();
+    message.append("ES clear cache request");
+    if (request.indices().length > 0) {
+      message.append(String.format(" on indices '%s'", StringUtils.join(request.indices(), ",")));
+    }
+    String[] fields = request.fields();
+    if (fields != null && fields.length > 0) {
+      message.append(String.format(" on fields '%s'", StringUtils.join(fields, ",")));
+    }
+    String[] filterKeys = request.filterKeys();
+    if (filterKeys != null && filterKeys.length > 0) {
+      message.append(String.format(" on filterKeys '%s'", StringUtils.join(filterKeys, ",")));
+    }
+    if (request.filterCache()) {
+      message.append(" with filter cache");
+    }
+    if (request.fieldDataCache()) {
+      message.append(" with field data cache");
+    }
+    if (request.idCache()) {
+      message.append(" with id cache");
+    }
+    return message.toString();
+  }
+}
index fd166c6b898e281e1217fd2e9ba54dd1e6cd410d..756f1d45477d0d9f9a30b39e718586cc9a0e58a7 100644 (file)
@@ -19,6 +19,7 @@
  */
 package org.sonar.server.issue.index;
 
+import com.google.common.collect.Maps;
 import org.sonar.api.issue.Issue;
 import org.sonar.api.issue.IssueComment;
 import org.sonar.api.rule.RuleKey;
@@ -38,6 +39,10 @@ public class IssueDoc extends BaseDoc implements Issue {
     super(fields);
   }
 
+  public IssueDoc() {
+    super(Maps.<String, Object>newHashMap());
+  }
+
   @Override
   public String key() {
     return getField(IssueIndexDefinition.FIELD_ISSUE_KEY);
index 52b4f52fa9218e8efb95d6ce6505cfda75153c6b..5c8b90a744d29cf5bc2e1c9bb8c88d36a1f6631f 100644 (file)
@@ -375,12 +375,12 @@ public class IssueIndex extends BaseIndex<Issue, FakeIssueDto, String> {
         .lookupType(ViewIndexDefinition.TYPE_VIEW)
         .lookupId(viewUuid)
         .lookupPath(ViewIndexDefinition.FIELD_PROJECTS))
-        .cacheKey(cacheKey(viewUuid));
+        .cacheKey(viewsLookupCacheKey(viewUuid));
     }
     return viewsFilter;
   }
 
-  public static String cacheKey(String viewUuid) {
+  public static String viewsLookupCacheKey(String viewUuid) {
     return IssueIndexDefinition.TYPE_ISSUE + viewUuid + ViewIndexDefinition.TYPE_VIEW;
   }
 
index 4faccc21c65546b81a913200a156f169827821e1..abd3c838ebb3072edac02eec59b7cd7d6af53789 100644 (file)
 package org.sonar.server.platform;
 
 import org.apache.commons.dbutils.DbUtils;
-import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheRequest;
 import org.elasticsearch.index.query.QueryBuilders;
 import org.slf4j.LoggerFactory;
 import org.sonar.api.ServerComponent;
 import org.sonar.core.persistence.DatabaseVersion;
 import org.sonar.core.persistence.DbSession;
 import org.sonar.core.persistence.MyBatis;
+import org.sonar.server.es.EsClient;
 import org.sonar.server.issue.index.IssueIndexDefinition;
 import org.sonar.server.search.IndexDefinition;
-import org.sonar.server.search.SearchClient;
 import org.sonar.server.source.index.SourceLineIndexDefinition;
+import org.sonar.server.view.index.ViewIndexDefinition;
 
 import java.sql.Connection;
 import java.sql.SQLException;
@@ -45,11 +45,11 @@ public class BackendCleanup implements ServerComponent {
   private static final String[] RESOURCE_RELATED_TABLES = {
     "group_roles", "user_roles", "properties"
   };
-  private final SearchClient searchClient;
+  private final EsClient esClient;
   private final MyBatis myBatis;
 
-  public BackendCleanup(SearchClient searchClient, MyBatis myBatis) {
-    this.searchClient = searchClient;
+  public BackendCleanup(EsClient esClient, MyBatis myBatis) {
+    this.esClient = esClient;
     this.myBatis = myBatis;
   }
 
@@ -81,18 +81,17 @@ public class BackendCleanup implements ServerComponent {
   public void clearIndexes() {
     LoggerFactory.getLogger(getClass()).info("Truncate Elasticsearch indices");
     try {
-      searchClient.admin().indices()
-        .clearCache(new ClearIndicesCacheRequest())
+      esClient.prepareClearCache()
         .get();
-      searchClient.prepareDeleteByQuery(searchClient.prepareState().get()
+      esClient.prepareDeleteByQuery(esClient.prepareState().get()
         .getState().getMetaData().concreteAllIndices())
         .setQuery(QueryBuilders.matchAllQuery())
         .get();
-      searchClient.prepareRefresh(searchClient.prepareState().get()
+      esClient.prepareRefresh(esClient.prepareState().get()
         .getState().getMetaData().concreteAllIndices())
         .setForce(true)
         .get();
-      searchClient.prepareFlush(searchClient.prepareState().get()
+      esClient.prepareFlush(esClient.prepareState().get()
         .getState().getMetaData().concreteAllIndices())
         .get();
     } catch (Exception e) {
@@ -130,6 +129,7 @@ public class BackendCleanup implements ServerComponent {
       // Clear inspection indexes
       clearIndex(IssueIndexDefinition.INDEX);
       clearIndex(SourceLineIndexDefinition.INDEX);
+      clearIndex(ViewIndexDefinition.INDEX);
 
     } finally {
       dbSession.close();
@@ -161,7 +161,7 @@ public class BackendCleanup implements ServerComponent {
    * Completely remove a index with all types
    */
   public void clearIndex(String indexName) {
-    searchClient.prepareDeleteByQuery(searchClient.prepareState().get()
+    esClient.prepareDeleteByQuery(esClient.prepareState().get()
       .getState().getMetaData().concreteIndices(new String[] {indexName}))
       .setQuery(QueryBuilders.matchAllQuery())
       .get();
@@ -171,7 +171,7 @@ public class BackendCleanup implements ServerComponent {
    * Remove only the type of an index
    */
   public void clearIndexType(IndexDefinition indexDefinition) {
-    searchClient.prepareDeleteByQuery(searchClient.prepareState().get()
+    esClient.prepareDeleteByQuery(esClient.prepareState().get()
       .getState().getMetaData().concreteIndices(new String[] {indexDefinition.getIndexName()})).setTypes(indexDefinition.getIndexType())
       .setQuery(QueryBuilders.matchAllQuery())
       .get();
index 59399af577c5f58acc7a97b419748e6a651d39ea..3c9de11535b0e2baef45c8b5b20a588525598a1d 100644 (file)
@@ -48,7 +48,7 @@ public class RuleDoc extends BaseDoc implements Rule {
 
   public static final String MANUAL_REPOSITORY = "manual";
 
-  RuleDoc(Map<String, Object> fields) {
+  public RuleDoc(Map<String, Object> fields) {
     super(fields);
   }
 
@@ -326,4 +326,5 @@ public class RuleDoc extends BaseDoc implements Rule {
   public String toString() {
     return ReflectionToStringBuilder.toString(this);
   }
+
 }
index 18cdfcbf0b4da5c809c87ea8bd245ba7e3eff20a..822f1d3297ba7cbdfeb369468480789905bc179c 100644 (file)
@@ -20,6 +20,7 @@
 package org.sonar.server.source.index;
 
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Maps;
 import org.sonar.server.search.BaseDoc;
 import org.sonar.server.search.BaseNormalizer;
 import org.sonar.server.search.IndexUtils;
@@ -29,7 +30,6 @@ import javax.annotation.Nullable;
 
 import java.util.Collection;
 import java.util.Date;
-import java.util.HashMap;
 import java.util.Map;
 
 public class SourceLineDoc extends BaseDoc {
@@ -40,7 +40,7 @@ public class SourceLineDoc extends BaseDoc {
 
   // For testing purpose
   public SourceLineDoc() {
-    this(new HashMap<String, Object>());
+    this(Maps.<String, Object>newHashMap());
   }
 
   public String projectUuid() {
index c01104d1801a858c0eb9331018692d708788bc81..30a83dde9c4b19da8d800e4111ab7ebc8951656b 100644 (file)
@@ -19,6 +19,7 @@
  */
 package org.sonar.server.user.index;
 
+import com.google.common.collect.Maps;
 import org.sonar.api.user.User;
 import org.sonar.server.search.BaseDoc;
 
@@ -33,6 +34,10 @@ public class UserDoc extends BaseDoc implements User {
     super(fields);
   }
 
+  public UserDoc() {
+    this(Maps.<String, Object>newHashMap());
+  }
+
   @Override
   public String login() {
     return getField(UserIndexDefinition.FIELD_LOGIN);
@@ -66,31 +71,38 @@ public class UserDoc extends BaseDoc implements User {
     return getField(UserIndexDefinition.FIELD_UPDATED_AT);
   }
 
-  public void setLogin(@Nullable String s) {
+  public UserDoc setLogin(@Nullable String s) {
     setField(UserIndexDefinition.FIELD_LOGIN, s);
+    return this;
   }
 
-  public void setName(@Nullable String s) {
+  public UserDoc setName(@Nullable String s) {
     setField(UserIndexDefinition.FIELD_NAME, s);
+    return this;
   }
 
-  public void setEmail(@Nullable String s) {
+  public UserDoc setEmail(@Nullable String s) {
     setField(UserIndexDefinition.FIELD_EMAIL, s);
+    return this;
   }
 
-  public void setActive(boolean b) {
+  public UserDoc setActive(boolean b) {
     setField(UserIndexDefinition.FIELD_ACTIVE, b);
+    return this;
   }
 
-  public void setScmAccounts(@Nullable List<String> s) {
+  public UserDoc setScmAccounts(@Nullable List<String> s) {
     setField(UserIndexDefinition.FIELD_SCM_ACCOUNTS, s);
+    return this;
   }
 
-  public void setCreatedAt(long l) {
+  public UserDoc setCreatedAt(long l) {
     setField(UserIndexDefinition.FIELD_CREATED_AT, l);
+    return this;
   }
 
-  public void setUpdatedAt(long l) {
+  public UserDoc setUpdatedAt(long l) {
     setField(UserIndexDefinition.FIELD_UPDATED_AT, l);
+    return this;
   }
 }
index 7476c6f96338cda119c431f41076099e889bb062..953aedf4dbc8bfa3f34be7be4878fbea81e78fb6 100644 (file)
@@ -28,6 +28,7 @@ import org.sonar.server.db.DbClient;
 import org.sonar.server.es.BaseIndexer;
 import org.sonar.server.es.BulkIndexer;
 import org.sonar.server.es.EsClient;
+import org.sonar.server.issue.index.IssueIndex;
 
 import java.util.List;
 import java.util.Map;
@@ -47,11 +48,12 @@ public class ViewIndexer extends BaseIndexer {
 
   /**
    * Index all views if the index is empty.
-   * Only used on startup .
+   * Only used on startup.
+   *
+   * The views lookup cache will not be cleared
    */
   @Override
   protected long doIndex(long lastUpdatedAt) {
-    // Index only if index is empty
     long count = esClient.prepareCount(ViewIndexDefinition.INDEX).setTypes(ViewIndexDefinition.TYPE_VIEW).get().getCount();
     if (count == 0) {
       DbSession dbSession = dbClient.openSession(false);
@@ -60,7 +62,7 @@ public class ViewIndexer extends BaseIndexer {
         for (UuidWithProjectUuidDto uuidWithProjectUuidDto : dbClient.componentDao().selectAllViewsAndSubViews(dbSession)) {
           viewAndProjectViewUuidMap.put(uuidWithProjectUuidDto.getUuid(), uuidWithProjectUuidDto.getProjectUuid());
         }
-        index(dbSession, viewAndProjectViewUuidMap);
+        index(dbSession, viewAndProjectViewUuidMap, false);
       } finally {
         dbSession.close();
       }
@@ -71,6 +73,8 @@ public class ViewIndexer extends BaseIndexer {
   /**
    * Index a root view : it will load projects on each sub views and index it.
    * Used by the compute engine to reindex a root view.
+   *
+   * The views lookup cache will be cleared
    */
   public void index(String rootViewUuid) {
     DbSession dbSession = dbClient.openSession(false);
@@ -79,36 +83,42 @@ public class ViewIndexer extends BaseIndexer {
       for (ComponentDto viewOrSubView : dbClient.componentDao().selectModulesTree(dbSession, rootViewUuid)) {
         viewAndProjectViewUuidMap.put(viewOrSubView.uuid(), viewOrSubView.projectUuid());
       }
-      index(dbSession, viewAndProjectViewUuidMap);
+      index(dbSession, viewAndProjectViewUuidMap, true);
     } finally {
       dbSession.close();
     }
   }
 
   /**
-   * Index a single document
+   * Index a single document.
+   *
+   * The views lookup cache will be cleared
    */
   public void index(ViewDoc viewDoc) {
     final BulkIndexer bulk = new BulkIndexer(esClient, ViewIndexDefinition.INDEX);
     bulk.start();
-    bulk.add(newUpsertRequest(viewDoc));
+    doIndex(bulk, viewDoc, true);
     bulk.stop();
   }
 
-  private void index(DbSession dbSession, Map<String, String> viewAndProjectViewUuidMap) {
+  private void index(DbSession dbSession, Map<String, String> viewAndProjectViewUuidMap, boolean needClearCache) {
     final BulkIndexer bulk = new BulkIndexer(esClient, ViewIndexDefinition.INDEX);
     bulk.start();
     for (Map.Entry<String, String> entry : viewAndProjectViewUuidMap.entrySet()) {
-      doIndex(dbSession, bulk, entry.getKey(), entry.getValue());
+      String viewUuid = entry.getKey();
+      List<String> projects = dbClient.componentDao().selectProjectsFromView(dbSession, viewUuid, entry.getValue());
+      doIndex(bulk, new ViewDoc()
+        .setUuid(viewUuid)
+        .setProjects(projects), needClearCache);
     }
     bulk.stop();
   }
 
-  private void doIndex(DbSession dbSession, BulkIndexer bulk, String uuid, String projectUuid) {
-    List<String> projects = dbClient.componentDao().selectProjectsFromView(dbSession, uuid, projectUuid);
-    bulk.add(newUpsertRequest(new ViewDoc()
-      .setUuid(uuid)
-      .setProjects(projects)));
+  private void doIndex(BulkIndexer bulk, ViewDoc viewDoc, boolean needClearCache) {
+    bulk.add(newUpsertRequest(viewDoc));
+    if (needClearCache) {
+      clearLookupCache(viewDoc.uuid());
+    }
   }
 
   private UpdateRequest newUpsertRequest(ViewDoc doc) {
@@ -117,4 +127,15 @@ public class ViewIndexer extends BaseIndexer {
       .upsert(doc.getFields());
   }
 
+  private void clearLookupCache(String viewUuid) {
+    try {
+      esClient.prepareClearCache()
+        .setFilterCache(true)
+        .setFilterKeys(IssueIndex.viewsLookupCacheKey(viewUuid))
+        .get();
+    } catch (Exception e) {
+      throw new IllegalStateException(String.format("Unable to clear lookup cache of view '%s'", viewUuid), e);
+    }
+  }
+
 }
index b62e768ceb78bc4d8f81af9bddfc2528e99246ae..d675d7438055f13db4e30677348f621ba7868f97 100644 (file)
@@ -116,11 +116,7 @@ public class ComponentTesting {
       .setQualifier(Qualifiers.VIEW);
   }
 
-  public static ComponentDto newTechnicalProject(ComponentDto project, ComponentDto view) {
-    return newTechnicalProject(Uuids.create(), project, view);
-  }
-
-  public static ComponentDto newTechnicalProject(String uuid, ComponentDto project, ComponentDto view) {
+  public static ComponentDto newProjectCopy(String uuid, ComponentDto project, ComponentDto view) {
     Preconditions.checkNotNull(project.getId(), "The project need to be persisted before creating this technical project.");
     return newChildComponent(uuid, view)
       .setUuid(uuid)
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/IndexViewsStepMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/IndexViewsStepMediumTest.java
deleted file mode 100644 (file)
index ddab04e..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-package org.sonar.server.computation.step;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.ClassRule;
-import org.junit.Test;
-import org.sonar.api.resources.Qualifiers;
-import org.sonar.api.security.DefaultGroups;
-import org.sonar.api.web.UserRole;
-import org.sonar.core.component.ComponentDto;
-import org.sonar.core.issue.db.IssueDto;
-import org.sonar.core.permission.GlobalPermissions;
-import org.sonar.core.persistence.DbSession;
-import org.sonar.core.rule.RuleDto;
-import org.sonar.server.component.ComponentTesting;
-import org.sonar.server.component.db.ComponentDao;
-import org.sonar.server.computation.ComputationContext;
-import org.sonar.server.db.DbClient;
-import org.sonar.server.issue.IssueQuery;
-import org.sonar.server.issue.IssueTesting;
-import org.sonar.server.issue.db.IssueDao;
-import org.sonar.server.issue.index.IssueIndex;
-import org.sonar.server.issue.index.IssueIndexer;
-import org.sonar.server.permission.InternalPermissionService;
-import org.sonar.server.permission.PermissionChange;
-import org.sonar.server.rule.RuleTesting;
-import org.sonar.server.rule.db.RuleDao;
-import org.sonar.server.search.QueryContext;
-import org.sonar.server.tester.ServerTester;
-import org.sonar.server.user.MockUserSession;
-import org.sonar.server.view.index.ViewIndexer;
-
-import static com.google.common.collect.Lists.newArrayList;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-/**
- * It's still not possible to only used EsTester as IssueIndex does not support it yet.
- */
-public class IndexViewsStepMediumTest {
-
-  ComputationContext context;
-
-  DbSession dbSession;
-
-  ViewIndexer indexer;
-
-  IndexViewsStep step;
-
-  @ClassRule
-  public static ServerTester tester = new ServerTester().addComponents(IndexViewsStep.class);
-
-  IssueIndex index;
-
-  @Before
-  public void setUp() throws Exception {
-    tester.clearIndexes();
-    context = mock(ComputationContext.class);
-    dbSession = tester.get(DbClient.class).openSession(false);
-    index = tester.get(IssueIndex.class);
-    step = tester.get(IndexViewsStep.class);
-  }
-
-  @After
-  public void after() {
-    dbSession.close();
-  }
-
-  @Test
-  public void clear_cache_of_issue_on_view_filter() throws Exception {
-    String viewUuid = "ABCD";
-    when(context.getProject()).thenReturn(ComponentTesting.newProjectDto(viewUuid).setQualifier(Qualifiers.VIEW));
-
-    RuleDto rule = RuleTesting.newXooX1();
-    tester.get(RuleDao.class).insert(dbSession, rule);
-    ComponentDto project1 = addProjectWithIssue(rule);
-
-    ComponentDto view = ComponentTesting.newView("ABCD");
-    ComponentDto techProject1 = ComponentTesting.newTechnicalProject("CDEF", project1, view);
-    tester.get(ComponentDao.class).insert(dbSession, view, techProject1);
-    dbSession.commit();
-    tester.get(ViewIndexer.class).index(viewUuid);
-
-    // Execute issue query on view -> 1 issue on view (and filter on view will be set in cache)
-    assertThat(tester.get(IssueIndex.class).search(IssueQuery.builder().viewUuids(newArrayList(viewUuid)).build(), new QueryContext()).getHits()).hasSize(1);
-
-    // Add a project to the view
-    ComponentDto project2 = addProjectWithIssue(rule);
-    ComponentDto techProject2 = ComponentTesting.newTechnicalProject("EFGH", project2, view);
-    tester.get(ComponentDao.class).insert(dbSession, techProject2);
-    dbSession.commit();
-
-    // Execute issue query on view -> Still 1 issue on view, issue on project2 is not yet visible
-    assertThat(tester.get(IssueIndex.class).search(IssueQuery.builder().viewUuids(newArrayList(viewUuid)).build(), new QueryContext()).getHits()).hasSize(1);
-
-    step.execute(context);
-
-    // Execute issue query on view -> issue of project2 are well taken into account
-    assertThat(tester.get(IssueIndex.class).search(IssueQuery.builder().viewUuids(newArrayList(viewUuid)).build(), new QueryContext()).getHits()).hasSize(2);
-  }
-
-  private ComponentDto addProjectWithIssue(RuleDto rule) {
-    ComponentDto project = ComponentTesting.newProjectDto();
-    ComponentDto file = ComponentTesting.newFileDto(project);
-    tester.get(ComponentDao.class).insert(dbSession, project, file);
-
-    IssueDto issue = IssueTesting.newDto(rule, file, project);
-    tester.get(IssueDao.class).insert(dbSession, issue);
-    dbSession.commit();
-
-    setDefaultProjectPermission(project);
-    tester.get(IssueIndexer.class).indexAll();
-
-    return project;
-  }
-
-  private void setDefaultProjectPermission(ComponentDto project) {
-    // project can be seen by anyone and by code viewer
-    MockUserSession.set().setLogin("admin").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
-    tester.get(InternalPermissionService.class).addPermission(new PermissionChange().setComponentKey(project.getKey()).setGroup(DefaultGroups.ANYONE).setPermission(UserRole.USER));
-    MockUserSession.set();
-  }
-}
index 0144eb0c6484f16225805b599b7fd3031f7e0c86..36e973f74111a62e35a41888a171a865cc830651 100644 (file)
@@ -79,10 +79,10 @@ public class PurgeRemovedViewsStepTest {
     when(context.getProject()).thenReturn(ComponentTesting.newProjectDto("DBCA").setQualifier(Qualifiers.VIEW));
 
     esTester.putDocuments(ViewIndexDefinition.INDEX, ViewIndexDefinition.TYPE_VIEW,
-      new ViewDoc().setUuid("ABCD").getFields(),
-      new ViewDoc().setUuid("BCDE").getFields(),
+      new ViewDoc().setUuid("ABCD"),
+      new ViewDoc().setUuid("BCDE"),
       // Should be removed as it no more exists in db
-      new ViewDoc().setUuid("CDEF").getFields());
+      new ViewDoc().setUuid("CDEF"));
 
     ComponentDto view = ComponentTesting.newProjectDto("ABCD").setQualifier(Qualifiers.VIEW);
     ComponentDto subView = ComponentTesting.newModuleDto("BCDE", view).setQualifier(Qualifiers.SUBVIEW);
@@ -94,4 +94,23 @@ public class PurgeRemovedViewsStepTest {
     List<String> viewUuids = esTester.getDocumentFields(ViewIndexDefinition.INDEX, ViewIndexDefinition.TYPE_VIEW, ViewIndexDefinition.FIELD_UUID);
     assertThat(viewUuids).containsOnly("ABCD", "BCDE");
   }
+
+  @Test
+  public void nothing_to_do_when_not_analysing_view() throws Exception {
+    when(context.getProject()).thenReturn(ComponentTesting.newProjectDto("DBCA"));
+
+    esTester.putDocuments(ViewIndexDefinition.INDEX, ViewIndexDefinition.TYPE_VIEW,
+      new ViewDoc().setUuid("ABCD"),
+      // This vies does not exists in db...
+      new ViewDoc().setUuid("BCDE"));
+
+    dbClient.componentDao().insert(session, ComponentTesting.newProjectDto("ABCD").setQualifier(Qualifiers.VIEW));
+    session.commit();
+
+    step.execute(context);
+
+    // ... But it should not be removed as the project of the context is not a view
+    assertThat(esTester.countDocuments(ViewIndexDefinition.INDEX, ViewIndexDefinition.TYPE_VIEW)).isEqualTo(2);
+  }
+
 }
index 638efc1de1e2c61938f2003e40a0a5c356432554..186722ff74b8f32d2c2dcf1fe632c26879f04ad3 100644 (file)
@@ -51,7 +51,6 @@ import java.io.File;
 import java.io.FileInputStream;
 import java.util.Collections;
 import java.util.List;
-import java.util.Map;
 
 import static com.google.common.collect.Lists.newArrayList;
 import static org.assertj.core.api.Assertions.assertThat;
@@ -158,10 +157,10 @@ public class EsTester extends ExternalResource {
     bulk.get();
   }
 
-  public void putDocuments(String index, String type, Map<String, Object>... docs) throws Exception {
+  public void putDocuments(String index, String type, BaseDoc... docs) throws Exception {
     BulkRequestBuilder bulk = client.prepareBulk().setRefresh(true);
-    for (Map<String, Object> doc : docs) {
-      bulk.add(new IndexRequest(index, type).source(doc));
+    for (BaseDoc doc : docs) {
+      bulk.add(new IndexRequest(index, type).source(doc.getFields()));
     }
     bulk.get();
   }
diff --git a/server/sonar-server/src/test/java/org/sonar/server/es/request/ProxyClearCacheRequestBuilderTest.java b/server/sonar-server/src/test/java/org/sonar/server/es/request/ProxyClearCacheRequestBuilderTest.java
new file mode 100644 (file)
index 0000000..6b31392
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.server.es.request;
+
+import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheRequestBuilder;
+import org.elasticsearch.common.unit.TimeValue;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.config.Settings;
+import org.sonar.core.profiling.Profiling;
+import org.sonar.server.es.EsTester;
+import org.sonar.server.search.SearchClient;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.fail;
+
+public class ProxyClearCacheRequestBuilderTest {
+
+  @Rule
+  public EsTester esTester = new EsTester();
+
+  @Test
+  public void clear_cache() {
+    ClearIndicesCacheRequestBuilder requestBuilder = esTester.client().prepareClearCache();
+    requestBuilder.get();
+  }
+
+  @Test
+  public void to_string() {
+    assertThat(esTester.client().prepareClearCache().toString()).isEqualTo("ES clear cache request");
+    assertThat(esTester.client().prepareClearCache("rules").toString()).isEqualTo("ES clear cache request on indices 'rules'");
+    assertThat(esTester.client().prepareClearCache().setFields("key").toString()).isEqualTo("ES clear cache request on fields 'key'");
+    assertThat(esTester.client().prepareClearCache().setFilterKeys("rule1").toString()).isEqualTo("ES clear cache request on filterKeys 'rule1'");
+    assertThat(esTester.client().prepareClearCache().setFilterCache(true).toString()).isEqualTo("ES clear cache request with filter cache");
+    assertThat(esTester.client().prepareClearCache().setFieldDataCache(true).toString()).isEqualTo("ES clear cache request with field data cache");
+    assertThat(esTester.client().prepareClearCache().setIdCache(true).toString()).isEqualTo("ES clear cache request with id cache");
+  }
+
+  @Test
+  public void with_profiling_basic() {
+    Profiling profiling = new Profiling(new Settings().setProperty(Profiling.CONFIG_PROFILING_LEVEL, Profiling.Level.BASIC.name()));
+    SearchClient searchClient = new SearchClient(new Settings(), profiling);
+
+    ClearIndicesCacheRequestBuilder requestBuilder = esTester.client().prepareClearCache();
+    requestBuilder.get();
+
+    // TODO assert profiling
+    searchClient.stop();
+  }
+
+  @Test
+  public void get_with_string_timeout_is_not_yet_implemented() throws Exception {
+    try {
+      esTester.client().prepareClearCache().get("1");
+      fail();
+    } catch (Exception e) {
+      assertThat(e).isInstanceOf(IllegalStateException.class).hasMessage("Not yet implemented");
+    }
+  }
+
+  @Test
+  public void get_with_time_value_timeout_is_not_yet_implemented() throws Exception {
+    try {
+      esTester.client().prepareClearCache().get(TimeValue.timeValueMinutes(1));
+      fail();
+    } catch (Exception e) {
+      assertThat(e).isInstanceOf(IllegalStateException.class).hasMessage("Not yet implemented");
+    }
+  }
+
+  @Test
+  public void execute_should_throw_an_unsupported_operation_exception() throws Exception {
+    try {
+      esTester.client().prepareClearCache().execute();
+      fail();
+    } catch (Exception e) {
+      assertThat(e).isInstanceOf(UnsupportedOperationException.class).hasMessage("execute() should not be called as it's used for asynchronous");
+    }
+  }
+
+}
index 78e76a05280afa03abc5c23b8232c278d8e55ddc..ea25bf28e0d2378a7b07c2804d4af36b67dba920 100644 (file)
 
 package org.sonar.server.platform;
 
-import org.junit.After;
+import com.google.common.collect.ImmutableMap;
 import org.junit.Before;
 import org.junit.ClassRule;
 import org.junit.Test;
-import org.sonar.api.security.DefaultGroups;
-import org.sonar.api.web.UserRole;
-import org.sonar.core.component.ComponentDto;
-import org.sonar.core.component.SnapshotDto;
-import org.sonar.core.issue.db.IssueDto;
-import org.sonar.core.permission.GlobalPermissions;
-import org.sonar.core.persistence.DbSession;
-import org.sonar.core.rule.RuleDto;
-import org.sonar.server.component.ComponentTesting;
-import org.sonar.server.component.SnapshotTesting;
-import org.sonar.server.component.db.ComponentDao;
-import org.sonar.server.db.DbClient;
+import org.junit.experimental.categories.Category;
+import org.sonar.core.persistence.DbTester;
+import org.sonar.server.es.EsTester;
 import org.sonar.server.issue.IssueTesting;
-import org.sonar.server.issue.db.IssueDao;
-import org.sonar.server.issue.index.IssueIndex;
-import org.sonar.server.issue.index.IssueIndexer;
-import org.sonar.server.permission.InternalPermissionService;
-import org.sonar.server.permission.PermissionChange;
+import org.sonar.server.issue.index.IssueIndexDefinition;
 import org.sonar.server.rule.RuleTesting;
-import org.sonar.server.rule.db.RuleDao;
-import org.sonar.server.rule.index.RuleIndex;
-import org.sonar.server.tester.ServerTester;
-import org.sonar.server.user.MockUserSession;
-
+import org.sonar.server.rule.index.RuleDoc;
+import org.sonar.server.rule.index.RuleNormalizer;
+import org.sonar.server.search.IndexDefinition;
+import org.sonar.server.source.index.SourceLineDoc;
+import org.sonar.server.source.index.SourceLineIndexDefinition;
+import org.sonar.server.view.index.ViewDoc;
+import org.sonar.server.view.index.ViewIndexDefinition;
+import org.sonar.test.DbTests;
+
+import static com.google.common.collect.Lists.newArrayList;
 import static org.assertj.core.api.Assertions.assertThat;
 
+@Category(DbTests.class)
 public class BackendCleanupMediumTest {
 
   @ClassRule
-  public static ServerTester tester = new ServerTester();
+  public static EsTester esTester = new EsTester();
 
-  DbClient db;
-  DbSession session;
-  RuleDto rule;
-  ComponentDto project;
-  ComponentDto file;
-  IssueDto issue;
+  @ClassRule
+  public static DbTester dbTester = new DbTester();
 
   BackendCleanup backendCleanup;
 
   @Before
   public void setUp() throws Exception {
-    tester.clearDbAndIndexes();
-    db = tester.get(DbClient.class);
-    session = db.openSession(false);
-    backendCleanup = tester.get(BackendCleanup.class);
-
-    rule = RuleTesting.newXooX1();
-    tester.get(RuleDao.class).insert(session, rule);
-
-    project = ComponentTesting.newProjectDto().setKey("MyProject");
-    tester.get(ComponentDao.class).insert(session, project);
-    SnapshotDto projectSnapshot = SnapshotTesting.createForProject(project);
-    db.snapshotDao().insert(session, projectSnapshot);
-
-    file = ComponentTesting.newFileDto(project).setKey("MyComponent");
-    tester.get(ComponentDao.class).insert(session, file);
-    db.snapshotDao().insert(session, SnapshotTesting.createForComponent(file, projectSnapshot));
-    session.commit();
-    // project can be seen by anyone
-    MockUserSession.set().setLogin("admin").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
-    tester.get(InternalPermissionService.class).addPermission(new PermissionChange().setComponentKey(project.getKey()).setGroup(DefaultGroups.ANYONE).setPermission(UserRole.USER));
-
-    issue = IssueTesting.newDto(rule, file, project);
-    tester.get(IssueDao.class).insert(session, issue);
-    session.commit();
-    tester.get(IssueIndexer.class).indexAll();
-  }
-
-  @After
-  public void after() {
-    session.close();
+    backendCleanup = new BackendCleanup(esTester.client(), dbTester.myBatis());
   }
 
   @Test
   public void clear_db() throws Exception {
-    backendCleanup.clearDb();
-    session.commit();
+    dbTester.prepareDbUnit(getClass(), "shared.xml");
 
-    // Everything should be removed from db
-    assertThat(tester.get(ComponentDao.class).getNullableByKey(session, project.key())).isNull();
-    assertThat(tester.get(ComponentDao.class).getNullableByKey(session, file.key())).isNull();
-    assertThat(tester.get(IssueDao.class).selectNullableByKey(session, file.key())).isNull();
-    assertThat(tester.get(RuleDao.class).getNullableByKey(session, rule.getKey())).isNull();
+    backendCleanup.clearDb();
 
-    // Nothing should be removed from indexes
-    assertThat(tester.get(IssueIndex.class).getNullableByKey(issue.getKey())).isNotNull();
-    assertThat(tester.get(RuleIndex.class).getNullableByKey(rule.getKey())).isNotNull();
+    assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(0);
+    assertThat(dbTester.countRowsOfTable("snapshots")).isEqualTo(0);
+    assertThat(dbTester.countRowsOfTable("rules")).isEqualTo(0);
+    assertThat(dbTester.countRowsOfTable("properties")).isEqualTo(0);
   }
 
   @Test
   public void clear_indexes() throws Exception {
-    backendCleanup.clearIndexes();
-    session.commit();
+    esTester.putDocuments(IssueIndexDefinition.INDEX, IssueIndexDefinition.TYPE_ISSUE, IssueTesting.newDoc());
+    esTester.putDocuments(IndexDefinition.RULE.getIndexName(), IndexDefinition.RULE.getIndexType(), newRuleDoc());
 
-    // Nothing should be removed from db
-    assertThat(tester.get(ComponentDao.class).getNullableByKey(session, project.key())).isNotNull();
-    assertThat(tester.get(ComponentDao.class).getNullableByKey(session, file.key())).isNotNull();
-    assertThat(tester.get(IssueDao.class).selectNullableByKey(session, issue.getKey())).isNotNull();
-    assertThat(tester.get(RuleDao.class).getNullableByKey(session, rule.getKey())).isNotNull();
+    backendCleanup.clearIndexes();
 
-    // Everything should be removed from indexes
-    assertThat(tester.get(IssueIndex.class).getNullableByKey(issue.getKey())).isNull();
-    assertThat(tester.get(RuleIndex.class).getNullableByKey(rule.getKey())).isNull();
+    assertThat(esTester.countDocuments(IssueIndexDefinition.INDEX, IssueIndexDefinition.TYPE_ISSUE)).isEqualTo(0);
   }
 
   @Test
   public void clear_all() throws Exception {
+    dbTester.prepareDbUnit(getClass(), "shared.xml");
+    esTester.putDocuments(IssueIndexDefinition.INDEX, IssueIndexDefinition.TYPE_ISSUE, IssueTesting.newDoc());
+    esTester.putDocuments(IndexDefinition.RULE.getIndexName(), IndexDefinition.RULE.getIndexType(), newRuleDoc());
+
     backendCleanup.clearAll();
-    session.commit();
 
-    // Everything should be removed from db
-    assertThat(tester.get(ComponentDao.class).getNullableByKey(session, project.key())).isNull();
-    assertThat(tester.get(ComponentDao.class).getNullableByKey(session, file.key())).isNull();
-    assertThat(tester.get(IssueDao.class).selectNullableByKey(session, file.key())).isNull();
-    assertThat(tester.get(RuleDao.class).getNullableByKey(session, rule.getKey())).isNull();
+    assertThat(esTester.countDocuments(IssueIndexDefinition.INDEX, IssueIndexDefinition.TYPE_ISSUE)).isEqualTo(0);
+    assertThat(esTester.countDocuments(IndexDefinition.RULE.getIndexName(), IndexDefinition.RULE.getIndexType())).isEqualTo(0);
 
-    // Everything should be removed from indexes
-    assertThat(tester.get(IssueIndex.class).getNullableByKey(issue.getKey())).isNull();
-    assertThat(tester.get(RuleIndex.class).getNullableByKey(rule.getKey())).isNull();
+    assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(0);
+    assertThat(dbTester.countRowsOfTable("snapshots")).isEqualTo(0);
+    assertThat(dbTester.countRowsOfTable("rules")).isEqualTo(0);
+    assertThat(dbTester.countRowsOfTable("properties")).isEqualTo(0);
   }
 
   @Test
   public void reset_data() throws Exception {
+    dbTester.prepareDbUnit(getClass(), "shared.xml");
+    esTester.putDocuments(IssueIndexDefinition.INDEX, IssueIndexDefinition.TYPE_ISSUE, IssueTesting.newDoc());
+    esTester.putDocuments(SourceLineIndexDefinition.INDEX, SourceLineIndexDefinition.TYPE, new SourceLineDoc().setProjectUuid("ABCD").setFileUuid("BCDE"));
+    esTester.putDocuments(ViewIndexDefinition.INDEX, ViewIndexDefinition.TYPE_VIEW, new ViewDoc().setUuid("CDEF").setProjects(newArrayList("DEFG")));
+    esTester.putDocuments(IndexDefinition.RULE.getIndexName(), IndexDefinition.RULE.getIndexType(), newRuleDoc());
+
     backendCleanup.resetData();
-    session.commit();
 
-    // Every projects and issues are removed (from db and indexes)
-    assertThat(tester.get(ComponentDao.class).getNullableByKey(session, project.key())).isNull();
-    assertThat(tester.get(ComponentDao.class).getNullableByKey(session, file.key())).isNull();
-    assertThat(tester.get(IssueDao.class).selectNullableByKey(session, issue.getKey())).isNull();
-    assertThat(tester.get(IssueIndex.class).getNullableByKey(issue.getKey())).isNull();
+    assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(0);
+    assertThat(dbTester.countRowsOfTable("snapshots")).isEqualTo(0);
+    assertThat(dbTester.countRowsOfTable("properties")).isEqualTo(0);
+    assertThat(esTester.countDocuments(IssueIndexDefinition.INDEX, IssueIndexDefinition.TYPE_ISSUE)).isEqualTo(0);
+    assertThat(esTester.countDocuments(SourceLineIndexDefinition.INDEX, SourceLineIndexDefinition.TYPE)).isEqualTo(0);
+    assertThat(esTester.countDocuments(ViewIndexDefinition.INDEX, ViewIndexDefinition.TYPE_VIEW)).isEqualTo(0);
+
+    // Rules should not be removed
+    assertThat(dbTester.countRowsOfTable("rules")).isEqualTo(1);
+    assertThat(esTester.countDocuments(IndexDefinition.RULE.getIndexName(), IndexDefinition.RULE.getIndexType())).isEqualTo(1);
+  }
 
-    // Every rules should not be removed (from db and indexes)
-    assertThat(tester.get(RuleDao.class).getNullableByKey(session, rule.getKey())).isNotNull();
-    assertThat(tester.get(RuleIndex.class).getNullableByKey(rule.getKey())).isNotNull();
+  private static RuleDoc newRuleDoc() {
+    return new RuleDoc(ImmutableMap.<String, Object>of(RuleNormalizer.RuleField.RULE_KEY.field(), RuleTesting.XOO_X1));
   }
 }
diff --git a/server/sonar-server/src/test/java/org/sonar/server/view/index/ViewIndexerMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/view/index/ViewIndexerMediumTest.java
new file mode 100644 (file)
index 0000000..3be8d4e
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.server.view.index;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.sonar.api.security.DefaultGroups;
+import org.sonar.api.web.UserRole;
+import org.sonar.core.component.ComponentDto;
+import org.sonar.core.issue.db.IssueDto;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.rule.RuleDto;
+import org.sonar.server.component.ComponentTesting;
+import org.sonar.server.component.db.ComponentDao;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.issue.IssueQuery;
+import org.sonar.server.issue.IssueTesting;
+import org.sonar.server.issue.db.IssueDao;
+import org.sonar.server.issue.index.IssueIndex;
+import org.sonar.server.issue.index.IssueIndexer;
+import org.sonar.server.permission.InternalPermissionService;
+import org.sonar.server.permission.PermissionChange;
+import org.sonar.server.rule.RuleTesting;
+import org.sonar.server.rule.db.RuleDao;
+import org.sonar.server.search.QueryContext;
+import org.sonar.server.tester.ServerTester;
+import org.sonar.server.user.MockUserSession;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * It's not possible to only used EsTester as IssueIndex does not support it yet.
+ *
+ * This class
+ */
+public class ViewIndexerMediumTest {
+
+  @ClassRule
+  public static ServerTester tester = new ServerTester();
+
+  DbSession dbSession;
+
+  ViewIndexer indexer;
+
+  IssueIndex index;
+
+  @Before
+  public void setUp() throws Exception {
+    tester.clearDbAndIndexes();
+    dbSession = tester.get(DbClient.class).openSession(false);
+    index = tester.get(IssueIndex.class);
+    indexer = tester.get(ViewIndexer.class);
+  }
+
+  @After
+  public void after() {
+    dbSession.close();
+  }
+
+  @Test
+  public void clear_views_lookup_cache_on_index_view_uuid() throws Exception {
+    String viewUuid = "ABCD";
+
+    RuleDto rule = RuleTesting.newXooX1();
+    tester.get(RuleDao.class).insert(dbSession, rule);
+    ComponentDto project1 = addProjectWithIssue(rule);
+
+    ComponentDto view = ComponentTesting.newView("ABCD");
+    ComponentDto techProject1 = ComponentTesting.newProjectCopy("CDEF", project1, view);
+    tester.get(ComponentDao.class).insert(dbSession, view, techProject1);
+    dbSession.commit();
+
+    // First view indexation
+    indexer.index(viewUuid);
+
+    // Execute issue query on view -> 1 issue on view
+    assertThat(tester.get(IssueIndex.class).search(IssueQuery.builder().viewUuids(newArrayList(viewUuid)).build(), new QueryContext()).getHits()).hasSize(1);
+
+    // Add a project to the view and index it again
+    ComponentDto project2 = addProjectWithIssue(rule);
+    ComponentDto techProject2 = ComponentTesting.newProjectCopy("EFGH", project2, view);
+    tester.get(ComponentDao.class).insert(dbSession, techProject2);
+    dbSession.commit();
+    indexer.index(viewUuid);
+
+    // Execute issue query on view -> issue of project2 are well taken into account : the cache has been cleared
+    assertThat(tester.get(IssueIndex.class).search(IssueQuery.builder().viewUuids(newArrayList(viewUuid)).build(), new QueryContext()).getHits()).hasSize(2);
+  }
+
+  private ComponentDto addProjectWithIssue(RuleDto rule) {
+    ComponentDto project = ComponentTesting.newProjectDto();
+    ComponentDto file = ComponentTesting.newFileDto(project);
+    tester.get(ComponentDao.class).insert(dbSession, project, file);
+
+    IssueDto issue = IssueTesting.newDto(rule, file, project);
+    tester.get(IssueDao.class).insert(dbSession, issue);
+    dbSession.commit();
+
+    setDefaultProjectPermission(project);
+    tester.get(IssueIndexer.class).indexAll();
+
+    return project;
+  }
+
+  private void setDefaultProjectPermission(ComponentDto project) {
+    // project can be seen by anyone and by code viewer
+    MockUserSession.set().setLogin("admin").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
+    tester.get(InternalPermissionService.class).addPermission(new PermissionChange().setComponentKey(project.getKey()).setGroup(DefaultGroups.ANYONE).setPermission(UserRole.USER));
+    MockUserSession.set();
+  }
+
+}
index 2b80ab88c5b5481d7820fa4e8b454dea7cac95ca..6e3c26f7d4661fc6e1a25e3361f86895d567628f 100644 (file)
@@ -88,7 +88,7 @@ public class ViewIndexerTest {
     // Some views are not in the db
     dbTester.prepareDbUnit(getClass(), "index.xml");
     esTester.putDocuments(ViewIndexDefinition.INDEX, ViewIndexDefinition.TYPE_VIEW,
-      new ViewDoc().setUuid("ABCD").setProjects(newArrayList("BCDE")).getFields());
+      new ViewDoc().setUuid("ABCD").setProjects(newArrayList("BCDE")));
 
     indexer.index();
 
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/platform/BackendCleanupMediumTest/shared.xml b/server/sonar-server/src/test/resources/org/sonar/server/platform/BackendCleanupMediumTest/shared.xml
new file mode 100644 (file)
index 0000000..3ac6d66
--- /dev/null
@@ -0,0 +1,22 @@
+<dataset>
+
+  <projects id="100" scope="PRJ" qualifier="TRK" kee="org.struts:struts" name="Struts"
+            uuid="JKLM" project_uuid="JKLM" module_uuid="[null]" module_uuid_path="."
+            enabled="[true]" copy_resource_id="[null]" path="[null]"/>
+
+  <snapshots id="100" project_id="100" parent_snapshot_id="[null]" root_project_id="100" root_snapshot_id="[null]"
+             status="P" islast="[true]" purge_status="[null]"
+             depth="[null]" scope="PRJ" qualifier="TRK" version="[null]" path=""/>
+
+  <rules tags="[null]" system_tags="[null]" id="1" plugin_rule_key="NewRuleKey" plugin_name="plugin" name="new name" description="new description" status="DEPRECATED"
+         plugin_config_key="NewConfigKey" priority="0" is_template="[true]" language="dart" created_at="2013-12-16" updated_at="2013-12-16" template_id="3"
+         note_data="[null]" note_user_login="[null]" note_created_at="[null]" note_updated_at="[null]"
+         characteristic_id="100" default_characteristic_id="101"
+         remediation_function="LINEAR" default_remediation_function="LINEAR_OFFSET"
+         remediation_coeff="1h" default_remediation_coeff="5d"
+         remediation_offset="5min" default_remediation_offset="10h"
+         effort_to_fix_description="squid.S115.effortToFix" description_format="MARKDOWN"/>
+
+  <properties id="1" prop_key="sonar.profile.java" text_value="Sonar Way" resource_id="1" user_id="[null]"/>
+
+</dataset>