/* * SonarQube * Copyright (C) 2009-2017 SonarSource SA * mailto:info AT sonarsource DOT com * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package org.sonar.application.cluster; import com.hazelcast.core.HazelcastInstance; import java.io.IOException; import org.junit.Rule; import org.junit.Test; import org.junit.rules.DisableOnDebug; import org.junit.rules.ExpectedException; import org.junit.rules.TestRule; import org.junit.rules.Timeout; import org.slf4j.Logger; import org.sonar.application.AppStateListener; import org.sonar.application.config.TestAppSettings; import org.sonar.process.ProcessId; import org.sonar.process.ProcessProperties; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.verify; import static org.sonar.application.cluster.HazelcastTestHelper.createHazelcastClient; import static org.sonar.application.cluster.HazelcastTestHelper.newClusterSettings; import static org.sonar.process.cluster.ClusterObjectKeys.SONARQUBE_VERSION; public class AppStateClusterImplTest { @Rule public ExpectedException expectedException = ExpectedException.none(); @Rule public TestRule safeguardTimeout = new DisableOnDebug(Timeout.seconds(60)); @Test public void instantiation_throws_ISE_if_cluster_mode_is_disabled() throws Exception { TestAppSettings settings = new TestAppSettings(); settings.set(ProcessProperties.CLUSTER_ENABLED, "false"); expectedException.expect(IllegalStateException.class); expectedException.expectMessage("Cluster is not enabled on this instance"); new AppStateClusterImpl(settings); } @Test public void tryToLockWebLeader_returns_true_only_for_the_first_call() throws Exception { TestAppSettings settings = newClusterSettings(); try (AppStateClusterImpl underTest = new AppStateClusterImpl(settings)) { assertThat(underTest.tryToLockWebLeader()).isEqualTo(true); assertThat(underTest.tryToLockWebLeader()).isEqualTo(false); } } @Test public void log_when_sonarqube_is_joining_a_cluster () throws IOException, InterruptedException, IllegalAccessException, NoSuchFieldException { // Now launch an instance that try to be part of the hzInstance cluster TestAppSettings settings = newClusterSettings(); Logger logger = mock(Logger.class); AppStateClusterImpl.setLogger(logger); try (AppStateClusterImpl appStateCluster = new AppStateClusterImpl(settings)) { verify(logger).info( eq("Joined the cluster [{}] that contains the following hosts : [{}]"), eq("sonarqube"), anyString() ); } } @Test public void test_listeners() throws InterruptedException { AppStateListener listener = mock(AppStateListener.class); try (AppStateClusterImpl underTest = new AppStateClusterImpl(newClusterSettings())) { underTest.addListener(listener); underTest.setOperational(ProcessId.ELASTICSEARCH); verify(listener, timeout(20_000)).onAppStateOperational(ProcessId.ELASTICSEARCH); assertThat(underTest.isOperational(ProcessId.ELASTICSEARCH, true)).isEqualTo(true); assertThat(underTest.isOperational(ProcessId.APP, true)).isEqualTo(false); assertThat(underTest.isOperational(ProcessId.WEB_SERVER, true)).isEqualTo(false); assertThat(underTest.isOperational(ProcessId.COMPUTE_ENGINE, true)).isEqualTo(false); } } @Test public void registerSonarQubeVersion_publishes_version_on_first_call() { TestAppSettings settings = newClusterSettings(); try (AppStateClusterImpl appStateCluster = new AppStateClusterImpl(settings)) { appStateCluster.registerSonarQubeVersion("6.4.1.5"); HazelcastInstance hzInstance = createHazelcastClient(appStateCluster); assertThat(hzInstance.getAtomicReference(SONARQUBE_VERSION).get()) .isNotNull() .isInstanceOf(String.class) .isEqualTo("6.4.1.5"); } } @Test public void reset_throws_always_ISE() { TestAppSettings settings = newClusterSettings(); try (AppStateClusterImpl appStateCluster = new AppStateClusterImpl(settings)) { expectedException.expect(IllegalStateException.class); expectedException.expectMessage("state reset is not supported in cluster mode"); appStateCluster.reset(); } } @Test public void registerSonarQubeVersion_throws_ISE_if_initial_version_is_different() throws Exception { // Now launch an instance that try to be part of the hzInstance cluster TestAppSettings settings = newClusterSettings(); try (AppStateClusterImpl appStateCluster = new AppStateClusterImpl(settings)) { // Register first version appStateCluster.registerSonarQubeVersion("1.0.0"); expectedException.expect(IllegalStateException.class); expectedException.expectMessage("The local version 2.0.0 is not the same as the cluster 1.0.0"); // Registering a second different version must trigger an exception appStateCluster.registerSonarQubeVersion("2.0.0"); } } }