diff options
author | Simon Brandhof <simon.brandhof@sonarsource.com> | 2017-10-17 16:45:10 +0200 |
---|---|---|
committer | Simon Brandhof <simon.brandhof@sonarsource.com> | 2017-10-18 10:43:22 +0200 |
commit | 9e4fe4aca049a680ba0476312f89a5fe133412cf (patch) | |
tree | de8500e3b8c26cfe094f38dd782709a815a273de | |
parent | d3195eafe8e0253fa8a7044013476de94fcb5edb (diff) | |
download | sonarqube-9e4fe4aca049a680ba0476312f89a5fe133412cf.tar.gz sonarqube-9e4fe4aca049a680ba0476312f89a5fe133412cf.zip |
Remove cluster tests
12 files changed, 4 insertions, 1354 deletions
diff --git a/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java b/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java index 9e214a27a86..0964c3cfe22 100644 --- a/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java +++ b/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java @@ -78,7 +78,6 @@ import org.sonar.process.NetworkUtilsImpl; import org.sonar.process.ProcessProperties; import org.sonar.process.Props; import org.sonar.process.logging.LogbackHelper; -import org.sonar.server.cluster.StartableHazelcastMember; import org.sonar.server.component.ComponentFinder; import org.sonar.server.component.index.ComponentIndexer; import org.sonar.server.computation.task.projectanalysis.ProjectAnalysisTaskModule; @@ -426,8 +425,6 @@ public class ComputeEngineContainerImpl implements ComputeEngineContainer { if (props.valueAsBoolean(ProcessProperties.CLUSTER_ENABLED)) { container.add( - StartableHazelcastMember.class, - // system health CeDistributedInformationImpl.class, diff --git a/server/sonar-ce/src/test/java/org/sonar/ce/CeDistributedInformationImplTest.java b/server/sonar-ce/src/test/java/org/sonar/ce/CeDistributedInformationImplTest.java index 8792800ce5c..e61accd9a50 100644 --- a/server/sonar-ce/src/test/java/org/sonar/ce/CeDistributedInformationImplTest.java +++ b/server/sonar-ce/src/test/java/org/sonar/ce/CeDistributedInformationImplTest.java @@ -27,7 +27,7 @@ import java.util.Map; import java.util.Set; import org.junit.Test; import org.sonar.ce.taskprocessor.CeWorkerFactory; -import org.sonar.server.cluster.StartableHazelcastMember; +import org.sonar.process.cluster.hz.HazelcastMember; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.data.MapEntry.entry; @@ -45,7 +45,7 @@ public class CeDistributedInformationImplTest { clientUUID3, ImmutableSet.of("4", "5", "6") ); - private StartableHazelcastMember hzClientWrapper = mock(StartableHazelcastMember.class); + private HazelcastMember hzClientWrapper = mock(HazelcastMember.class); @Test public void getWorkerUUIDs_returns_union_of_workers_uuids_of_local_and_cluster_worker_uuids() { diff --git a/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java b/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java index a4c1e7822fb..9f02e6aa47c 100644 --- a/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java +++ b/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java @@ -21,13 +21,10 @@ package org.sonar.ce.container; import java.io.File; import java.io.IOException; -import java.net.InetAddress; import java.util.Date; -import java.util.Optional; import java.util.Properties; import java.util.stream.Collectors; import org.apache.commons.dbcp.BasicDataSource; -import org.hamcrest.CoreMatchers; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -42,23 +39,15 @@ import org.sonar.ce.CeDistributedInformationImpl; import org.sonar.ce.StandaloneCeDistributedInformation; import org.sonar.db.DbTester; import org.sonar.db.property.PropertyDto; -import org.sonar.process.NetworkUtilsImpl; import org.sonar.process.ProcessId; import org.sonar.process.ProcessProperties; import org.sonar.process.Props; -import org.sonar.server.cluster.StartableHazelcastMember; import static java.lang.String.valueOf; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assume.assumeThat; import static org.mockito.Mockito.mock; import static org.sonar.process.ProcessEntryPoint.PROPERTY_PROCESS_INDEX; -import static org.sonar.process.ProcessEntryPoint.PROPERTY_PROCESS_KEY; import static org.sonar.process.ProcessEntryPoint.PROPERTY_SHARED_PATH; -import static org.sonar.process.ProcessProperties.CLUSTER_ENABLED; -import static org.sonar.process.ProcessProperties.CLUSTER_NODE_HOST; -import static org.sonar.process.ProcessProperties.CLUSTER_NODE_PORT; -import static org.sonar.process.ProcessProperties.CLUSTER_NODE_TYPE; import static org.sonar.process.ProcessProperties.PATH_DATA; import static org.sonar.process.ProcessProperties.PATH_HOME; import static org.sonar.process.ProcessProperties.PATH_TEMP; @@ -86,36 +75,7 @@ public class ComputeEngineContainerImplTest { } @Test - public void real_start_with_cluster() throws IOException { - Optional<InetAddress> localhost = NetworkUtilsImpl.INSTANCE.getLocalNonLoopbackIpv4Address(); - // test is ignored if offline - assumeThat(localhost.isPresent(), CoreMatchers.is(true)); - - Properties properties = getProperties(); - properties.setProperty(PROPERTY_PROCESS_KEY, ProcessId.COMPUTE_ENGINE.getKey()); - properties.setProperty(CLUSTER_ENABLED, "true"); - properties.setProperty(CLUSTER_NODE_TYPE, "application"); - properties.setProperty(CLUSTER_NODE_HOST, localhost.get().getHostAddress()); - properties.setProperty(CLUSTER_NODE_PORT, "" + NetworkUtilsImpl.INSTANCE.getNextAvailablePort(localhost.get())); - - // required persisted properties - insertProperty(CoreProperties.SERVER_ID, "a_startup_id"); - insertProperty(CoreProperties.SERVER_STARTTIME, DateUtils.formatDateTime(new Date())); - - underTest - .start(new Props(properties)); - - MutablePicoContainer picoContainer = underTest.getComponentContainer().getPicoContainer(); - assertThat( - picoContainer.getComponentAdapters().stream() - .map(ComponentAdapter::getComponentImplementation) - .collect(Collectors.toList())).contains((Class) StartableHazelcastMember.class, - (Class) CeDistributedInformationImpl.class); - underTest.stop(); - } - - @Test - public void real_start_without_cluster() throws IOException { + public void test_real_start() throws IOException { Properties properties = getProperties(); // required persisted properties @@ -160,7 +120,7 @@ public class ComputeEngineContainerImplTest { assertThat( picoContainer.getComponentAdapters().stream() .map(ComponentAdapter::getComponentImplementation) - .collect(Collectors.toList())).doesNotContain((Class) StartableHazelcastMember.class, + .collect(Collectors.toList())).doesNotContain( (Class) CeDistributedInformationImpl.class).contains( (Class) StandaloneCeDistributedInformation.class); assertThat(picoContainer.getParent().getParent().getParent().getParent()).isNull(); diff --git a/server/sonar-server/src/main/java/org/sonar/server/cluster/StartableHazelcastMember.java b/server/sonar-server/src/main/java/org/sonar/server/cluster/StartableHazelcastMember.java deleted file mode 100644 index 7bf6c82d487..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/cluster/StartableHazelcastMember.java +++ /dev/null @@ -1,156 +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.sonar.server.cluster; - -import com.hazelcast.core.Cluster; -import com.hazelcast.core.IAtomicReference; -import com.hazelcast.core.MemberSelector; -import java.net.UnknownHostException; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.locks.Lock; -import org.sonar.api.Startable; -import org.sonar.api.config.Configuration; -import org.sonar.process.NetworkUtils; -import org.sonar.process.ProcessId; -import org.sonar.process.ProcessProperties; -import org.sonar.process.cluster.NodeType; -import org.sonar.process.cluster.hz.DistributedAnswer; -import org.sonar.process.cluster.hz.DistributedCall; -import org.sonar.process.cluster.hz.HazelcastMember; -import org.sonar.process.cluster.hz.HazelcastMemberBuilder; - -import static java.lang.String.format; -import static java.util.Arrays.asList; -import static java.util.Objects.requireNonNull; -import static org.sonar.process.ProcessEntryPoint.PROPERTY_PROCESS_KEY; -import static org.sonar.process.ProcessProperties.CLUSTER_HOSTS; -import static org.sonar.process.ProcessProperties.CLUSTER_NODE_HOST; -import static org.sonar.process.ProcessProperties.CLUSTER_NODE_TYPE; - -/** - * Implementation of {@link HazelcastMember} as used by Compute Engine and - * Web Server processes. It is configured by {@link Configuration} - * and its lifecycle is managed by picocontainer. - */ -public class StartableHazelcastMember implements HazelcastMember, Startable { - - private final Configuration config; - private final NetworkUtils network; - private HazelcastMember member = null; - - public StartableHazelcastMember(Configuration config, NetworkUtils network) { - this.config = config; - this.network = network; - } - - @Override - public <E> IAtomicReference<E> getAtomicReference(String name) { - return nonNullMember().getAtomicReference(name); - } - - @Override - public <E> Set<E> getSet(String name) { - return nonNullMember().getSet(name); - } - - @Override - public <E> List<E> getList(String name) { - return nonNullMember().getList(name); - } - - @Override - public <K, V> Map<K, V> getMap(String name) { - return nonNullMember().getMap(name); - } - - @Override - public <K, V> Map<K, V> getReplicatedMap(String name) { - return nonNullMember().getReplicatedMap(name); - } - - @Override - public String getUuid() { - return nonNullMember().getUuid(); - } - - @Override - public Set<String> getMemberUuids() { - return nonNullMember().getMemberUuids(); - } - - @Override - public Lock getLock(String name) { - return nonNullMember().getLock(name); - } - - @Override - public long getClusterTime() { - return nonNullMember().getClusterTime(); - } - - @Override - public Cluster getCluster() { - return nonNullMember().getCluster(); - } - - @Override - public <T> DistributedAnswer<T> call(DistributedCall<T> callable, MemberSelector memberSelector, long timeoutMs) - throws InterruptedException { - return nonNullMember().call(callable, memberSelector, timeoutMs); - } - - private HazelcastMember nonNullMember() { - return requireNonNull(member, "Hazelcast member not started"); - } - - @Override - public void close() { - if (member != null) { - member.close(); - member = null; - } - } - - @Override - public void start() { - String networkAddress = config.get(CLUSTER_NODE_HOST).orElseThrow(() -> new IllegalStateException("Missing node host")); - int freePort; - try { - freePort = network.getNextAvailablePort(network.toInetAddress(networkAddress)); - } catch (UnknownHostException e) { - throw new IllegalStateException(format("Can not resolve address %s", networkAddress), e); - } - this.member = new HazelcastMemberBuilder() - .setNodeName(config.get(ProcessProperties.CLUSTER_NODE_NAME).orElseThrow(() -> new IllegalStateException("Missing node name"))) - .setNodeType(NodeType.parse(config.get(CLUSTER_NODE_TYPE).orElseThrow(() -> new IllegalStateException("Missing node type")))) - .setPort(freePort) - .setProcessId(ProcessId.fromKey(config.get(PROPERTY_PROCESS_KEY).orElseThrow(() -> new IllegalStateException("Missing process key")))) - .setMembers(asList(config.getStringArray(CLUSTER_HOSTS))) - .setNetworkInterface(networkAddress) - .build(); - } - - @Override - public void stop() { - close(); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/cluster/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/cluster/package-info.java deleted file mode 100644 index 28ed7dc786f..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/cluster/package-info.java +++ /dev/null @@ -1,23 +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. - */ -@ParametersAreNonnullByDefault -package org.sonar.server.cluster; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java index ed55f0e1cb8..b7ef5fd0193 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java @@ -39,7 +39,6 @@ import org.sonar.server.authentication.LogOAuthWarning; import org.sonar.server.batch.BatchWsModule; import org.sonar.server.branch.BranchFeatureProxyImpl; import org.sonar.server.ce.ws.CeWsModule; -import org.sonar.server.cluster.StartableHazelcastMember; import org.sonar.server.component.ComponentCleanerService; import org.sonar.server.component.ComponentFinder; import org.sonar.server.component.ComponentService; @@ -247,7 +246,6 @@ public class PlatformLevel4 extends PlatformLevel { EsDbCompatibilityImpl.class); addIfCluster( - StartableHazelcastMember.class, NodeHealthModule.class, ChangeLogLevelClusterService.class); addIfStandalone( diff --git a/server/sonar-server/src/test/java/org/sonar/server/cluster/StartableHazelcastMemberTest.java b/server/sonar-server/src/test/java/org/sonar/server/cluster/StartableHazelcastMemberTest.java deleted file mode 100644 index 84e82d23386..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/cluster/StartableHazelcastMemberTest.java +++ /dev/null @@ -1,107 +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.sonar.server.cluster; - -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.function.Supplier; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.api.config.internal.MapSettings; -import org.sonar.process.NetworkUtils; -import org.sonar.process.NetworkUtilsImpl; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; - -public class StartableHazelcastMemberTest { - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - private MapSettings settings = new MapSettings(); - private String loopback = InetAddress.getLoopbackAddress().getHostAddress(); - - @Test - public void start_initializes_hazelcast() { - completeValidSettings(); - StartableHazelcastMember underTest = new StartableHazelcastMember(settings.asConfig(), NetworkUtilsImpl.INSTANCE); - verifyStopped(underTest); - - underTest.start(); - - assertThat(underTest.getUuid()).isNotEmpty(); - assertThat(underTest.getCluster().getMembers()).hasSize(1); - assertThat(underTest.getMemberUuids()).containsExactly(underTest.getUuid()); - assertThat(underTest.getSet("foo")).isNotNull(); - assertThat(underTest.getReplicatedMap("foo")).isNotNull(); - assertThat(underTest.getAtomicReference("foo")).isNotNull(); - assertThat(underTest.getList("foo")).isNotNull(); - assertThat(underTest.getMap("foo")).isNotNull(); - assertThat(underTest.getLock("foo")).isNotNull(); - assertThat(underTest.getClusterTime()).isGreaterThan(0); - - underTest.stop(); - - verifyStopped(underTest); - } - - @Test - public void throw_ISE_if_host_for_random_port_cant_be_resolved() throws Exception{ - NetworkUtils network = mock(NetworkUtils.class); - doThrow(new UnknownHostException("BOOM")).when(network).toInetAddress(anyString()); - completeValidSettings(); - StartableHazelcastMember underTest = new StartableHazelcastMember(settings.asConfig(), network); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("Can not resolve address "); - - underTest.start(); - - verifyStopped(underTest); - } - - private void completeValidSettings() { - settings.setProperty("sonar.cluster.name", "foo"); - settings.setProperty("sonar.cluster.node.host", loopback); - settings.setProperty("sonar.cluster.node.name", "bar"); - settings.setProperty("sonar.cluster.node.type", "application"); - settings.setProperty("process.key", "ce"); - } - - private static void verifyStopped(StartableHazelcastMember member) { - expectNpe(member::getMemberUuids); - expectNpe(member::getCluster); - expectNpe(member::getUuid); - } - - private static void expectNpe(Supplier supplier) { - try { - supplier.get(); - fail(); - } catch (NullPointerException e) { - } - } - -} 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"); - } -} |