+++ /dev/null
-/*
- * 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;
-
-import com.google.common.annotations.VisibleForTesting;
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.io.IOUtils;
-import org.elasticsearch.action.admin.cluster.health.ClusterHealthStatus;
-import org.elasticsearch.client.Client;
-import org.elasticsearch.common.logging.ESLoggerFactory;
-import org.elasticsearch.common.logging.slf4j.Slf4jESLoggerFactory;
-import org.elasticsearch.common.settings.ImmutableSettings;
-import org.elasticsearch.node.Node;
-import org.elasticsearch.node.NodeBuilder;
-import org.picocontainer.Startable;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.config.Settings;
-import org.sonar.api.platform.ServerFileSystem;
-
-import java.io.File;
-import java.io.IOException;
-
-/**
- * ElasticSearch Node used to connect to index.
- */
-public class ESNode implements Startable {
-
- private static final Logger LOG = LoggerFactory.getLogger(ESNode.class);
-
- private static final String HTTP_ENABLED = "http.enabled";
- static final String DATA_DIR = "data/es";
-
- private static final String DEFAULT_HEALTH_TIMEOUT = "30s";
-
- private final ServerFileSystem fileSystem;
- private final Settings settings;
- private final String healthTimeout;
-
- // available only after startup
- private Node node;
-
- public ESNode(ServerFileSystem fileSystem, Settings settings) {
- this(fileSystem, settings, DEFAULT_HEALTH_TIMEOUT);
- }
-
- @VisibleForTesting
- ESNode(ServerFileSystem fileSystem, Settings settings, String healthTimeout) {
- this.fileSystem = fileSystem;
- this.settings = settings;
- this.healthTimeout = healthTimeout;
- }
-
- @Override
- public void start() {
- LOG.info("Starting Elasticsearch...");
-
- initLogging();
- ImmutableSettings.Builder esSettings = ImmutableSettings.builder()
- .loadFromUrl(getClass().getResource("config/elasticsearch.json"));
- initDirs(esSettings);
- initRestConsole(esSettings);
- initNetwork(esSettings);
-
- node = NodeBuilder.nodeBuilder()
- .settings(esSettings)
- .node();
- node.start();
-
- addIndexTemplates();
-
- if (
- node.client().admin().cluster().prepareHealth()
- .setWaitForYellowStatus()
- .setTimeout(healthTimeout)
- .execute().actionGet()
- .getStatus() == ClusterHealthStatus.RED) {
- throw new IllegalStateException(
- String.format("Elasticsearch index is corrupt, please delete directory '%s/%s' and relaunch the SonarQube server.", fileSystem.getHomeDir().getAbsolutePath(), DATA_DIR));
- }
-
- LOG.info("Elasticsearch started");
- }
-
- private void addIndexTemplates() {
- try {
- node.client().admin().indices().preparePutTemplate("default")
- .setSource(IOUtils.toString(getClass().getResource("config/templates/default.json")))
- .execute().actionGet();
- } catch (IOException ioe) {
- throw new IllegalStateException("Unable to load index templates", ioe);
- }
- }
-
- private void initLogging() {
- ESLoggerFactory.setDefaultFactory(new Slf4jESLoggerFactory());
- }
-
- private void initNetwork(ImmutableSettings.Builder esSettings) {
- esSettings.put("network.bind_host", "127.0.0.1");
- }
-
- private void initRestConsole(ImmutableSettings.Builder esSettings) {
- int httpPort = settings.getInt("sonar.es.http.port");
- if (httpPort > 0) {
- LOG.warn("Elasticsearch HTTP console enabled on port {}. Only for debugging purpose.", httpPort);
- esSettings.put(HTTP_ENABLED, true);
- esSettings.put("http.host", "127.0.0.1");
- esSettings.put("http.port", httpPort);
- } else {
- esSettings.put(HTTP_ENABLED, false);
- }
- }
-
- private void initDirs(ImmutableSettings.Builder esSettings) {
- File esDir = new File(fileSystem.getHomeDir(), DATA_DIR);
- try {
- FileUtils.forceMkdir(esDir);
- esSettings.put("path.home", esDir.getAbsolutePath());
- LOG.debug("Elasticsearch data stored in {}", esDir.getAbsolutePath());
- } catch (Exception e) {
- throw new IllegalStateException("Fail to create directory " + esDir.getAbsolutePath(), e);
- }
- }
-
- @Override
- public void stop() {
- if (node != null) {
- node.close();
- node = null;
- }
- }
-
- public Client client() {
- if (node == null) {
- throw new IllegalStateException("Elasticsearch is not started");
- }
- return node.client();
- }
-}
import org.sonar.server.debt.DebtRulesXMLImporter;
import org.sonar.server.duplication.ws.DuplicationsWriter;
import org.sonar.server.duplication.ws.DuplicationsWs;
-import org.sonar.server.es.ESNode;
+import org.sonar.server.search.ESNode;
import org.sonar.server.issue.ActionService;
import org.sonar.server.issue.AssignAction;
import org.sonar.server.issue.CommentAction;
import org.sonar.core.qualityprofile.db.ActiveRuleDto;
import org.sonar.core.qualityprofile.db.ActiveRuleKey;
import org.sonar.core.qualityprofile.db.QualityProfileKey;
-import org.sonar.server.es.ESNode;
+import org.sonar.server.search.ESNode;
import org.sonar.server.qualityprofile.ActiveRule;
import org.sonar.server.search.BaseIndex;
import org.sonar.server.search.IndexDefinition;
import org.sonar.api.rule.RuleStatus;
import org.sonar.core.cluster.WorkQueue;
import org.sonar.core.rule.RuleDto;
-import org.sonar.server.es.ESNode;
+import org.sonar.server.search.ESNode;
import org.sonar.server.qualityprofile.index.ActiveRuleNormalizer;
import org.sonar.server.rule.Rule;
import org.sonar.server.search.BaseIndex;
import org.slf4j.LoggerFactory;
import org.sonar.core.cluster.WorkQueue;
import org.sonar.core.persistence.Dto;
-import org.sonar.server.es.ESNode;
import java.io.IOException;
import java.io.Serializable;
--- /dev/null
+/*
+ * 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.search;
+
+import com.google.common.annotations.VisibleForTesting;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+import org.elasticsearch.action.admin.cluster.health.ClusterHealthStatus;
+import org.elasticsearch.client.Client;
+import org.elasticsearch.common.logging.ESLoggerFactory;
+import org.elasticsearch.common.logging.slf4j.Slf4jESLoggerFactory;
+import org.elasticsearch.common.settings.ImmutableSettings;
+import org.elasticsearch.node.Node;
+import org.elasticsearch.node.NodeBuilder;
+import org.picocontainer.Startable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.config.Settings;
+import org.sonar.api.platform.ServerFileSystem;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * ElasticSearch Node used to connect to index.
+ */
+public class ESNode implements Startable {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ESNode.class);
+
+ private static final String HTTP_ENABLED = "http.enabled";
+ static final String DATA_DIR = "data/es";
+
+ private static final String DEFAULT_HEALTH_TIMEOUT = "30s";
+
+ private final ServerFileSystem fileSystem;
+ private final Settings settings;
+ private final String healthTimeout;
+
+ // available only after startup
+ private Node node;
+
+ public ESNode(ServerFileSystem fileSystem, Settings settings) {
+ this(fileSystem, settings, DEFAULT_HEALTH_TIMEOUT);
+ }
+
+ @VisibleForTesting
+ ESNode(ServerFileSystem fileSystem, Settings settings, String healthTimeout) {
+ this.fileSystem = fileSystem;
+ this.settings = settings;
+ this.healthTimeout = healthTimeout;
+ }
+
+ @Override
+ public void start() {
+ LOG.info("Start Elasticsearch...");
+
+ initLogging();
+ ImmutableSettings.Builder esSettings = ImmutableSettings.builder()
+ .loadFromUrl(getClass().getResource("config/elasticsearch.json"));
+ initDirs(esSettings);
+ initRestConsole(esSettings);
+ initNetwork(esSettings);
+
+ node = NodeBuilder.nodeBuilder()
+ .settings(esSettings)
+ .node();
+ node.start();
+
+ addIndexTemplates();
+
+ if (
+ node.client().admin().cluster().prepareHealth()
+ .setWaitForYellowStatus()
+ .setTimeout(healthTimeout)
+ .execute().actionGet()
+ .getStatus() == ClusterHealthStatus.RED) {
+ throw new IllegalStateException(
+ String.format("Elasticsearch index is corrupt, please delete directory '%s/%s' and relaunch the SonarQube server.", fileSystem.getHomeDir().getAbsolutePath(), DATA_DIR));
+ }
+
+ LOG.info("Elasticsearch started");
+ }
+
+ private void addIndexTemplates() {
+ try {
+ node.client().admin().indices().preparePutTemplate("default")
+ .setSource(IOUtils.toString(getClass().getResource("config/templates/default.json")))
+ .execute().actionGet();
+ } catch (IOException ioe) {
+ throw new IllegalStateException("Unable to load index templates", ioe);
+ }
+ }
+
+ private void initLogging() {
+ ESLoggerFactory.setDefaultFactory(new Slf4jESLoggerFactory());
+ }
+
+ private void initNetwork(ImmutableSettings.Builder esSettings) {
+ esSettings.put("network.bind_host", "127.0.0.1");
+ }
+
+ private void initRestConsole(ImmutableSettings.Builder esSettings) {
+ int httpPort = settings.getInt("sonar.es.http.port");
+ if (httpPort > 0) {
+ LOG.warn("Elasticsearch HTTP console enabled on port {}. Only for debugging purpose.", httpPort);
+ esSettings.put(HTTP_ENABLED, true);
+ esSettings.put("http.host", "127.0.0.1");
+ esSettings.put("http.port", httpPort);
+ } else {
+ esSettings.put(HTTP_ENABLED, false);
+ }
+ }
+
+ private void initDirs(ImmutableSettings.Builder esSettings) {
+ File esDir = new File(fileSystem.getHomeDir(), DATA_DIR);
+ try {
+ FileUtils.forceMkdir(esDir);
+ esSettings.put("path.home", esDir.getAbsolutePath());
+ LOG.debug("Elasticsearch data stored in {}", esDir.getAbsolutePath());
+ } catch (Exception e) {
+ throw new IllegalStateException("Fail to create directory " + esDir.getAbsolutePath(), e);
+ }
+ }
+
+ @Override
+ public void stop() {
+ if (node != null) {
+ node.close();
+ node = null;
+ }
+ }
+
+ public Client client() {
+ if (node == null) {
+ throw new IllegalStateException("Elasticsearch is not started");
+ }
+ return node.client();
+ }
+}
+++ /dev/null
-{
- "cluster": {
- "name": "sonarqube"
- },
- "node": {
- "name": "sonarqube",
- "local": true,
- "data": true
- },
- "discovery": {
- "zen": {
- "multicast": {
- "enabled": false
- }
- }
- },
- "index": {
- "number_of_shards": 1,
- "number_of_replicas": 0,
- "mapper": {
- "dynamic": false
- },
- "analysis": {
- "analyzer": {
- "sortable": {
- "type": "custom",
- "tokenizer": "keyword",
- "filter": "lowercase"
- },
- "rule_name": {
- "type": "custom",
- "tokenizer": "standard",
- "filter": ["lowercase", "rule_name_ngram"]
- }
- },
- "filter": {
- "rule_name_ngram": {
- "type": "nGram",
- "min_gram": 3,
- "max_gram": 5,
- "token_chars": [ "letter", "digit" ]
- }
- }
- }
- }
-}
+++ /dev/null
-{
- "template": "*",
- "mappings": {
- "_default_": {
- "dynamic": "strict"
- }
- }
-}
--- /dev/null
+{
+ "cluster": {
+ "name": "sonarqube"
+ },
+ "node": {
+ "name": "sonarqube",
+ "local": true,
+ "data": true
+ },
+ "discovery": {
+ "zen": {
+ "multicast": {
+ "enabled": false
+ }
+ }
+ },
+ "index": {
+ "number_of_shards": 1,
+ "number_of_replicas": 0,
+ "mapper": {
+ "dynamic": false
+ },
+ "analysis": {
+ "analyzer": {
+ "sortable": {
+ "type": "custom",
+ "tokenizer": "keyword",
+ "filter": "lowercase"
+ },
+ "rule_name": {
+ "type": "custom",
+ "tokenizer": "standard",
+ "filter": ["lowercase", "rule_name_ngram"]
+ }
+ },
+ "filter": {
+ "rule_name_ngram": {
+ "type": "nGram",
+ "min_gram": 3,
+ "max_gram": 5,
+ "token_chars": [ "letter", "digit" ]
+ }
+ }
+ }
+ }
+}
--- /dev/null
+{
+ "template": "*",
+ "mappings": {
+ "_default_": {
+ "dynamic": "strict"
+ }
+ }
+}
+++ /dev/null
-/*
- * 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;
-
-import com.google.common.io.Resources;
-import org.apache.commons.io.FileUtils;
-import org.elasticsearch.action.admin.cluster.health.ClusterHealthStatus;
-import org.elasticsearch.client.AdminClient;
-import org.elasticsearch.client.ClusterAdminClient;
-import org.elasticsearch.cluster.ClusterState;
-import org.elasticsearch.common.xcontent.XContentFactory;
-import org.elasticsearch.index.mapper.StrictDynamicMappingException;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.config.Settings;
-import org.sonar.api.platform.ServerFileSystem;
-import org.sonar.api.utils.ZipUtils;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.HttpURLConnection;
-import java.net.URI;
-import java.net.URL;
-
-import static org.fest.assertions.Assertions.assertThat;
-import static org.fest.assertions.Fail.fail;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class ESNodeTest {
-
- ServerFileSystem fs;
- File homedir;
- File dataDir;
-
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- @Before
- public void createMocks() throws IOException {
- homedir = temp.newFolder();
- fs = mock(ServerFileSystem.class);
- when(fs.getHomeDir()).thenReturn(homedir);
- dataDir = new File(homedir, ESNode.DATA_DIR);
- }
-
- @After
- public void cleanUp() {
- FileUtils.deleteQuietly(homedir);
- }
-
- @Test
- public void start_and_stop_es_node() throws Exception {
- assertThat(dataDir).doesNotExist();
-
- ESNode node = new ESNode(fs, new Settings());
- node.start();
-
- ClusterAdminClient cluster = node.client().admin().cluster();
- ClusterState state = cluster.state(cluster.prepareState().request()).actionGet().getState();
- assertThat(state.getNodes().size()).isEqualTo(1);
- assertThat(state.getNodes().getMasterNode().isDataNode()).isTrue();
- assertThat(dataDir).exists().isDirectory();
-
- // REST console is disabled by default
- assertThat(state.getMetaData().settings().get("http.port")).isNull();
-
- node.stop();
-
- // data dir is persistent
- assertThat(dataDir).exists().isDirectory();
- }
-
- @Test(expected = StrictDynamicMappingException.class)
- public void should_use_default_settings_for_index() throws Exception {
- ESNode node = new ESNode(fs, new Settings());
- node.start();
-
- node.client().admin().indices().prepareCreate("polop")
- .addMapping("type1", "{\"type1\": {\"properties\": {\"value\": {\"type\": \"string\"}}}}")
- .execute().actionGet();
- node.client().admin().cluster().prepareHealth("polop").setWaitForYellowStatus().execute().actionGet();
-
- // default "sortable" analyzer is defined for all indices
- assertThat(node.client().admin().indices().prepareAnalyze("polop", "This Is A Wonderful Text").setAnalyzer("sortable").execute().actionGet()
- .getTokens().get(0).getTerm()).isEqualTo("this is a wonderful text");
-
- // strict mapping is enforced
- try {
- node.client().prepareIndex("polop", "type1", "666").setSource(
- XContentFactory.jsonBuilder().startObject().field("unknown", "plouf").endObject()
- ).execute().actionGet();
- } finally {
- node.stop();
- }
- }
-
- @Test
- public void should_restore_status_on_startup() throws Exception {
- File zip = new File(Resources.getResource(getClass(), "ESNodeTest/data-es-clean.zip").toURI());
- ZipUtils.unzip(zip, dataDir);
-
- ESNode node = new ESNode(fs, new Settings());
- node.start();
-
- AdminClient admin = node.client().admin();
- assertThat(admin.indices().prepareExists("myindex").execute().actionGet().isExists()).isTrue();
- assertThat(admin.cluster().prepareHealth("myindex").setWaitForYellowStatus().execute().actionGet().getStatus()).isIn(ClusterHealthStatus.GREEN, ClusterHealthStatus.YELLOW);
-
- node.stop();
- }
-
- @Test(expected = IllegalStateException.class)
- public void should_fail_on_corrupt_index() throws Exception {
- File zip = new File(Resources.getResource(getClass(), "ESNodeTest/data-es-corrupt.zip").toURI());
- ZipUtils.unzip(zip, dataDir);
-
- ESNode node = new ESNode(fs, new Settings(), "5s");
- try {
- node.start();
- } finally {
- node.stop();
- }
- }
-
- @Test
- public void should_fail_to_get_client_if_not_started() {
- ESNode node = new ESNode(fs, new Settings());
- try {
- node.client();
- fail();
- } catch (IllegalStateException e) {
- assertThat(e).hasMessage("Elasticsearch is not started");
- }
- }
-
- @Test
- public void should_enable_rest_console() throws Exception {
- Settings settings = new Settings();
- int httpPort = NetworkUtils.freePort();
- settings.setProperty("sonar.es.http.port", httpPort);
- ESNode node = new ESNode(fs, settings);
- node.start();
-
- URL url = URI.create("http://localhost:" + httpPort).toURL();
- HttpURLConnection connection = (HttpURLConnection) url.openConnection();
- connection.connect();
- assertThat(connection.getResponseCode()).isEqualTo(200);
-
- node.stop();
- connection = (HttpURLConnection) url.openConnection();
- try {
- connection.connect();
- fail();
- } catch (Exception e) {
- // ok, console is down
- }
- }
-}
+++ /dev/null
-/*
- * 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;
-
-import java.io.IOException;
-import java.net.ServerSocket;
-
-class NetworkUtils {
-
- static int freePort() {
- for (int index = 0; index < 5; index++) {
- try {
- ServerSocket socket = new ServerSocket(0);
- int unusedPort = socket.getLocalPort();
- socket.close();
- if (isValidPort(unusedPort)) {
- return unusedPort;
- }
-
- } catch (IOException e) {
- throw new IllegalStateException("Can not find an open network port", e);
- }
- }
- throw new IllegalStateException("Can not find an open network port");
- }
-
-
- private static boolean isValidPort(int port) {
- return port > 1023;
- }
-}
--- /dev/null
+/*
+ * 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.search;
+
+import com.google.common.io.Resources;
+import org.apache.commons.io.FileUtils;
+import org.elasticsearch.action.admin.cluster.health.ClusterHealthStatus;
+import org.elasticsearch.client.AdminClient;
+import org.elasticsearch.client.ClusterAdminClient;
+import org.elasticsearch.cluster.ClusterState;
+import org.elasticsearch.common.xcontent.XContentFactory;
+import org.elasticsearch.index.mapper.StrictDynamicMappingException;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.config.Settings;
+import org.sonar.api.platform.ServerFileSystem;
+import org.sonar.api.utils.ZipUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URI;
+import java.net.URL;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.fest.assertions.Fail.fail;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class ESNodeTest {
+
+ ServerFileSystem fs;
+ File homedir;
+ File dataDir;
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ @Before
+ public void createMocks() throws IOException {
+ homedir = temp.newFolder();
+ fs = mock(ServerFileSystem.class);
+ when(fs.getHomeDir()).thenReturn(homedir);
+ dataDir = new File(homedir, ESNode.DATA_DIR);
+ }
+
+ @After
+ public void cleanUp() {
+ FileUtils.deleteQuietly(homedir);
+ }
+
+ @Test
+ public void start_and_stop_es_node() throws Exception {
+ assertThat(dataDir).doesNotExist();
+
+ ESNode node = new ESNode(fs, new Settings());
+ node.start();
+
+ ClusterAdminClient cluster = node.client().admin().cluster();
+ ClusterState state = cluster.state(cluster.prepareState().request()).actionGet().getState();
+ assertThat(state.getNodes().size()).isEqualTo(1);
+ assertThat(state.getNodes().getMasterNode().isDataNode()).isTrue();
+ assertThat(dataDir).exists().isDirectory();
+
+ // REST console is disabled by default
+ assertThat(state.getMetaData().settings().get("http.port")).isNull();
+
+ node.stop();
+
+ // data dir is persistent
+ assertThat(dataDir).exists().isDirectory();
+ }
+
+ @Test(expected = StrictDynamicMappingException.class)
+ public void should_use_default_settings_for_index() throws Exception {
+ ESNode node = new ESNode(fs, new Settings());
+ node.start();
+
+ node.client().admin().indices().prepareCreate("polop")
+ .addMapping("type1", "{\"type1\": {\"properties\": {\"value\": {\"type\": \"string\"}}}}")
+ .execute().actionGet();
+ node.client().admin().cluster().prepareHealth("polop").setWaitForYellowStatus().execute().actionGet();
+
+ // default "sortable" analyzer is defined for all indices
+ assertThat(node.client().admin().indices().prepareAnalyze("polop", "This Is A Wonderful Text").setAnalyzer("sortable").execute().actionGet()
+ .getTokens().get(0).getTerm()).isEqualTo("this is a wonderful text");
+
+ // strict mapping is enforced
+ try {
+ node.client().prepareIndex("polop", "type1", "666").setSource(
+ XContentFactory.jsonBuilder().startObject().field("unknown", "plouf").endObject()
+ ).execute().actionGet();
+ } finally {
+ node.stop();
+ }
+ }
+
+ @Test
+ public void should_restore_status_on_startup() throws Exception {
+ File zip = new File(Resources.getResource(getClass(), "ESNodeTest/data-es-clean.zip").toURI());
+ ZipUtils.unzip(zip, dataDir);
+
+ ESNode node = new ESNode(fs, new Settings());
+ node.start();
+
+ AdminClient admin = node.client().admin();
+ assertThat(admin.indices().prepareExists("myindex").execute().actionGet().isExists()).isTrue();
+ assertThat(admin.cluster().prepareHealth("myindex").setWaitForYellowStatus().execute().actionGet().getStatus()).isIn(ClusterHealthStatus.GREEN, ClusterHealthStatus.YELLOW);
+
+ node.stop();
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void should_fail_on_corrupt_index() throws Exception {
+ File zip = new File(Resources.getResource(getClass(), "ESNodeTest/data-es-corrupt.zip").toURI());
+ ZipUtils.unzip(zip, dataDir);
+
+ ESNode node = new ESNode(fs, new Settings(), "5s");
+ try {
+ node.start();
+ } finally {
+ node.stop();
+ }
+ }
+
+ @Test
+ public void should_fail_to_get_client_if_not_started() {
+ ESNode node = new ESNode(fs, new Settings());
+ try {
+ node.client();
+ fail();
+ } catch (IllegalStateException e) {
+ assertThat(e).hasMessage("Elasticsearch is not started");
+ }
+ }
+
+ @Test
+ public void should_enable_rest_console() throws Exception {
+ Settings settings = new Settings();
+ int httpPort = NetworkUtils.freePort();
+ settings.setProperty("sonar.es.http.port", httpPort);
+ ESNode node = new ESNode(fs, settings);
+ node.start();
+
+ URL url = URI.create("http://localhost:" + httpPort).toURL();
+ HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+ connection.connect();
+ assertThat(connection.getResponseCode()).isEqualTo(200);
+
+ node.stop();
+ connection = (HttpURLConnection) url.openConnection();
+ try {
+ connection.connect();
+ fail();
+ } catch (Exception e) {
+ // ok, console is down
+ }
+ }
+}
--- /dev/null
+/*
+ * 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.search;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+
+class NetworkUtils {
+
+ static int freePort() {
+ for (int index = 0; index < 5; index++) {
+ try {
+ ServerSocket socket = new ServerSocket(0);
+ int unusedPort = socket.getLocalPort();
+ socket.close();
+ if (isValidPort(unusedPort)) {
+ return unusedPort;
+ }
+
+ } catch (IOException e) {
+ throw new IllegalStateException("Can not find an open network port", e);
+ }
+ }
+ throw new IllegalStateException("Can not find an open network port");
+ }
+
+
+ private static boolean isValidPort(int port) {
+ return port > 1023;
+ }
+}
import org.sonar.core.persistence.DatabaseVersion;
import org.sonar.core.persistence.DbSession;
import org.sonar.core.persistence.MyBatis;
-import org.sonar.server.es.ESNode;
+import org.sonar.server.search.ESNode;
import java.sql.Connection;