]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-4832 Cleanup a bit experiment leftovers
authorJean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com>
Thu, 7 Nov 2013 11:06:36 +0000 (12:06 +0100)
committerJean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com>
Fri, 8 Nov 2013 17:21:45 +0000 (18:21 +0100)
Introduce elasticsearch-test for ES integration tests
Enhance coverage on SearchIndex
Rename node in SearchNode
Unplug index at startup (will be triggered by call from RegisterRule to
RuleRegistry)

sonar-server/pom.xml
sonar-server/src/main/java/org/sonar/server/platform/Platform.java
sonar-server/src/main/java/org/sonar/server/rule/RuleRegistry.java [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/search/SearchIndex.java
sonar-server/src/main/java/org/sonar/server/search/SearchNode.java
sonar-server/src/main/java/org/sonar/server/startup/IndexRules.java [deleted file]
sonar-server/src/test/java/org/sonar/server/search/SearchIndexTest.java
sonar-server/src/test/resources/org/sonar/server/search/SearchIndexTest/correct_mapping1.json [new file with mode: 0644]
sonar-server/src/test/resources/org/sonar/server/search/SearchIndexTest/correct_mapping2.json [new file with mode: 0644]
sonar-server/src/test/resources/org/sonar/server/search/SearchIndexTest/malformed.json [new file with mode: 0644]

index ed96eff0aa295b5d6a45ddc54c712b2e6f11d7e1..e67c953a9b832155674d02ee0c58bb6e88dc102b 100644 (file)
       <artifactId>sonar-testing-harness</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>com.github.tlrx</groupId>
+      <artifactId>elasticsearch-test</artifactId>
+      <version>${elasticsearch.version}</version>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 
 
index 777e93e08ccdbd801e2a6c7b2e86da21e2b47f8b..c7e56a72e1903d62e36ab6000db736abdefc1a25 100644 (file)
@@ -19,6 +19,8 @@
  */
 package org.sonar.server.platform;
 
+import org.sonar.server.rule.RuleRegistry;
+
 import org.apache.commons.configuration.BaseConfiguration;
 import org.slf4j.LoggerFactory;
 import org.sonar.api.config.EmailSettings;
@@ -354,7 +356,7 @@ public final class Platform {
     startupContainer.addSingleton(LogServerId.class);
     startupContainer.addSingleton(RegisterServletFilters.class);
     startupContainer.addSingleton(CleanDryRunCache.class);
-    startupContainer.addSingleton(IndexRules.class);
+    startupContainer.addSingleton(RuleRegistry.class);
     startupContainer.startComponents();
 
     startupContainer.getComponentByType(ServerLifecycleNotifier.class).notifyStart();
diff --git a/sonar-server/src/main/java/org/sonar/server/rule/RuleRegistry.java b/sonar-server/src/main/java/org/sonar/server/rule/RuleRegistry.java
new file mode 100644 (file)
index 0000000..de7ffa4
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.rule;
+
+import org.elasticsearch.common.collect.Lists;
+import org.elasticsearch.common.io.BytesStream;
+import org.elasticsearch.common.xcontent.XContentBuilder;
+import org.elasticsearch.common.xcontent.XContentFactory;
+import org.sonar.api.database.DatabaseSession;
+import org.sonar.api.rules.Rule;
+import org.sonar.api.rules.RuleParam;
+import org.sonar.core.i18n.RuleI18nManager;
+import org.sonar.jpa.session.DatabaseSessionFactory;
+import org.sonar.server.search.SearchIndex;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * Fill search index with rules
+ * @since 4.1
+ */
+public final class RuleRegistry {
+
+  private static final String INDEX_RULES = "rules";
+  private static final String TYPE_RULE = "rule";
+
+  private SearchIndex searchIndex;
+  private DatabaseSessionFactory sessionFactory;
+  private RuleI18nManager ruleI18nManager;
+
+  public RuleRegistry(SearchIndex searchIndex, DatabaseSessionFactory sessionFactory, RuleI18nManager ruleI18nManager) {
+    this.searchIndex = searchIndex;
+    this.sessionFactory = sessionFactory;
+    this.ruleI18nManager = ruleI18nManager;
+  }
+
+  public void start() {
+    searchIndex.addMappingFromClasspath(INDEX_RULES, TYPE_RULE, "/com/sonar/search/rule_mapping.json");
+  }
+
+  public void bulkRegisterRules() {
+    DatabaseSession session = sessionFactory.getSession();
+
+    try {
+      List<String> ids = Lists.newArrayList();
+      List<BytesStream> docs = Lists.newArrayList();
+      for (Rule rule: session.getResults(Rule.class)) {
+        ids.add(rule.getId().toString());
+        XContentBuilder document = XContentFactory.jsonBuilder()
+            .startObject()
+            .field("id", rule.getId())
+            .field("key", rule.ruleKey())
+            .field("language", rule.getLanguage())
+            .field("name", ruleI18nManager.getName(rule, Locale.getDefault()))
+            .field("description", ruleI18nManager.getDescription(rule.getRepositoryKey(), rule.getKey(), Locale.getDefault()))
+            .field("parentKey", rule.getParent() == null ? null : rule.getParent().getKey())
+            .field("repositoryKey", rule.getRepositoryKey())
+            .field("severity", rule.getSeverity())
+            .field("status", rule.getStatus())
+            .field("createdAt", rule.getCreatedAt())
+            .field("updatedAt", rule.getUpdatedAt());
+        if(!rule.getParams().isEmpty()) {
+          document.startArray("params");
+          for (RuleParam param: rule.getParams()) {
+            document.startObject()
+              .field("key", param.getKey())
+              .field("type", param.getType())
+              .field("defaultValue", param.getDefaultValue())
+              .field("description", param.getDescription())
+              .endObject();
+          }
+          document.endArray();
+        }
+        docs.add(document.endObject());
+      }
+      searchIndex.bulkIndex(INDEX_RULES, TYPE_RULE, ids.toArray(new String[0]), docs.toArray(new BytesStream[0]));
+    } catch(IOException ioe) {
+      throw new IllegalStateException("Unable to index rules", ioe);
+    }
+  }
+}
index 99704461929204e7f7df75f9ed73c4632bd52839..8935db2faba478c6f5d9cd00fda0bc22060751af 100644 (file)
@@ -20,6 +20,7 @@
 package org.sonar.server.search;
 
 import org.apache.commons.io.IOUtils;
+import org.elasticsearch.ElasticSearchParseException;
 import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsRequest;
 import org.elasticsearch.action.bulk.BulkItemResponse;
 import org.elasticsearch.action.bulk.BulkRequestBuilder;
@@ -29,7 +30,6 @@ import org.elasticsearch.client.Client;
 import org.elasticsearch.client.IndicesAdminClient;
 import org.elasticsearch.client.Requests;
 import org.elasticsearch.common.io.BytesStream;
-import org.elasticsearch.index.query.QueryBuilders;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -61,10 +61,6 @@ public class SearchIndex {
     client.prepareIndex(index, type, id).setSource(source.bytes()).execute().actionGet();
   }
 
-  public void put(String index, String type, String id, BytesStream source, String parent) {
-    client.prepareIndex(index, type, id).setParent(parent).setSource(source.bytes()).execute().actionGet();
-  }
-
   public void bulkIndex(String index, String type, String[] ids, BytesStream[] sources) {
     BulkRequestBuilder builder = new BulkRequestBuilder(client);
     for (int i=0; i<ids.length; i++) {
@@ -91,8 +87,10 @@ public class SearchIndex {
   public void addMappingFromClasspath(String index, String type, String resourcePath) {
     try {
       addMapping(index, type, IOUtils.toString(getClass().getResource(resourcePath)));
+    } catch(NullPointerException nonExisting) {
+      throw new IllegalArgumentException("Could not load unexisting file at " + resourcePath, nonExisting);
     } catch(IOException ioException) {
-      throw new IllegalStateException("Could not find mapping in classpath at "+resourcePath, ioException);
+      throw new IllegalArgumentException("Problem loading file at " + resourcePath, ioException);
     }
   }
 
@@ -105,14 +103,12 @@ public class SearchIndex {
     } catch (Exception e) {
       LOG.error("While checking for index existence", e);
     }
-    indices.putMapping(Requests.putMappingRequest(index).type(type).source(mapping)).actionGet();
-  }
 
-  public void stats(String index) {
-    LOG.info(
-      String.format(
-        "Index %s contains %d elements", index,
-        client.prepareSearch(index).setQuery(QueryBuilders.matchAllQuery()).execute().actionGet().getHits().totalHits()));
+    try {
+      indices.putMapping(Requests.putMappingRequest(index).type(type).source(mapping)).actionGet();
+    } catch(ElasticSearchParseException parseException) {
+      throw new IllegalArgumentException("Invalid mapping file", parseException);
+    }
   }
 
   public SearchResponse find(SearchQuery query) {
index 7bae90ca352897303444858df515b6117fd2fd84..d928543fc12a603304a292a4fd230c080e35fadc 100644 (file)
@@ -61,6 +61,7 @@ public class SearchNode {
   public void start() {
     LOG.info("Starting {} in {}", this.getClass().getSimpleName(), nodeDir);
     nodeSettingsBuilder
+      .put("node.name", "sonarqube")
       .put("node.path.conf", nodeDir)
       .put("node.path.data", nodeDir)
       .put("node.path.work", nodeDir)
diff --git a/sonar-server/src/main/java/org/sonar/server/startup/IndexRules.java b/sonar-server/src/main/java/org/sonar/server/startup/IndexRules.java
deleted file mode 100644 (file)
index b765b05..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.startup;
-
-import org.elasticsearch.common.collect.Lists;
-import org.elasticsearch.common.io.BytesStream;
-import org.elasticsearch.common.xcontent.XContentBuilder;
-import org.elasticsearch.common.xcontent.XContentFactory;
-import org.sonar.api.database.DatabaseSession;
-import org.sonar.api.rules.Rule;
-import org.sonar.api.rules.RuleParam;
-import org.sonar.core.i18n.RuleI18nManager;
-import org.sonar.server.search.SearchIndex;
-
-import java.io.IOException;
-import java.util.List;
-import java.util.Locale;
-
-/**
- * Fill search index with rules
- * @since 4.1
- */
-public final class IndexRules {
-
-  private static final String INDEX_RULES = "rules";
-  private static final String TYPE_RULE = "rule";
-
-  private SearchIndex searchIndex;
-  private DatabaseSession session;
-  private RuleI18nManager ruleI18nManager;
-
-  public IndexRules(SearchIndex searchIndex, DatabaseSession session, RuleI18nManager ruleI18nManager) {
-    this.searchIndex = searchIndex;
-    this.session = session;
-    this.ruleI18nManager = ruleI18nManager;
-  }
-
-  public void start() {
-
-    try {
-      searchIndex.addMappingFromClasspath(INDEX_RULES, TYPE_RULE, "/com/sonar/search/rule_mapping.json");
-      List<String> ids = Lists.newArrayList();
-      List<BytesStream> docs = Lists.newArrayList();
-      for (Rule rule: session.getResults(Rule.class)) {
-        ids.add(rule.getId().toString());
-        XContentBuilder document = XContentFactory.jsonBuilder()
-            .startObject()
-            .field("id", rule.getId())
-            .field("key", rule.ruleKey())
-            .field("language", rule.getLanguage())
-            .field("name", ruleI18nManager.getName(rule, Locale.getDefault()))
-            .field("description", ruleI18nManager.getDescription(rule.getRepositoryKey(), rule.getKey(), Locale.getDefault()))
-            .field("parentKey", rule.getParent() == null ? null : rule.getParent().getKey())
-            .field("repositoryKey", rule.getRepositoryKey())
-            .field("severity", rule.getSeverity())
-            .field("status", rule.getStatus())
-            .field("createdAt", rule.getCreatedAt())
-            .field("updatedAt", rule.getUpdatedAt());
-        if(!rule.getParams().isEmpty()) {
-          document.startArray("params");
-          for (RuleParam param: rule.getParams()) {
-            document.startObject()
-              .field("key", param.getKey())
-              .field("type", param.getType())
-              .field("defaultValue", param.getDefaultValue())
-              .field("description", param.getDescription())
-              .endObject();
-          }
-          document.endArray();
-        }
-        docs.add(document.endObject());
-      }
-      searchIndex.bulkIndex(INDEX_RULES, TYPE_RULE, ids.toArray(new String[0]), docs.toArray(new BytesStream[0]));
-    } catch(IOException ioe) {
-      throw new IllegalStateException("Unable to index rules", ioe);
-    }
-  }
-}
index f10047b8ea90df50e8aa35da571f221235f05fd5..0edd4146ff7ceee9bbdd99739c0a0cf470fbf5da 100644 (file)
 
 package org.sonar.server.search;
 
-import org.elasticsearch.client.Client;
+import com.github.tlrx.elasticsearch.test.EsSetup;
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
+import static org.fest.assertions.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 public class SearchIndexTest {
 
+  private EsSetup esSetup;
   private SearchNode searchNode;
 
-  private Client client;
-
   private SearchIndex searchIndex;
 
   @Before
   public void setUp() {
+    esSetup = new EsSetup();
+    esSetup.execute(EsSetup.deleteAll());
+
     searchNode = mock(SearchNode.class);
-    client = mock(Client.class);
-    when(searchNode.client()).thenReturn(client);
+    when(searchNode.client()).thenReturn(esSetup.client());
 
     searchIndex = new SearchIndex(searchNode);
+    searchIndex.start();
+  }
+
+  @After
+  public void tearDown() {
+    esSetup.terminate();
   }
 
   @Test
   public void should_start_and_stop_properly() {
+    verify(searchNode).client();
+    searchIndex.stop();
+  }
+
+  @Test
+  public void should_create_index_when_loading_mapping_from_classpath() {
+    String index = "index";
+    String type = "type";
+    String resourcePath = "/org/sonar/server/search/SearchIndexTest/correct_mapping1.json";
+
     searchIndex.start();
+    searchIndex.addMappingFromClasspath(index, type, resourcePath);
 
-    verify(searchNode).client();
+    assertThat(esSetup.exists(index)).isTrue();
+  }
 
-    searchIndex.stop();
+  @Test
+  public void should_reuse_index_when_loading_mapping_from_classpath() {
+    String index = "index";
+    String type1 = "type1";
+    String type2 = "type2";
+    String resourcePath1 = "/org/sonar/server/search/SearchIndexTest/correct_mapping1.json";
+    String resourcePath2 = "/org/sonar/server/search/SearchIndexTest/correct_mapping2.json";
+
+    searchIndex.start();
+    searchIndex.addMappingFromClasspath(index, type1, resourcePath1);
+    searchIndex.addMappingFromClasspath(index, type2, resourcePath2);
 
-    verify(client).close();
+    assertThat(esSetup.exists(index)).isTrue();
   }
+
+
+  @Test(expected = IllegalArgumentException.class)
+  public void should_fail_to_load_inexistent_mapping() {
+    String resourcePath = "/org/sonar/server/search/SearchIndexTest/inexistent.json";
+
+    searchIndex.start();
+    searchIndex.addMappingFromClasspath("unchecked", "unchecked", resourcePath);
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void should_fail_to_load_malformed_mapping() {
+    String resourcePath = "/org/sonar/server/search/SearchIndexTest/malformed.json";
+
+    searchIndex.start();
+    searchIndex.addMappingFromClasspath("unchecked", "unchecked", resourcePath);
+  }
+
 }
diff --git a/sonar-server/src/test/resources/org/sonar/server/search/SearchIndexTest/correct_mapping1.json b/sonar-server/src/test/resources/org/sonar/server/search/SearchIndexTest/correct_mapping1.json
new file mode 100644 (file)
index 0000000..67e2ddd
--- /dev/null
@@ -0,0 +1,9 @@
+{
+  "type1": {
+    "properties": {
+      "value": {
+        "type": "string"
+      }
+    }
+  }
+}
diff --git a/sonar-server/src/test/resources/org/sonar/server/search/SearchIndexTest/correct_mapping2.json b/sonar-server/src/test/resources/org/sonar/server/search/SearchIndexTest/correct_mapping2.json
new file mode 100644 (file)
index 0000000..d1b9448
--- /dev/null
@@ -0,0 +1,9 @@
+{
+  "type2": {
+    "properties": {
+      "value": {
+        "type": "string"
+      }
+    }
+  }
+}
diff --git a/sonar-server/src/test/resources/org/sonar/server/search/SearchIndexTest/malformed.json b/sonar-server/src/test/resources/org/sonar/server/search/SearchIndexTest/malformed.json
new file mode 100644 (file)
index 0000000..a01ad5e
--- /dev/null
@@ -0,0 +1 @@
+blarg