aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorSimon Brandhof <simon.brandhof@sonarsource.com>2017-10-17 16:45:10 +0200
committerSimon Brandhof <simon.brandhof@sonarsource.com>2017-10-18 10:43:22 +0200
commit9e4fe4aca049a680ba0476312f89a5fe133412cf (patch)
treede8500e3b8c26cfe094f38dd782709a815a273de /tests
parentd3195eafe8e0253fa8a7044013476de94fcb5edb (diff)
downloadsonarqube-9e4fe4aca049a680ba0476312f89a5fe133412cf.tar.gz
sonarqube-9e4fe4aca049a680ba0476312f89a5fe133412cf.zip
Remove cluster tests
Diffstat (limited to 'tests')
-rw-r--r--tests/src/test/java/org/sonarqube/tests/Category5Suite.java2
-rw-r--r--tests/src/test/java/org/sonarqube/tests/cluster/Cluster.java131
-rw-r--r--tests/src/test/java/org/sonarqube/tests/cluster/ClusterTest.java451
-rw-r--r--tests/src/test/java/org/sonarqube/tests/cluster/Node.java248
-rw-r--r--tests/src/test/java/org/sonarqube/tests/cluster/NodeConfig.java187
5 files changed, 0 insertions, 1019 deletions
diff --git a/tests/src/test/java/org/sonarqube/tests/Category5Suite.java b/tests/src/test/java/org/sonarqube/tests/Category5Suite.java
index bd4ee5b26d0..13e6c3d9921 100644
--- a/tests/src/test/java/org/sonarqube/tests/Category5Suite.java
+++ b/tests/src/test/java/org/sonarqube/tests/Category5Suite.java
@@ -25,7 +25,6 @@ import org.sonarqube.tests.analysis.AnalysisEsResilienceTest;
import org.sonarqube.tests.authorisation.SystemPasscodeTest;
import org.sonarqube.tests.ce.CeShutdownTest;
import org.sonarqube.tests.ce.CeWorkersTest;
-import org.sonarqube.tests.cluster.ClusterTest;
import org.sonarqube.tests.issue.IssueCreationDatePluginChangedTest;
import org.sonarqube.tests.qualityProfile.ActiveRuleEsResilienceTest;
import org.sonarqube.tests.qualityProfile.BuiltInQualityProfilesNotificationTest;
@@ -51,7 +50,6 @@ import org.sonarqube.tests.user.UserEsResilienceTest;
*/
@RunWith(Suite.class)
@Suite.SuiteClasses({
- ClusterTest.class,
ServerSystemRestartingOrchestrator.class,
RestartTest.class,
SettingsTestRestartingOrchestrator.class,
diff --git a/tests/src/test/java/org/sonarqube/tests/cluster/Cluster.java b/tests/src/test/java/org/sonarqube/tests/cluster/Cluster.java
deleted file mode 100644
index 58fb754f4b2..00000000000
--- a/tests/src/test/java/org/sonarqube/tests/cluster/Cluster.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * 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.sonarqube.tests.cluster;
-
-import com.sonar.orchestrator.Orchestrator;
-import com.sonar.orchestrator.OrchestratorBuilder;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.function.Consumer;
-import java.util.stream.Stream;
-import javax.annotation.Nullable;
-import org.slf4j.LoggerFactory;
-import util.ItUtils;
-
-import static java.util.stream.Collectors.joining;
-
-class Cluster implements AutoCloseable {
-
- @Nullable
- private final String clusterName;
-
- private final List<Node> nodes = new ArrayList<>();
- private final String systemPassCode = "fooBar2000";
-
- Cluster(@Nullable String name) {
- this.clusterName = name;
- }
-
- Node startNode(NodeConfig config, Consumer<OrchestratorBuilder> consumer) {
- Node node = addNode(config, consumer);
- node.start();
- return node;
- }
-
- Node addNode(NodeConfig config, Consumer<OrchestratorBuilder> consumer) {
- OrchestratorBuilder builder = newOrchestratorBuilder(config);
- builder.setServerProperty("sonar.web.systemPasscode", systemPassCode);
-
- switch (config.getType()) {
- case SEARCH:
- builder
- .setServerProperty("sonar.cluster.node.type", "search")
- .setServerProperty("sonar.search.host", config.getAddress().getHostAddress())
- .setServerProperty("sonar.search.port", "" + config.getSearchPort().get())
- .setServerProperty("sonar.search.javaOpts", "-Xmx64m -Xms64m -XX:+HeapDumpOnOutOfMemoryError");
- break;
- case APPLICATION:
- builder
- .setServerProperty("sonar.cluster.node.type", "application")
- .setServerProperty("sonar.web.host", config.getAddress().getHostAddress())
- .setServerProperty("sonar.web.port", "" + config.getWebPort().get())
- .setServerProperty("sonar.web.javaOpts", "-Xmx128m -Xms16m -XX:+HeapDumpOnOutOfMemoryError")
- .setServerProperty("sonar.auth.jwtBase64Hs256Secret", "HrPSavOYLNNrwTY+SOqpChr7OwvbR/zbDLdVXRN0+Eg=")
- .setServerProperty("sonar.ce.javaOpts", "-Xmx32m -Xms16m -XX:+HeapDumpOnOutOfMemoryError");
- break;
- }
- consumer.accept(builder);
- Orchestrator orchestrator = builder.build();
- Node node = new Node(config, orchestrator, systemPassCode);
- nodes.add(node);
- return node;
- }
-
- Stream<Node> getNodes() {
- return nodes.stream();
- }
-
- Stream<Node> getAppNodes() {
- return nodes.stream().filter(n -> n.getConfig().getType() == NodeConfig.NodeType.APPLICATION);
- }
-
- Node getAppNode(int index) {
- return getAppNodes().skip(index).findFirst().orElseThrow(IllegalArgumentException::new);
- }
-
- Stream<Node> getSearchNodes() {
- return nodes.stream().filter(n -> n.getConfig().getType() == NodeConfig.NodeType.SEARCH);
- }
-
- Node getSearchNode(int index) {
- return getSearchNodes().skip(index).findFirst().orElseThrow(IllegalArgumentException::new);
- }
-
- @Override
- public void close() throws Exception {
- // nodes are stopped in order of creation
- for (Node node : nodes) {
- try {
- node.stop();
- } catch (Exception e) {
- LoggerFactory.getLogger(getClass()).error("Fail to stop node", e);
- }
- }
- }
-
- private OrchestratorBuilder newOrchestratorBuilder(NodeConfig node) {
- OrchestratorBuilder builder = Orchestrator.builderEnv();
- builder.setOrchestratorProperty("orchestrator.keepDatabase", "true");
- builder.setServerProperty("sonar.cluster.enabled", "true");
- builder.setServerProperty("sonar.cluster.node.host", node.getAddress().getHostAddress());
- builder.setServerProperty("sonar.cluster.node.port", "" + node.getHzPort());
- builder.setServerProperty("sonar.cluster.hosts", node.getConnectedNodes().stream().map(NodeConfig::getHzHost).collect(joining(",")));
- builder.setServerProperty("sonar.cluster.search.hosts", node.getSearchNodes().stream().map(NodeConfig::getSearchHost).collect(joining(",")));
- if (clusterName != null) {
- builder.setServerProperty("sonar.cluster.name", clusterName);
- }
- if (node.getName().isPresent()) {
- builder.setServerProperty("sonar.cluster.node.name", node.getName().get());
- }
- builder.addPlugin(ItUtils.pluginArtifact("server-plugin"));
- builder.setStartupLogWatcher(logLine -> true);
- return builder;
- }
-}
diff --git a/tests/src/test/java/org/sonarqube/tests/cluster/ClusterTest.java b/tests/src/test/java/org/sonarqube/tests/cluster/ClusterTest.java
deleted file mode 100644
index 74d69832b42..00000000000
--- a/tests/src/test/java/org/sonarqube/tests/cluster/ClusterTest.java
+++ /dev/null
@@ -1,451 +0,0 @@
-/*
- * 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.sonarqube.tests.cluster;
-
-import com.google.gson.internal.LinkedTreeMap;
-import com.sonar.orchestrator.Orchestrator;
-import com.sonar.orchestrator.OrchestratorBuilder;
-import com.sonar.orchestrator.db.DefaultDatabase;
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.function.BinaryOperator;
-import java.util.function.Consumer;
-import java.util.stream.IntStream;
-import org.apache.commons.io.FileUtils;
-import org.junit.BeforeClass;
-import org.junit.Ignore;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.DisableOnDebug;
-import org.junit.rules.ExpectedException;
-import org.junit.rules.TemporaryFolder;
-import org.junit.rules.TestRule;
-import org.junit.rules.Timeout;
-import org.sonarqube.pageobjects.Navigation;
-import org.sonarqube.pageobjects.SystemInfoPage;
-import org.sonarqube.ws.WsSystem;
-import org.sonarqube.ws.client.HttpException;
-import org.sonarqube.ws.client.issue.SearchWsRequest;
-import util.ItUtils;
-
-import static com.google.common.base.Preconditions.checkState;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.Assert.fail;
-import static org.sonarqube.tests.cluster.NodeConfig.newApplicationConfig;
-import static org.sonarqube.tests.cluster.NodeConfig.newSearchConfig;
-
-@Ignore
-public class ClusterTest {
-
- @Rule
- public TestRule safeguard = new DisableOnDebug(Timeout.seconds(300));
-
- @Rule
- public ExpectedException expectedException = ExpectedException.none();
-
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- @BeforeClass
- public static void initDbSchema() throws Exception {
- Orchestrator orchestrator = Orchestrator.builderEnv()
- // enforce (re-)creation of database schema
- .setOrchestratorProperty("orchestrator.keepDatabase", "false")
- .build();
- DefaultDatabase db = new DefaultDatabase(orchestrator.getConfiguration());
- checkState(!db.getClient().getDialect().equals("h2"), "H2 is not supported in cluster mode");
- db.start();
- db.stop();
- }
-
- @Test
- public void test_high_availability_topology() throws Exception {
- try (Cluster cluster = newCluster(3, 2)) {
- cluster.getNodes().forEach(Node::start);
-
- cluster.getAppNode(0).waitForHealthGreen();
- cluster.getAppNodes().forEach(node -> assertThat(node.getStatus()).hasValue(WsSystem.Status.UP));
-
- cluster.getNodes().forEach(node -> {
- node.assertThatProcessesAreUp();
- assertThat(node.anyLogsContain(" ERROR ")).isFalse();
- assertThat(node.anyLogsContain("MessageException")).isFalse();
- });
-
- verifyGreenHealthOfNodes(cluster);
-
- // verify that there's a single web startup leader
- Node startupLeader = cluster.getAppNodes()
- .filter(Node::isStartupLeader)
- .reduce(singleElement())
- .get();
- assertThat(startupLeader.hasStartupLeaderOperations()).isTrue();
- assertThat(startupLeader.hasCreatedSearchIndices()).isTrue();
-
- // verify that the second app node is a startup follower
- Node startupFollower = cluster.getAppNodes()
- .filter(Node::isStartupFollower)
- .reduce(singleElement())
- .get();
- assertThat(startupFollower.hasStartupLeaderOperations()).isFalse();
- assertThat(startupFollower.hasCreatedSearchIndices()).isFalse();
-
- cluster.getAppNodes().forEach(app -> {
- // compute engine is being started when app node is already in status UP
- app.waitForCeLogsContain("Compute Engine is operational");
- assertThat(app.anyLogsContain("Process[ce] is up")).isTrue();
- });
-
- testSystemInfoPage(cluster, cluster.getAppNode(0));
- testSystemInfoPage(cluster, cluster.getAppNode(1));
- }
- }
-
- private void verifyGreenHealthOfNodes(Cluster cluster) {
- WsSystem.HealthResponse health = cluster.getAppNode(0).getHealth().get();
- cluster.getNodes().forEach(node -> {
- WsSystem.Node healthNode = health.getNodes().getNodesList().stream()
- .filter(n -> n.getPort() == node.getConfig().getHzPort())
- .findFirst()
- .orElseThrow(() -> new IllegalStateException("Node with port " + node.getConfig().getHzPort() + " not found in api/system/health"));
- assertThat(healthNode.getStartedAt()).isNotEmpty();
- assertThat(healthNode.getHost()).isNotEmpty();
- assertThat(healthNode.getCausesCount()).isEqualTo(0);
- assertThat(healthNode.getHealth()).isEqualTo(WsSystem.Health.GREEN);
- });
- }
-
- private void testSystemInfoPage(Cluster cluster, Node node) {
- Navigation nav = node.openBrowser().logIn().submitCredentials("admin");
- node.wsClient().users().skipOnboardingTutorial();
- SystemInfoPage page = nav.openSystemInfo();
-
- page.getCardItem("System")
- .shouldHaveHealth()
- .shouldHaveMainSection()
- .shouldHaveSection("Database")
- .shouldHaveField("Database Version")
- .shouldHaveSection("Search State")
- .shouldHaveSection("Search Indexes")
- .shouldNotHaveSection("Settings")
- .shouldNotHaveSection("Plugins")
- .shouldHaveField("High Availability")
- .shouldNotHaveField("Official Distribution")
- .shouldNotHaveField("Version")
- .shouldNotHaveField("Logs Level")
- .shouldNotHaveField("Health")
- .shouldNotHaveField("Health Causes");
-
- cluster.getNodes().forEach(clusterNodes -> {
- page.shouldHaveCard(clusterNodes.getConfig().getName().get());
- });
-
- page.getCardItem(String.valueOf(node.getConfig().getName().get()))
- .shouldHaveHealth()
- .shouldHaveSection("System")
- .shouldHaveSection("Database")
- .shouldHaveSection("Web Logging")
- .shouldHaveSection("Compute Engine Logging")
- .shouldNotHaveSection("Settings")
- .shouldHaveField("Version")
- .shouldHaveField("Official Distribution")
- .shouldHaveField("Processors")
- .shouldNotHaveField("Health")
- .shouldNotHaveField("Health Causes");
-
- page.getCardItem(cluster.getSearchNode(0).getConfig().getName().get())
- .shouldHaveHealth()
- .shouldHaveSection("Search State")
- .shouldHaveField("Disk Available")
- .shouldHaveField("Max File Descriptors")
- .shouldNotHaveField("Health")
- .shouldNotHaveField("Health Causes");
- }
-
- @Test
- public void minimal_cluster_is_2_search_and_1_application_nodes() throws Exception {
- try (Cluster cluster = newCluster(2, 1)) {
- cluster.getNodes().forEach(Node::start);
-
- Node app = cluster.getAppNode(0);
- app.waitForStatusUp();
- app.waitForCeLogsContain("Compute Engine is operational");
-
- app.waitForHealth(WsSystem.Health.YELLOW);
- WsSystem.HealthResponse health = app.getHealth().orElseThrow(() -> new IllegalStateException("Health is not available"));
- assertThat(health.getCausesList()).extracting(WsSystem.Cause::getMessage)
- .contains("There should be at least three search nodes")
- .contains("There should be at least two application nodes");
-
- assertThat(app.isStartupLeader()).isTrue();
- assertThat(app.hasStartupLeaderOperations()).isTrue();
-
- cluster.getNodes().forEach(node -> {
- assertThat(node.anyLogsContain(" ERROR ")).isFalse();
- node.assertThatProcessesAreUp();
- });
- }
- }
-
- @Test
- public void configuration_of_connection_to_other_nodes_can_be_non_exhaustive() throws Exception {
- try (Cluster cluster = new Cluster(null)) {
- NodeConfig searchConfig1 = newSearchConfig("Search 1");
- NodeConfig searchConfig2 = newSearchConfig("Search 2");
- NodeConfig appConfig = newApplicationConfig("App 1");
-
- // HZ bus : app -> search 2 -> search1, which is not recommended at all !!!
- searchConfig2.addConnectionToBus(searchConfig1);
- appConfig.addConnectionToBus(searchConfig2);
-
- // search1 is not configured to connect search2
- // app is not configured to connect to search 1
- // --> not recommended at all !!!
- searchConfig2.addConnectionToSearch(searchConfig1);
- appConfig.addConnectionToSearch(searchConfig2);
-
- cluster.startNode(searchConfig1, nothing());
- cluster.startNode(searchConfig2, nothing());
- Node app = cluster.startNode(appConfig, nothing());
-
- app.waitForStatusUp();
- assertThat(app.isStartupLeader()).isTrue();
- assertThat(app.hasStartupLeaderOperations()).isTrue();
-
- // no errors
- cluster.getNodes().forEach(node -> assertThat(node.anyLogsContain(" ERROR ")).isFalse());
- }
- }
-
- @Test
- public void cluster_name_can_be_overridden() throws Exception {
- try (Cluster cluster = new Cluster("foo")) {
- NodeConfig searchConfig1 = newSearchConfig("Search 1");
- NodeConfig searchConfig2 = newSearchConfig("Search 2");
- NodeConfig appConfig = newApplicationConfig("App 1");
- NodeConfig.interconnectBus(searchConfig1, searchConfig2, appConfig);
- NodeConfig.interconnectSearch(searchConfig1, searchConfig2, appConfig);
-
- cluster.startNode(searchConfig1, nothing());
- cluster.startNode(searchConfig2, nothing());
- cluster.startNode(appConfig, nothing());
-
- Node appNode = cluster.getAppNode(0);
- appNode.waitForStatusUp();
- }
- }
-
- @Test
- public void node_fails_to_join_cluster_if_different_cluster_name() throws Exception {
- try (Cluster cluster = new Cluster("foo")) {
- NodeConfig searchConfig1 = newSearchConfig("Search 1");
- NodeConfig searchConfig2 = newSearchConfig("Search 2");
- NodeConfig.interconnectBus(searchConfig1, searchConfig2);
- NodeConfig.interconnectSearch(searchConfig1, searchConfig2);
- cluster.startNode(searchConfig1, nothing());
- cluster.startNode(searchConfig2, nothing());
-
- NodeConfig searchConfig3 = newSearchConfig("Search 3")
- .addConnectionToSearch(searchConfig1)
- .addConnectionToBus(searchConfig1, searchConfig2);
- Node search3 = cluster.addNode(searchConfig3, b -> b
- .setServerProperty("sonar.cluster.name", "bar")
- .setStartupLogWatcher(logLine -> logLine.contains("SonarQube is up")));
- try {
- search3.start();
- fail();
- } catch (IllegalStateException e) {
- assertThat(e).hasMessage("Server startup failure");
- // TODO how to force process to write into sonar.log, even if sonar.log.console=true ?
- // assertThat(search3.anyLogsContain("This node has a cluster name [bar], which does not match [foo] from the cluster")).isTrue();
- }
- }
- }
-
- @Test
- public void restarting_all_application_nodes_elects_a_new_startup_leader() throws Exception {
- // no need for 3 search nodes, 2 is enough for the test
- try (Cluster cluster = newCluster(2, 2)) {
- cluster.getNodes().forEach(Node::start);
- cluster.getAppNodes().forEach(Node::waitForStatusUp);
-
- // stop application nodes only
- cluster.getAppNodes().forEach(app -> {
- app.stop();
- app.cleanUpLogs();
- // logs are empty, no more possible to know if node was startup leader/follower
- assertThat(app.isStartupLeader()).isFalse();
- assertThat(app.isStartupFollower()).isFalse();
- });
-
- // restart application nodes
- cluster.getAppNodes().forEach(Node::start);
- cluster.getAppNodes().forEach(Node::waitForStatusUp);
-
- // one app node is elected as startup leader. It does some initialization stuff,
- // like registration of rules. Search indices already exist and are up-to-date.
- Node startupLeader = cluster.getAppNodes()
- .filter(Node::isStartupLeader)
- .reduce(singleElement())
- .get();
- assertThat(startupLeader.hasStartupLeaderOperations()).isTrue();
- assertThat(startupLeader.hasCreatedSearchIndices()).isFalse();
-
- Node startupFollower = cluster.getAppNodes()
- .filter(Node::isStartupFollower)
- .reduce(singleElement())
- .get();
- assertThat(startupFollower.hasStartupLeaderOperations()).isFalse();
- assertThat(startupFollower.hasCreatedSearchIndices()).isFalse();
- assertThat(startupFollower).isNotSameAs(startupLeader);
- }
- }
-
- @Test
- public void set_log_level_affects_all_nodes() throws Exception {
- try (Cluster cluster = newCluster(2, 2)) {
- cluster.getNodes().forEach(Node::start);
- cluster.getAppNodes().forEach(Node::waitForStatusUp);
-
- cluster.getAppNodes().forEach(node -> {
- assertThat(node.webLogsContain(" TRACE web[")).isFalse();
- });
-
- cluster.getAppNode(0).wsClient().system().changeLogLevel("TRACE");
-
- cluster.getAppNodes().forEach(node -> {
-
- // do something, that will produce logging
- node.wsClient().issues().search(new SearchWsRequest());
-
- // check logs
- assertThat(node.webLogsContain(" TRACE web[")).isTrue();
- });
-
- Map<String, Object> data = ItUtils.jsonToMap(cluster.getAppNode(0).wsClient().system().info().content());
- ArrayList<Object> applicationNodes = (ArrayList<Object>) data.get("Application Nodes");
- applicationNodes.forEach(node -> {
- LinkedTreeMap<Object, Object> nodeData = (LinkedTreeMap<Object, Object>) node;
- LinkedTreeMap<Object, Object> ceLoggingData = (LinkedTreeMap<Object, Object>) nodeData.get("Compute Engine Logging");
- assertThat(ceLoggingData.get("Logs Level")).as("Compute engine logs level of a node").isEqualTo("TRACE");
- });
- }
- }
-
- @Test
- public void restart_action_is_not_allowed_for_cluster_nodes() throws Exception {
- try (Cluster cluster = newCluster(2, 1)) {
- cluster.getNodes().forEach(Node::start);
- cluster.getAppNodes().forEach(Node::waitForStatusUp);
-
- cluster.getAppNodes().forEach(node -> {
- try {
- node.wsClient().system().restart();
- fail("The restart webservice must not succeed on cluster nodes");
- } catch (HttpException e) {
- // all good, we expected this!
- assertThat(e.code()).isEqualTo(400);
- assertThat(e.content()).contains("Restart not allowed for cluster nodes");
- }
- });
- }
- }
-
- @Test
- public void health_becomes_RED_when_all_search_nodes_go_down() throws Exception {
- try (Cluster cluster = newCluster(2, 1)) {
- cluster.getNodes().forEach(Node::start);
-
- Node app = cluster.getAppNode(0);
- app.waitForHealth(WsSystem.Health.YELLOW);
-
- cluster.getSearchNodes().forEach(Node::stop);
-
- app.waitForHealth(WsSystem.Health.RED);
- assertThat(app.getHealth().get().getCausesList()).extracting(WsSystem.Cause::getMessage)
- .contains("Elasticsearch status is RED (unavailable)");
- }
- }
-
- @Test
- public void health_ws_is_available_when_server_is_starting() throws Exception {
- File startupLock = temp.newFile();
- FileUtils.touch(startupLock);
-
- try (Cluster cluster = newCluster(2, 0)) {
- // add an application node that pauses during startup
- NodeConfig appConfig = NodeConfig.newApplicationConfig("App 1")
- .addConnectionToBus(cluster.getSearchNode(0).getConfig())
- .addConnectionToSearch(cluster.getSearchNode(0).getConfig());
- Node appNode = cluster.addNode(appConfig, b -> b.setServerProperty("sonar.web.startupLock.path", startupLock.getAbsolutePath()));
-
- cluster.getNodes().forEach(Node::start);
-
- appNode.waitFor(node -> WsSystem.Status.STARTING == node.getStatus().orElse(null));
-
- // WS answers whereas server is still not started
- assertThat(appNode.getHealth().get().getHealth()).isEqualTo(WsSystem.Health.RED);
-
- // just to be sure, verify that server is still being started
- assertThat(appNode.getStatus()).hasValue(WsSystem.Status.STARTING);
-
- startupLock.delete();
- }
- }
-
- /**
- * Used to have non-blocking {@link Node#start()}. Orchestrator considers
- * node to be up as soon as the first log is generated.
- */
- private static Consumer<OrchestratorBuilder> nothing() {
- return b -> {
- };
- }
-
- /**
- * Configure a cluster with recommended configuration (each node has references
- * to other nodes)
- */
- private static Cluster newCluster(int nbOfSearchNodes, int nbOfAppNodes) {
- Cluster cluster = new Cluster(null);
-
- List<NodeConfig> configs = new ArrayList<>();
- IntStream.range(0, nbOfSearchNodes).forEach(i -> configs.add(newSearchConfig("Search " + i)));
- IntStream.range(0, nbOfAppNodes).forEach(i -> configs.add(newApplicationConfig("App " + i)));
- NodeConfig[] configsArray = configs.toArray(new NodeConfig[configs.size()]);
-
- // a node is connected to all nodes, including itself (see sonar.cluster.hosts)
- NodeConfig.interconnectBus(configsArray);
-
- // search nodes are interconnected, and app nodes connect to all search nodes
- NodeConfig.interconnectSearch(configsArray);
-
- configs.forEach(c -> cluster.addNode(c, nothing()));
- return cluster;
- }
-
- private static BinaryOperator<Node> singleElement() {
- return (a, b) -> {
- throw new IllegalStateException("More than one element");
- };
- }
-}
diff --git a/tests/src/test/java/org/sonarqube/tests/cluster/Node.java b/tests/src/test/java/org/sonarqube/tests/cluster/Node.java
deleted file mode 100644
index 8b200f496b8..00000000000
--- a/tests/src/test/java/org/sonarqube/tests/cluster/Node.java
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * 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.sonarqube.tests.cluster;
-
-import com.google.common.util.concurrent.Uninterruptibles;
-import com.sonar.orchestrator.Orchestrator;
-import java.io.File;
-import java.io.IOException;
-import java.net.ServerSocket;
-import java.util.List;
-import java.util.Optional;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Predicate;
-import javax.annotation.Nullable;
-import org.apache.commons.io.FileUtils;
-import org.sonarqube.pageobjects.Navigation;
-import org.sonarqube.tests.LogsTailer;
-import org.sonarqube.ws.WsSystem;
-import org.sonarqube.ws.client.WsClient;
-import util.ItUtils;
-
-import static com.google.common.base.Preconditions.checkState;
-import static org.assertj.core.api.Assertions.assertThat;
-
-class Node {
-
- private final NodeConfig config;
- private final Orchestrator orchestrator;
- private final String systemPassCode;
- private LogsTailer logsTailer;
- private final LogsTailer.Content content = new LogsTailer.Content();
-
- Node(NodeConfig config, Orchestrator orchestrator, String systemPassCode) {
- this.config = config;
- this.orchestrator = orchestrator;
- this.systemPassCode = systemPassCode;
- }
-
- NodeConfig getConfig() {
- return config;
- }
-
- /**
- * Non-blocking startup of node. The method does not wait for
- * node to be started because Orchestrator uses a StartupLogWatcher
- * that returns as soon as a log is generated.
- */
- void start() {
- orchestrator.start();
- logsTailer = LogsTailer.builder()
- .addFile(orchestrator.getServer().getWebLogs())
- .addFile(orchestrator.getServer().getCeLogs())
- .addFile(orchestrator.getServer().getEsLogs())
- .addFile(orchestrator.getServer().getAppLogs())
- .addConsumer(content)
- .build();
- }
-
- void stop() {
- orchestrator.stop();
- if (logsTailer != null) {
- logsTailer.close();
- }
- }
-
- void cleanUpLogs() {
- if (orchestrator.getServer() != null) {
- FileUtils.deleteQuietly(orchestrator.getServer().getWebLogs());
- FileUtils.deleteQuietly(orchestrator.getServer().getCeLogs());
- FileUtils.deleteQuietly(orchestrator.getServer().getEsLogs());
- FileUtils.deleteQuietly(orchestrator.getServer().getAppLogs());
- }
- }
-
- boolean isStartupLeader() {
- return webLogsContain("Cluster enabled (startup leader)");
- }
-
- boolean isStartupFollower() {
- return webLogsContain("Cluster enabled (startup follower)");
- }
-
- void waitForStatusUp() {
- waitFor(node -> WsSystem.Status.UP == node.getStatus().orElse(null));
- }
-
- /**
- * Waiting for health to be green... or yellow on the boxes that
- * have less than 15% of free disk space. In that case Elasticsearch
- * can't build shard replicas so it is yellow.
- */
- void waitForHealthGreen() {
- waitFor(node -> {
- Optional<WsSystem.HealthResponse> health = node.getHealth();
- if (!health.isPresent()) {
- return false;
- }
- if (health.get().getHealth() == WsSystem.Health.GREEN) {
- return true;
- }
- if (health.get().getHealth() == WsSystem.Health.YELLOW) {
- List<WsSystem.Cause> causes = health.get().getCausesList();
- return causes.size() == 1 && "Elasticsearch status is YELLOW".equals(causes.get(0).getMessage());
- }
- return false;
- });
- }
-
- void waitForHealth(WsSystem.Health expectedHealth) {
- waitFor(node -> expectedHealth.equals(node.getHealth().map(WsSystem.HealthResponse::getHealth).orElse(null)));
- }
-
- Optional<WsSystem.Status> getStatus() {
- checkState(config.getType() == NodeConfig.NodeType.APPLICATION);
- if (orchestrator.getServer() == null) {
- return Optional.empty();
- }
- try {
- return Optional.ofNullable(ItUtils.newAdminWsClient(orchestrator).system().status().getStatus());
- } catch (Exception e) {
- return Optional.empty();
- }
- }
-
- Optional<WsSystem.HealthResponse> getHealth() {
- checkState(config.getType() == NodeConfig.NodeType.APPLICATION);
- if (orchestrator.getServer() == null) {
- return Optional.empty();
- }
- try {
- return Optional.ofNullable(ItUtils.newSystemUserWsClient(orchestrator, systemPassCode).system().health());
- } catch (Exception e) {
- return Optional.empty();
- }
- }
-
- void waitFor(Predicate<Node> predicate) {
- try {
- while (!predicate.test(this)) {
- Thread.sleep(500);
- }
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- }
- }
-
- void assertThatProcessesAreUp() {
- assertThat(arePortsBound()).as(getConfig().getType().toString()).isTrue();
- switch (config.getType()) {
- case SEARCH:
- assertThat(anyLogsContain("Process[es] is up")).isTrue();
- assertThat(anyLogsContain("Process[web] is up")).isFalse();
- assertThat(anyLogsContain("Elasticsearch cluster enabled")).isTrue();
- break;
- case APPLICATION:
- assertThat(anyLogsContain("Process[es] is up")).isFalse();
- assertThat(anyLogsContain("Process[web] is up")).isTrue();
- assertThat(anyLogsContain("Elasticsearch cluster enabled")).isFalse();
- break;
- }
- }
-
- void waitForCeLogsContain(String expectedMessage) {
- boolean found = false;
- while (!found) {
- found = orchestrator.getServer() != null && fileContains(orchestrator.getServer().getCeLogs(), expectedMessage);
- if (!found) {
- Uninterruptibles.sleepUninterruptibly(1_000, TimeUnit.MILLISECONDS);
- }
- }
- }
-
- boolean hasStartupLeaderOperations() throws IOException {
- if (orchestrator.getServer() == null) {
- return false;
- }
- String logs = FileUtils.readFileToString(orchestrator.getServer().getWebLogs());
- return logs.contains("Register metrics") &&
- logs.contains("Register rules");
- }
-
- boolean hasCreatedSearchIndices() throws IOException {
- if (orchestrator.getServer() == null) {
- return false;
- }
- String logs = FileUtils.readFileToString(orchestrator.getServer().getWebLogs());
- return logs.contains("[o.s.s.e.IndexCreator] Create index");
- }
-
- boolean anyLogsContain(String message) {
- return content.hasText(message);
- }
-
- boolean webLogsContain(String message) {
- if (orchestrator.getServer() == null) {
- return false;
- }
- return fileContains(orchestrator.getServer().getWebLogs(), message);
- }
-
- Navigation openBrowser() {
- return Navigation.create(orchestrator);
- }
-
- private static boolean fileContains(@Nullable File logFile, String message) {
- try {
- return logFile != null && logFile.exists() && FileUtils.readFileToString(logFile).contains(message);
- } catch (Exception e) {
- throw new IllegalStateException(e);
- }
- }
-
- private boolean arePortsBound() {
- return isPortBound(config.getHzPort()) &&
- config.getSearchPort().map(this::isPortBound).orElse(true) &&
- config.getWebPort().map(this::isPortBound).orElse(true);
- }
-
- private boolean isPortBound(int port) {
- try (ServerSocket socket = new ServerSocket(port, 50, config.getAddress())) {
- return false;
- } catch (IOException e) {
- return true;
- }
- }
-
- public WsClient wsClient() {
- checkState(config.getType() == NodeConfig.NodeType.APPLICATION);
- return ItUtils.newAdminWsClient(orchestrator);
- }
-}
diff --git a/tests/src/test/java/org/sonarqube/tests/cluster/NodeConfig.java b/tests/src/test/java/org/sonarqube/tests/cluster/NodeConfig.java
deleted file mode 100644
index cd7951a0bb7..00000000000
--- a/tests/src/test/java/org/sonarqube/tests/cluster/NodeConfig.java
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * 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.sonarqube.tests.cluster;
-
-import com.sonar.orchestrator.util.NetworkUtils;
-import java.net.Inet4Address;
-import java.net.InetAddress;
-import java.net.NetworkInterface;
-import java.net.SocketException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.List;
-import java.util.Optional;
-import javax.annotation.Nullable;
-
-import static com.google.common.base.Preconditions.checkArgument;
-
-class NodeConfig {
-
- enum NodeType {
- SEARCH("search"), APPLICATION("application");
-
- final String value;
-
- NodeType(String value) {
- this.value = value;
- }
-
- String getValue() {
- return value;
- }
- }
-
- private final NodeType type;
- @Nullable
- private final String name;
- private final InetAddress address;
- private final int hzPort;
- @Nullable
- private final Integer searchPort;
- @Nullable
- private final Integer webPort;
- private final List<NodeConfig> connectedNodes = new ArrayList<>();
- private final List<NodeConfig> searchNodes = new ArrayList<>();
-
- private NodeConfig(NodeType type, @Nullable String name) {
- this.type = type;
- this.name = name;
- this.address = getNonLoopbackIpv4Address();
- this.hzPort = NetworkUtils.getNextAvailablePort(this.address);
- this.connectedNodes.add(this);
- switch (type) {
- case SEARCH:
- this.searchPort = NetworkUtils.getNextAvailablePort(this.address);
- this.webPort = null;
- this.searchNodes.add(this);
- break;
- case APPLICATION:
- this.searchPort = null;
- this.webPort = NetworkUtils.getNextAvailablePort(this.address);
- break;
- default:
- throw new IllegalArgumentException();
- }
- }
-
- NodeType getType() {
- return type;
- }
-
- Optional<String> getName() {
- return Optional.ofNullable(name);
- }
-
- InetAddress getAddress() {
- return address;
- }
-
- int getHzPort() {
- return hzPort;
- }
-
- Optional<Integer> getSearchPort() {
- return Optional.ofNullable(searchPort);
- }
-
- Optional<Integer> getWebPort() {
- return Optional.ofNullable(webPort);
- }
-
- String getHzHost() {
- return address.getHostAddress() + ":" + hzPort;
- }
-
- String getSearchHost() {
- return address.getHostAddress() + ":" + searchPort;
- }
-
- NodeConfig addConnectionToBus(NodeConfig... configs) {
- connectedNodes.addAll(Arrays.asList(configs));
- return this;
- }
-
- NodeConfig addConnectionToSearch(NodeConfig... configs) {
- Arrays.stream(configs).forEach(config -> {
- checkArgument(config.getType() == NodeType.SEARCH);
- searchNodes.add(config);
- });
- return this;
- }
-
- List<NodeConfig> getConnectedNodes() {
- return connectedNodes;
- }
-
- List<NodeConfig> getSearchNodes() {
- return searchNodes;
- }
-
- static NodeConfig newApplicationConfig(String name) {
- return new NodeConfig(NodeType.APPLICATION, name);
- }
-
- static NodeConfig newSearchConfig(String name) {
- return new NodeConfig(NodeType.SEARCH, name);
- }
-
- /**
- * See property sonar.cluster.hosts
- */
- static void interconnectBus(NodeConfig... configs) {
- Arrays.stream(configs).forEach(config -> Arrays.stream(configs).filter(c -> c != config).forEach(config::addConnectionToBus));
- }
-
- /**
- * See property sonar.cluster.search.hosts
- */
- static void interconnectSearch(NodeConfig... configs) {
- Arrays.stream(configs).forEach(config -> Arrays.stream(configs)
- .filter(c -> c.getType() == NodeType.SEARCH)
- .forEach(config::addConnectionToSearch));
- }
-
- private static InetAddress getNonLoopbackIpv4Address() {
- try {
- Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces();
- for (NetworkInterface networkInterface : Collections.list(nets)) {
- if (!networkInterface.isLoopback() && networkInterface.isUp() && !isBlackListed(networkInterface)) {
- Enumeration<InetAddress> inetAddresses = networkInterface.getInetAddresses();
- while (inetAddresses.hasMoreElements()) {
- InetAddress inetAddress = inetAddresses.nextElement();
- if (inetAddress instanceof Inet4Address) {
- return inetAddress;
- }
- }
- }
- }
- } catch (SocketException se) {
- throw new RuntimeException("Cannot find a non loopback card required for tests", se);
- }
- throw new RuntimeException("Cannot find a non loopback card required for tests");
- }
-
- private static boolean isBlackListed(NetworkInterface networkInterface) {
- return networkInterface.getName().startsWith("docker") ||
- networkInterface.getName().startsWith("vboxnet");
- }
-}