From 22022d06b61b5ffb20c292b36fd697ec7de7c381 Mon Sep 17 00:00:00 2001 From: Eric Hartmann Date: Fri, 8 Sep 2017 17:09:23 +0200 Subject: [PATCH] Fix quality flaws --- .../application/cluster/HazelcastCluster.java | 7 +- .../cluster/AppStateClusterImplTest.java | 18 ++-- .../cluster/HazelcastClusterTest.java | 84 ++++++++++++++----- .../cluster/HazelcastTestHelper.java | 16 +++- 4 files changed, 88 insertions(+), 37 deletions(-) diff --git a/server/sonar-main/src/main/java/org/sonar/application/cluster/HazelcastCluster.java b/server/sonar-main/src/main/java/org/sonar/application/cluster/HazelcastCluster.java index 523ed681652..54c0c7bd69b 100644 --- a/server/sonar-main/src/main/java/org/sonar/application/cluster/HazelcastCluster.java +++ b/server/sonar-main/src/main/java/org/sonar/application/cluster/HazelcastCluster.java @@ -161,6 +161,11 @@ public class HazelcastCluster implements AutoCloseable { } } + public String getSonarQubeVersion() { + IAtomicReference sqVersion = hzInstance.getAtomicReference(SONARQUBE_VERSION); + return sqVersion.get(); + } + public void registerClusterName(String nodeValue) { IAtomicReference property = hzInstance.getAtomicReference(CLUSTER_NAME); if (property.get() == null) { @@ -190,7 +195,7 @@ public class HazelcastCluster implements AutoCloseable { // Removing listeners operationalProcesses.removeEntryListener(operationalProcessListenerUUID); hzInstance.getClientService().removeClientListener(clientListenerUUID); - hzInstance.getCluster().removeMembershipListener(nodeDisconnectedListenerUUID); + hzInstance.getCluster().removeMembershipListener(nodeDisconnectedListenerUUID); // Removing the operationalProcess from the replicated map operationalProcesses.keySet().forEach( diff --git a/server/sonar-main/src/test/java/org/sonar/application/cluster/AppStateClusterImplTest.java b/server/sonar-main/src/test/java/org/sonar/application/cluster/AppStateClusterImplTest.java index e80e932b528..e1a903db8fd 100644 --- a/server/sonar-main/src/test/java/org/sonar/application/cluster/AppStateClusterImplTest.java +++ b/server/sonar-main/src/test/java/org/sonar/application/cluster/AppStateClusterImplTest.java @@ -42,7 +42,7 @@ 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.application.cluster.HazelcastTestHelper.newApplicationSettings; import static org.sonar.process.cluster.ClusterObjectKeys.CLUSTER_NAME; import static org.sonar.process.cluster.ClusterObjectKeys.SONARQUBE_VERSION; @@ -67,7 +67,7 @@ public class AppStateClusterImplTest { @Test public void tryToLockWebLeader_returns_true_only_for_the_first_call() throws Exception { - TestAppSettings settings = newClusterSettings(); + TestAppSettings settings = newApplicationSettings(); try (AppStateClusterImpl underTest = new AppStateClusterImpl(settings)) { assertThat(underTest.tryToLockWebLeader()).isEqualTo(true); @@ -78,7 +78,7 @@ public class AppStateClusterImplTest { @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(); + TestAppSettings settings = newApplicationSettings(); Logger logger = mock(Logger.class); AppStateClusterImpl.setLogger(logger); @@ -94,7 +94,7 @@ public class AppStateClusterImplTest { @Test public void test_listeners() throws InterruptedException { AppStateListener listener = mock(AppStateListener.class); - try (AppStateClusterImpl underTest = new AppStateClusterImpl(newClusterSettings())) { + try (AppStateClusterImpl underTest = new AppStateClusterImpl(newApplicationSettings())) { underTest.addListener(listener); underTest.setOperational(ProcessId.ELASTICSEARCH); @@ -109,7 +109,7 @@ public class AppStateClusterImplTest { @Test public void registerSonarQubeVersion_publishes_version_on_first_call() { - TestAppSettings settings = newClusterSettings(); + TestAppSettings settings = newApplicationSettings(); try (AppStateClusterImpl appStateCluster = new AppStateClusterImpl(settings)) { appStateCluster.registerSonarQubeVersion("6.4.1.5"); @@ -124,7 +124,7 @@ public class AppStateClusterImplTest { @Test public void registerClusterName_publishes_clusterName_on_first_call() { - TestAppSettings settings = newClusterSettings(); + TestAppSettings settings = newApplicationSettings(); String clusterName = randomAlphanumeric(20); try (AppStateClusterImpl appStateCluster = new AppStateClusterImpl(settings)) { @@ -140,7 +140,7 @@ public class AppStateClusterImplTest { @Test public void reset_throws_always_ISE() { - TestAppSettings settings = newClusterSettings(); + TestAppSettings settings = newApplicationSettings(); try (AppStateClusterImpl appStateCluster = new AppStateClusterImpl(settings)) { expectedException.expect(IllegalStateException.class); @@ -152,7 +152,7 @@ public class AppStateClusterImplTest { @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(); + TestAppSettings settings = newApplicationSettings(); try (AppStateClusterImpl appStateCluster = new AppStateClusterImpl(settings)) { // Register first version @@ -169,7 +169,7 @@ public class AppStateClusterImplTest { @Test public void registerClusterName_throws_MessageException_if_clusterName_is_different() throws Exception { // Now launch an instance that try to be part of the hzInstance cluster - TestAppSettings settings = newClusterSettings(); + TestAppSettings settings = newApplicationSettings(); try (AppStateClusterImpl appStateCluster = new AppStateClusterImpl(settings)) { // Register first version diff --git a/server/sonar-main/src/test/java/org/sonar/application/cluster/HazelcastClusterTest.java b/server/sonar-main/src/test/java/org/sonar/application/cluster/HazelcastClusterTest.java index 81d5a818191..2be53baca1d 100644 --- a/server/sonar-main/src/test/java/org/sonar/application/cluster/HazelcastClusterTest.java +++ b/server/sonar-main/src/test/java/org/sonar/application/cluster/HazelcastClusterTest.java @@ -57,8 +57,11 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.sonar.application.cluster.HazelcastTestHelper.closeAllHazelcastClients; import static org.sonar.application.cluster.HazelcastTestHelper.createHazelcastClient; -import static org.sonar.application.cluster.HazelcastTestHelper.newClusterSettings; +import static org.sonar.application.cluster.HazelcastTestHelper.newApplicationSettings; +import static org.sonar.application.cluster.HazelcastTestHelper.newSearchSettings; +import static org.sonar.process.ProcessProperties.CLUSTER_HOSTS; import static org.sonar.process.ProcessProperties.CLUSTER_NAME; +import static org.sonar.process.ProcessProperties.CLUSTER_NODE_PORT; import static org.sonar.process.cluster.ClusterObjectKeys.LEADER; import static org.sonar.process.cluster.ClusterObjectKeys.OPERATIONAL_PROCESSES; import static org.sonar.process.cluster.ClusterObjectKeys.SONARQUBE_VERSION; @@ -77,7 +80,7 @@ public class HazelcastClusterTest { @Test public void test_two_tryToLockWebLeader_must_return_true() { - ClusterProperties clusterProperties = new ClusterProperties(newClusterSettings()); + ClusterProperties clusterProperties = new ClusterProperties(newApplicationSettings()); try (HazelcastCluster hzCluster = HazelcastCluster.create(clusterProperties)) { assertThat(hzCluster.tryToLockWebLeader()).isEqualTo(true); assertThat(hzCluster.tryToLockWebLeader()).isEqualTo(false); @@ -86,7 +89,7 @@ public class HazelcastClusterTest { @Test public void when_another_process_locked_webleader_tryToLockWebLeader_must_return_false() { - ClusterProperties clusterProperties = new ClusterProperties(newClusterSettings()); + ClusterProperties clusterProperties = new ClusterProperties(newApplicationSettings()); try (HazelcastCluster hzCluster = HazelcastCluster.create(clusterProperties)) { HazelcastInstance hzInstance = createHazelcastClient(hzCluster); hzInstance.getAtomicReference(LEADER).set("aaaa"); @@ -96,7 +99,7 @@ public class HazelcastClusterTest { @Test public void when_no_leader_getLeaderHostName_must_return_NO_LEADER() { - ClusterProperties clusterProperties = new ClusterProperties(newClusterSettings()); + ClusterProperties clusterProperties = new ClusterProperties(newApplicationSettings()); try (HazelcastCluster hzCluster = HazelcastCluster.create(clusterProperties)) { assertThat(hzCluster.getLeaderHostName()).isEmpty(); } @@ -104,7 +107,7 @@ public class HazelcastClusterTest { @Test public void when_no_leader_getLeaderHostName_must_return_the_hostname() { - ClusterProperties clusterProperties = new ClusterProperties(newClusterSettings()); + ClusterProperties clusterProperties = new ClusterProperties(newApplicationSettings()); try (HazelcastCluster hzCluster = HazelcastCluster.create(clusterProperties)) { assertThat(hzCluster.tryToLockWebLeader()).isTrue(); assertThat(hzCluster.getLeaderHostName().get()).isEqualTo( @@ -114,7 +117,7 @@ public class HazelcastClusterTest { @Test public void members_must_be_empty_when_there_is_no_other_node() { - ClusterProperties clusterProperties = new ClusterProperties(newClusterSettings()); + ClusterProperties clusterProperties = new ClusterProperties(newApplicationSettings()); try (HazelcastCluster hzCluster = HazelcastCluster.create(clusterProperties)) { assertThat(hzCluster.getMembers()).isEmpty(); } @@ -122,7 +125,7 @@ public class HazelcastClusterTest { @Test public void set_operational_is_writing_to_cluster() { - ClusterProperties clusterProperties = new ClusterProperties(newClusterSettings()); + ClusterProperties clusterProperties = new ClusterProperties(newApplicationSettings()); try (HazelcastCluster hzCluster = HazelcastCluster.create(clusterProperties)) { hzCluster.setOperational(ProcessId.ELASTICSEARCH); @@ -140,7 +143,7 @@ public class HazelcastClusterTest { @Test public void hazelcast_cluster_name_is_hardcoded_and_not_affected_by_settings() { - TestAppSettings testAppSettings = newClusterSettings(); + TestAppSettings testAppSettings = newApplicationSettings(); testAppSettings.set(CLUSTER_NAME, "a_cluster_"); ClusterProperties clusterProperties = new ClusterProperties(testAppSettings); try (HazelcastCluster hzCluster = HazelcastCluster.create(clusterProperties)) { @@ -150,7 +153,7 @@ public class HazelcastClusterTest { @Test public void cluster_must_keep_a_list_of_clients() throws InterruptedException { - TestAppSettings testAppSettings = newClusterSettings(); + TestAppSettings testAppSettings = newApplicationSettings(); testAppSettings.set(CLUSTER_NAME, "a_cluster_"); ClusterProperties clusterProperties = new ClusterProperties(testAppSettings); try (HazelcastCluster hzCluster = HazelcastCluster.create(clusterProperties)) { @@ -181,7 +184,7 @@ public class HazelcastClusterTest { @Test public void localUUID_must_not_be_empty() { - ClusterProperties clusterProperties = new ClusterProperties(newClusterSettings()); + ClusterProperties clusterProperties = new ClusterProperties(newApplicationSettings()); try (HazelcastCluster hzCluster = HazelcastCluster.create(clusterProperties)) { assertThat(hzCluster.getLocalUUID()).isNotEmpty(); } @@ -189,7 +192,7 @@ public class HazelcastClusterTest { @Test public void when_a_process_is_set_operational_listener_must_be_triggered() { - ClusterProperties clusterProperties = new ClusterProperties(newClusterSettings()); + ClusterProperties clusterProperties = new ClusterProperties(newApplicationSettings()); try (HazelcastCluster hzCluster = HazelcastCluster.create(clusterProperties)) { AppStateListener listener = mock(AppStateListener.class); hzCluster.addListener(listener); @@ -209,10 +212,9 @@ public class HazelcastClusterTest { } } - @Test public void registerSonarQubeVersion_publishes_version_on_first_call() { - ClusterProperties clusterProperties = new ClusterProperties(newClusterSettings()); + ClusterProperties clusterProperties = new ClusterProperties(newApplicationSettings()); try (HazelcastCluster hzCluster = HazelcastCluster.create(clusterProperties)) { hzCluster.registerSonarQubeVersion("1.0.0.0"); @@ -223,7 +225,7 @@ public class HazelcastClusterTest { @Test public void registerSonarQubeVersion_throws_ISE_if_initial_version_is_different() throws Exception { - ClusterProperties clusterProperties = new ClusterProperties(newClusterSettings()); + ClusterProperties clusterProperties = new ClusterProperties(newApplicationSettings()); try (HazelcastCluster hzCluster = HazelcastCluster.create(clusterProperties)) { // Register first version hzCluster.registerSonarQubeVersion("1.0.0"); @@ -238,7 +240,7 @@ public class HazelcastClusterTest { @Test public void simulate_network_cluster() throws InterruptedException { - TestAppSettings settings = newClusterSettings(); + TestAppSettings settings = newApplicationSettings(); settings.set(ProcessProperties.CLUSTER_NODE_HOST, InetAddress.getLoopbackAddress().getHostAddress()); AppStateListener listener = mock(AppStateListener.class); @@ -275,7 +277,7 @@ public class HazelcastClusterTest { memoryAppender.start(); lc.getLogger("com.hazelcast").addAppender(memoryAppender); - try (AppStateClusterImpl appStateCluster = new AppStateClusterImpl(newClusterSettings())) { + try (AppStateClusterImpl appStateCluster = new AppStateClusterImpl(newApplicationSettings())) { } assertThat(memoryAppender.events).isNotEmpty(); @@ -284,23 +286,59 @@ public class HazelcastClusterTest { ); } - private class MemoryAppender extends AppenderBase { - private final List events = new ArrayList(); + @Test + public void removing_the_last_application_node_must_clear_web_leader() throws InterruptedException { + try (AppStateClusterImpl appStateCluster = new AppStateClusterImpl(newSearchSettings())) { + TestAppSettings appSettings = newApplicationSettings(); + appSettings.set(CLUSTER_HOSTS, appStateCluster.getHazelcastCluster().getLocalEndPoint()); + appSettings.set(CLUSTER_NODE_PORT, "9004"); + ClusterProperties clusterProperties = new ClusterProperties(appSettings); + + // Simulate a connection from an application node + HazelcastCluster appNode = HazelcastCluster.create(clusterProperties); + appNode.tryToLockWebLeader(); + appNode.setOperational(ProcessId.WEB_SERVER); + appNode.setOperational(ProcessId.COMPUTE_ENGINE); + appNode.registerSonarQubeVersion("6.6.0.22999"); + + assertThat(appStateCluster.getLeaderHostName()).isPresent(); + assertThat(appStateCluster.isOperational(ProcessId.WEB_SERVER, false)).isTrue(); + assertThat(appStateCluster.isOperational(ProcessId.COMPUTE_ENGINE, false)).isTrue(); + assertThat(appStateCluster.getHazelcastCluster().getSonarQubeVersion()).isEqualTo("6.6.0.22999"); + + // Shutdown the node + appNode.close(); + + // Propagation of all information take some time, let's wait 5s maximum + int counter = 10; + while (appStateCluster.getHazelcastCluster().getSonarQubeVersion() != null && counter > 0) { + Thread.sleep(500); + counter--; + } - @Override - protected void append(E eventObject) { - events.add(eventObject); + assertThat(appStateCluster.getLeaderHostName()).isNotPresent(); + assertThat(appStateCluster.isOperational(ProcessId.WEB_SERVER, false)).isFalse(); + assertThat(appStateCluster.isOperational(ProcessId.COMPUTE_ENGINE, false)).isFalse(); + assertThat(appStateCluster.getHazelcastCluster().getSonarQubeVersion()).isNull(); } } - @Test public void configuration_tweaks_of_hazelcast_must_be_present() { - try (HazelcastCluster hzCluster = HazelcastCluster.create(new ClusterProperties(newClusterSettings()))) { + try (HazelcastCluster hzCluster = HazelcastCluster.create(new ClusterProperties(newApplicationSettings()))) { assertThat(hzCluster.hzInstance.getConfig().getProperty("hazelcast.tcp.join.port.try.count")).isEqualTo("10"); assertThat(hzCluster.hzInstance.getConfig().getProperty("hazelcast.phone.home.enabled")).isEqualTo("false"); assertThat(hzCluster.hzInstance.getConfig().getProperty("hazelcast.logging.type")).isEqualTo("slf4j"); assertThat(hzCluster.hzInstance.getConfig().getProperty("hazelcast.socket.bind.any")).isEqualTo("false"); } } + + private class MemoryAppender extends AppenderBase { + private final List events = new ArrayList(); + + @Override + protected void append(E eventObject) { + events.add(eventObject); + } + } } diff --git a/server/sonar-main/src/test/java/org/sonar/application/cluster/HazelcastTestHelper.java b/server/sonar-main/src/test/java/org/sonar/application/cluster/HazelcastTestHelper.java index b95a7c6e787..24186ffd180 100644 --- a/server/sonar-main/src/test/java/org/sonar/application/cluster/HazelcastTestHelper.java +++ b/server/sonar-main/src/test/java/org/sonar/application/cluster/HazelcastTestHelper.java @@ -49,6 +49,10 @@ public class HazelcastTestHelper { return hazelcastInstance; } + static HazelcastInstance createHazelcastClient(AppStateClusterImpl appStateCluster) { + return createHazelcastClient(appStateCluster.getHazelcastCluster()); + } + static void closeAllHazelcastClients() { HAZELCAST_INSTANCES.stream().forEach( hz -> { @@ -61,15 +65,19 @@ public class HazelcastTestHelper { ); } - static HazelcastInstance createHazelcastClient(AppStateClusterImpl appStateCluster) { - return createHazelcastClient(appStateCluster.getHazelcastCluster()); + static TestAppSettings newApplicationSettings() { + TestAppSettings settings = new TestAppSettings(); + settings.set(ProcessProperties.CLUSTER_ENABLED, "true"); + settings.set(ProcessProperties.CLUSTER_NAME, "sonarqube"); + settings.set(ProcessProperties.CLUSTER_NODE_TYPE, "application"); + return settings; } - static TestAppSettings newClusterSettings() { + static TestAppSettings newSearchSettings() { TestAppSettings settings = new TestAppSettings(); settings.set(ProcessProperties.CLUSTER_ENABLED, "true"); settings.set(ProcessProperties.CLUSTER_NAME, "sonarqube"); - settings.set(ProcessProperties.CLUSTER_NODE_TYPE, "application"); + settings.set(ProcessProperties.CLUSTER_NODE_TYPE, "search"); return settings; } } -- 2.39.5