/* * 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.ce.cluster; import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.AppenderBase; import com.google.common.collect.ImmutableSet; import com.hazelcast.client.impl.HazelcastClientInstanceImpl; import com.hazelcast.client.impl.HazelcastClientProxy; import com.hazelcast.core.HazelcastInstance; import java.net.InetAddress; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import org.apache.commons.lang.RandomStringUtils; import org.junit.AfterClass; import org.junit.BeforeClass; 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.LoggerFactory; import org.sonar.api.config.MapSettings; import org.sonar.api.config.PropertyDefinitions; import org.sonar.api.config.Settings; import org.sonar.process.NetworkUtils; import org.sonar.process.ProcessProperties; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.data.MapEntry.entry; public class HazelcastClientWrapperImplTest { @Rule public ExpectedException expectedException = ExpectedException.none(); @Rule public TestRule safeguardTimeout = new DisableOnDebug(Timeout.seconds(60)); private static HazelcastInstance hzCluster; private static HazelcastClientWrapperImpl hzClient; @BeforeClass public static void setupHazelcastClusterAndHazelcastClient() { int port = NetworkUtils.getNextAvailablePort(InetAddress.getLoopbackAddress()); hzCluster = HazelcastTestHelper.createHazelcastCluster("cluster_with_client", port); Settings settings = createClusterSettings("cluster_with_client", "localhost:" + port); hzClient = new HazelcastClientWrapperImpl(settings); } @AfterClass public static void stopHazelcastClusterAndHazelcastClient() { try { hzClient.stop(); } catch (Exception e) { // Ignore it } try { hzCluster.shutdown(); } catch (Exception e) { // Ignore it } } @Test public void start_throws_ISE_if_LOCALENDPOINT_is_incorrect() { Settings settings = createClusterSettings("sonarqube", "\u4563\u1432\u1564"); HazelcastClientWrapperImpl hzClient = new HazelcastClientWrapperImpl(settings); expectedException.expect(IllegalStateException.class); expectedException.expectMessage("Unable to connect to any address in the config! The following addresses were tried:"); hzClient.start(); } @Test public void constructor_throws_ISE_if_LOCALENDPOINT_is_empty() { Settings settings = createClusterSettings("sonarqube", ""); expectedException.expect(IllegalStateException.class); expectedException.expectMessage("LocalEndPoint have not been set"); new HazelcastClientWrapperImpl(settings); } @Test public void constructor_throws_ISE_if_CLUSTER_ENABLED_is_false() { Settings settings = createClusterSettings("sonarqube", "localhost:9003"); settings.setProperty(ProcessProperties.CLUSTER_ENABLED, false); expectedException.expect(IllegalStateException.class); expectedException.expectMessage("Cluster is not enabled"); new HazelcastClientWrapperImpl(settings); } @Test public void constructor_throws_ISE_if_missing_CLUSTER_ENABLED() { Settings settings = createClusterSettings("sonarqube", "localhost:9003"); settings.removeProperty(ProcessProperties.CLUSTER_ENABLED); expectedException.expect(IllegalStateException.class); expectedException.expectMessage("Cluster is not enabled"); new HazelcastClientWrapperImpl(settings); } @Test public void constructor_throws_ISE_if_missing_CLUSTER_NAME() { Settings settings = createClusterSettings("sonarqube", "localhost:9003"); settings.removeProperty(ProcessProperties.CLUSTER_NAME); expectedException.expect(IllegalStateException.class); expectedException.expectMessage("sonar.cluster.name is missing"); new HazelcastClientWrapperImpl(settings); } @Test public void constructor_throws_ISE_if_missing_CLUSTER_LOCALENDPOINT() { Settings settings = createClusterSettings("sonarqube", "localhost:9003"); settings.removeProperty(ProcessProperties.CLUSTER_LOCALENDPOINT); expectedException.expect(IllegalStateException.class); expectedException.expectMessage("LocalEndPoint have not been set"); new HazelcastClientWrapperImpl(settings); } @Test public void client_must_connect_to_hazelcast() { int port = NetworkUtils.getNextAvailablePort(InetAddress.getLoopbackAddress()); // Launch a fake Hazelcast instance HazelcastInstance hzInstance = HazelcastTestHelper.createHazelcastCluster("client_must_connect_to_hazelcast", port); Settings settings = createClusterSettings("client_must_connect_to_hazelcast", "localhost:" + port); HazelcastClientWrapperImpl hazelcastClientWrapperImpl = new HazelcastClientWrapperImpl(settings); try { hazelcastClientWrapperImpl.start(); assertThat(hazelcastClientWrapperImpl.getConnectedClients()).hasSize(1); assertThat(hazelcastClientWrapperImpl.getClientUUID()).isNotEmpty(); } finally { hazelcastClientWrapperImpl.stop(); } } @Test public void client_must_be_able_to_set_ReplicatedMap_objects() throws InterruptedException { try { hzClient.start(); Set<String> setTest = new HashSet<>(); setTest.addAll( Arrays.asList(RandomStringUtils.randomAlphanumeric(10), RandomStringUtils.randomAlphanumeric(10)) ); Map<String, Set<String>> replicatedMap = hzClient.getReplicatedMap("TEST1"); replicatedMap.put("KEY1", ImmutableSet.copyOf(setTest)); assertThat(hzCluster.getReplicatedMap("TEST1")) .containsOnlyKeys("KEY1"); assertThat(hzCluster.getReplicatedMap("TEST1").get("KEY1")) .isEqualTo(setTest); } finally { hzClient.stop(); } } @Test public void client_must_be_able_to_retrieve_Set_objects() { try { hzClient.start(); // Set Set<String> setTest = new HashSet<>(); setTest.addAll(Arrays.asList("8", "9")); hzCluster.getSet("TEST1").addAll(setTest); assertThat(hzClient.getSet("TEST1")).containsAll(setTest); } finally { hzClient.stop(); } } @Test public void client_must_be_able_to_retrieve_List_objects() { try { hzClient.start(); // List List<String> listTest = Arrays.asList("1", "2"); hzCluster.getList("TEST2").addAll(listTest); assertThat(hzClient.getList("TEST2")).containsAll(listTest); } finally { hzClient.stop(); } } @Test public void client_must_be_able_to_retrieve_Map_objects() { try { hzClient.start(); Map mapTest = new HashMap<>(); mapTest.put("a", Arrays.asList("123", "456")); hzCluster.getMap("TEST3").putAll(mapTest); assertThat(hzClient.getMap("TEST3")).containsExactly( entry("a", Arrays.asList("123", "456")) ); } finally { hzClient.stop(); } } @Test public void configuration_tweaks_of_hazelcast_must_be_present() { try { hzClient.start(); HazelcastClientInstanceImpl realClient = ((HazelcastClientProxy) hzClient.hzInstance).client; assertThat(realClient.getClientConfig().getProperty("hazelcast.tcp.join.port.try.count")).isEqualTo("10"); assertThat(realClient.getClientConfig().getProperty("hazelcast.phone.home.enabled")).isEqualTo("false"); assertThat(realClient.getClientConfig().getProperty("hazelcast.logging.type")).isEqualTo("slf4j"); } finally { hzClient.stop(); } } @Test public void hazelcast_client_must_log_through_sl4fj() { MemoryAppender<ILoggingEvent> memoryAppender = new MemoryAppender<>(); LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); lc.reset(); memoryAppender.setContext(lc); memoryAppender.start(); lc.getLogger("com.hazelcast").addAppender(memoryAppender); try { hzClient.start(); } finally { hzClient.stop(); memoryAppender.stop(); } assertThat(memoryAppender.events).isNotEmpty(); memoryAppender.events.stream().forEach( e -> assertThat(e.getLoggerName()).startsWith("com.hazelcast") ); } private static Settings createClusterSettings(String name, String localEndPoint) { Properties properties = new Properties(); properties.setProperty(ProcessProperties.CLUSTER_NAME, name); properties.setProperty(ProcessProperties.CLUSTER_LOCALENDPOINT, localEndPoint); properties.setProperty(ProcessProperties.CLUSTER_ENABLED, "true"); return new MapSettings(new PropertyDefinitions()).addProperties(properties); } private class MemoryAppender<E> extends AppenderBase<E> { private final List<E> events = new ArrayList(); @Override protected void append(E eventObject) { events.add(eventObject); } } }