aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Schwarz <daniel.schwarz@sonarsource.com>2017-09-07 14:02:53 +0200
committerDaniel Schwarz <bartfastiel@users.noreply.github.com>2017-09-11 13:40:02 +0200
commitd77cf9f6541ed04f39b0e0201618343e80946602 (patch)
treeb8bab566db9cb880f6e673181abf7b6d9e41b686
parent8b2756441322b038aab642023846e91334b70f76 (diff)
downloadsonarqube-d77cf9f6541ed04f39b0e0201618343e80946602.tar.gz
sonarqube-d77cf9f6541ed04f39b0e0201618343e80946602.zip
Add test for EsProcessMonitor
-rw-r--r--server/sonar-main/src/main/java/org/sonar/application/process/EsConnector.java27
-rw-r--r--server/sonar-main/src/main/java/org/sonar/application/process/EsConnectorImpl.java35
-rw-r--r--server/sonar-main/src/main/java/org/sonar/application/process/EsProcessMonitor.java32
-rw-r--r--server/sonar-main/src/main/java/org/sonar/application/process/ProcessLauncherImpl.java5
-rw-r--r--server/sonar-main/src/test/java/org/sonar/application/process/EsProcessMonitorTest.java99
5 files changed, 176 insertions, 22 deletions
diff --git a/server/sonar-main/src/main/java/org/sonar/application/process/EsConnector.java b/server/sonar-main/src/main/java/org/sonar/application/process/EsConnector.java
new file mode 100644
index 00000000000..8104430d5a3
--- /dev/null
+++ b/server/sonar-main/src/main/java/org/sonar/application/process/EsConnector.java
@@ -0,0 +1,27 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.application.process;
+
+import org.elasticsearch.client.transport.TransportClient;
+import org.elasticsearch.cluster.health.ClusterHealthStatus;
+
+public interface EsConnector {
+ ClusterHealthStatus getClusterHealthStatus(TransportClient transportClient);
+}
diff --git a/server/sonar-main/src/main/java/org/sonar/application/process/EsConnectorImpl.java b/server/sonar-main/src/main/java/org/sonar/application/process/EsConnectorImpl.java
new file mode 100644
index 00000000000..a55f0590bea
--- /dev/null
+++ b/server/sonar-main/src/main/java/org/sonar/application/process/EsConnectorImpl.java
@@ -0,0 +1,35 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.application.process;
+
+import org.elasticsearch.action.admin.cluster.health.ClusterHealthRequest;
+import org.elasticsearch.client.transport.TransportClient;
+import org.elasticsearch.cluster.health.ClusterHealthStatus;
+
+import static org.elasticsearch.common.unit.TimeValue.timeValueSeconds;
+
+public class EsConnectorImpl implements EsConnector {
+ @Override
+ public ClusterHealthStatus getClusterHealthStatus(TransportClient transportClient) {
+ return transportClient.admin().cluster()
+ .health(new ClusterHealthRequest().waitForStatus(ClusterHealthStatus.YELLOW).timeout(timeValueSeconds(30)))
+ .actionGet().getStatus();
+ }
+}
diff --git a/server/sonar-main/src/main/java/org/sonar/application/process/EsProcessMonitor.java b/server/sonar-main/src/main/java/org/sonar/application/process/EsProcessMonitor.java
index 52c0a9d917a..ff049e69e67 100644
--- a/server/sonar-main/src/main/java/org/sonar/application/process/EsProcessMonitor.java
+++ b/server/sonar-main/src/main/java/org/sonar/application/process/EsProcessMonitor.java
@@ -28,11 +28,8 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
-import org.elasticsearch.action.admin.cluster.health.ClusterHealthRequest;
-import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
import org.elasticsearch.client.transport.NoNodeAvailableException;
import org.elasticsearch.client.transport.TransportClient;
-import org.elasticsearch.cluster.health.ClusterHealthStatus;
import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
@@ -40,12 +37,10 @@ import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.transport.Netty4Plugin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.sonar.process.ProcessId;
import org.sonar.process.command.EsCommand;
import static java.util.Collections.singletonList;
import static java.util.Collections.unmodifiableList;
-import static org.elasticsearch.common.unit.TimeValue.timeValueSeconds;
import static org.sonar.application.process.EsProcessMonitor.Status.CONNECTION_REFUSED;
import static org.sonar.application.process.EsProcessMonitor.Status.GREEN;
import static org.sonar.application.process.EsProcessMonitor.Status.KO;
@@ -60,11 +55,13 @@ public class EsProcessMonitor extends AbstractProcessMonitor {
private final AtomicBoolean nodeUp = new AtomicBoolean(false);
private final AtomicBoolean nodeOperational = new AtomicBoolean(false);
private final EsCommand esCommand;
+ private final EsConnector esConnector;
private AtomicReference<TransportClient> transportClient = new AtomicReference<>(null);
- public EsProcessMonitor(Process process, ProcessId processId, EsCommand esCommand) {
- super(process, processId);
+ public EsProcessMonitor(Process process, EsCommand esCommand, EsConnector esConnector) {
+ super(process, esCommand.getProcessId());
this.esCommand = esCommand;
+ this.esConnector = esConnector;
}
@Override
@@ -131,19 +128,16 @@ public class EsProcessMonitor extends AbstractProcessMonitor {
private Status checkStatus() {
try {
- ClusterHealthResponse response = getTransportClient().admin().cluster()
- .health(new ClusterHealthRequest().waitForStatus(ClusterHealthStatus.YELLOW).timeout(timeValueSeconds(30)))
- .actionGet();
- if (response.getStatus() == ClusterHealthStatus.GREEN) {
- return GREEN;
+ switch (esConnector.getClusterHealthStatus(getTransportClient())) {
+ case GREEN:
+ return GREEN;
+ case YELLOW:
+ return YELLOW;
+ case RED:
+ return RED;
+ default:
+ return KO;
}
- if (response.getStatus() == ClusterHealthStatus.YELLOW) {
- return YELLOW;
- }
- if (response.getStatus() == ClusterHealthStatus.RED) {
- return RED;
- }
- return KO;
} catch (NoNodeAvailableException e) {
return CONNECTION_REFUSED;
} catch (Exception e) {
diff --git a/server/sonar-main/src/main/java/org/sonar/application/process/ProcessLauncherImpl.java b/server/sonar-main/src/main/java/org/sonar/application/process/ProcessLauncherImpl.java
index af17e5ff80b..17547f420bf 100644
--- a/server/sonar-main/src/main/java/org/sonar/application/process/ProcessLauncherImpl.java
+++ b/server/sonar-main/src/main/java/org/sonar/application/process/ProcessLauncherImpl.java
@@ -71,7 +71,6 @@ public class ProcessLauncherImpl implements ProcessLauncher {
@Override
public ProcessMonitor launch(EsCommand esCommand) {
Process process = null;
- ProcessId processId = esCommand.getProcessId();
try {
writeConfFiles(esCommand);
ProcessBuilder processBuilder = create(esCommand);
@@ -79,13 +78,13 @@ public class ProcessLauncherImpl implements ProcessLauncher {
process = processBuilder.start();
- return new EsProcessMonitor(process, processId, esCommand);
+ return new EsProcessMonitor(process, esCommand, new EsConnectorImpl());
} catch (Exception e) {
// just in case
if (process != null) {
process.destroyForcibly();
}
- throw new IllegalStateException(format("Fail to launch process [%s]", processId.getKey()), e);
+ throw new IllegalStateException(format("Fail to launch process [%s]", esCommand.getProcessId().getKey()), e);
}
}
diff --git a/server/sonar-main/src/test/java/org/sonar/application/process/EsProcessMonitorTest.java b/server/sonar-main/src/test/java/org/sonar/application/process/EsProcessMonitorTest.java
new file mode 100644
index 00000000000..f1993b462f6
--- /dev/null
+++ b/server/sonar-main/src/test/java/org/sonar/application/process/EsProcessMonitorTest.java
@@ -0,0 +1,99 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.application.process;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Random;
+import org.elasticsearch.client.transport.NoNodeAvailableException;
+import org.elasticsearch.cluster.health.ClusterHealthStatus;
+import org.junit.Test;
+import org.sonar.process.ProcessId;
+import org.sonar.process.command.EsCommand;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class EsProcessMonitorTest {
+
+ @Test
+ public void isOperational_should_return_false_if_Elasticsearch_is_RED() throws Exception {
+ EsConnector esConnector = mock(EsConnector.class);
+ when(esConnector.getClusterHealthStatus(any())).thenReturn(ClusterHealthStatus.RED);
+ EsProcessMonitor underTest = new EsProcessMonitor(mock(Process.class), getEsCommand(), esConnector);
+ assertThat(underTest.isOperational()).isFalse();
+ }
+
+ @Test
+ public void isOperational_should_return_true_if_Elasticsearch_is_YELLOW() throws Exception {
+ EsConnector esConnector = mock(EsConnector.class);
+ when(esConnector.getClusterHealthStatus(any())).thenReturn(ClusterHealthStatus.YELLOW);
+ EsProcessMonitor underTest = new EsProcessMonitor(mock(Process.class), getEsCommand(), esConnector);
+ assertThat(underTest.isOperational()).isTrue();
+ }
+
+ @Test
+ public void isOperational_should_return_true_if_Elasticsearch_is_GREEN() throws Exception {
+ EsConnector esConnector = mock(EsConnector.class);
+ when(esConnector.getClusterHealthStatus(any())).thenReturn(ClusterHealthStatus.GREEN);
+ EsProcessMonitor underTest = new EsProcessMonitor(mock(Process.class), getEsCommand(), esConnector);
+ assertThat(underTest.isOperational()).isTrue();
+ }
+
+ @Test
+ public void isOperational_should_return_true_if_Elasticsearch_was_GREEN_once() throws Exception {
+ EsConnector esConnector = mock(EsConnector.class);
+ when(esConnector.getClusterHealthStatus(any())).thenReturn(ClusterHealthStatus.GREEN);
+ EsProcessMonitor underTest = new EsProcessMonitor(mock(Process.class), getEsCommand(), esConnector);
+ assertThat(underTest.isOperational()).isTrue();
+
+ when(esConnector.getClusterHealthStatus(any())).thenReturn(ClusterHealthStatus.RED);
+ assertThat(underTest.isOperational()).isTrue();
+ }
+
+ @Test
+ public void isOperational_should_retry_if_Elasticsearch_is_unreachable() throws Exception {
+ EsConnector esConnector = mock(EsConnector.class);
+ when(esConnector.getClusterHealthStatus(any()))
+ .thenThrow(new NoNodeAvailableException("test"))
+ .thenReturn(ClusterHealthStatus.GREEN);
+ EsProcessMonitor underTest = new EsProcessMonitor(mock(Process.class), getEsCommand(), esConnector);
+ assertThat(underTest.isOperational()).isTrue();
+ }
+
+ @Test
+ public void isOperational_should_return_false_if_Elasticsearch_status_cannot_be_evaluated() throws Exception {
+ EsConnector esConnector = mock(EsConnector.class);
+ when(esConnector.getClusterHealthStatus(any()))
+ .thenThrow(new RuntimeException("test"));
+ EsProcessMonitor underTest = new EsProcessMonitor(mock(Process.class), getEsCommand(), esConnector);
+ assertThat(underTest.isOperational()).isFalse();
+ }
+
+ private EsCommand getEsCommand() throws IOException {
+ Path tempDirectory = Files.createTempDirectory(getClass().getSimpleName());
+ return new EsCommand(ProcessId.ELASTICSEARCH, tempDirectory.toFile())
+ .setHost("localhost")
+ .setPort(new Random().nextInt(40000));
+ }
+}