You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

AppNodesClusterHostsConsistencyTest.java 8.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2021 SonarSource SA
  4. * mailto:info AT sonarsource DOT com
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program; if not, write to the Free Software Foundation,
  18. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. package org.sonar.application.cluster;
  21. import com.google.common.collect.ImmutableMap;
  22. import com.hazelcast.cluster.Address;
  23. import com.hazelcast.cluster.Cluster;
  24. import com.hazelcast.cluster.Member;
  25. import com.hazelcast.cluster.MemberSelector;
  26. import com.hazelcast.cp.IAtomicReference;
  27. import java.net.InetAddress;
  28. import java.net.UnknownHostException;
  29. import java.util.Arrays;
  30. import java.util.Collections;
  31. import java.util.LinkedHashMap;
  32. import java.util.List;
  33. import java.util.Map;
  34. import java.util.Set;
  35. import java.util.UUID;
  36. import java.util.concurrent.locks.Lock;
  37. import java.util.function.Consumer;
  38. import org.junit.After;
  39. import org.junit.Before;
  40. import org.junit.Rule;
  41. import org.junit.Test;
  42. import org.junit.rules.ExpectedException;
  43. import org.sonar.application.config.TestAppSettings;
  44. import org.sonar.process.cluster.hz.DistributedAnswer;
  45. import org.sonar.process.cluster.hz.DistributedCall;
  46. import org.sonar.process.cluster.hz.DistributedCallback;
  47. import org.sonar.process.cluster.hz.HazelcastMember;
  48. import static org.mockito.Mockito.mock;
  49. import static org.mockito.Mockito.verify;
  50. import static org.mockito.Mockito.verifyNoMoreInteractions;
  51. import static org.mockito.Mockito.when;
  52. import static org.sonar.process.ProcessProperties.Property.CLUSTER_HZ_HOSTS;
  53. public class AppNodesClusterHostsConsistencyTest {
  54. @Rule
  55. public ExpectedException expectedException = ExpectedException.none();
  56. @SuppressWarnings("unchecked")
  57. private final Consumer<String> logger = mock(Consumer.class);
  58. @Before
  59. @After
  60. public void setUp() {
  61. AppNodesClusterHostsConsistency.clearInstance();
  62. }
  63. @Test
  64. public void log_warning_if_configured_hosts_are_not_consistent() throws UnknownHostException {
  65. Map<Member, List<String>> hostsPerMember = new LinkedHashMap<>();
  66. Member m1 = newLocalHostMember(1, true);
  67. Member m2 = newLocalHostMember(2);
  68. Member m3 = newLocalHostMember(3);
  69. hostsPerMember.put(m2, Arrays.asList("1.1.1.1:1000", "1.1.1.1:2000"));
  70. hostsPerMember.put(m3, Arrays.asList("1.1.1.1:1000", "1.1.1.2:1000"));
  71. TestAppSettings settings = new TestAppSettings(ImmutableMap.of(CLUSTER_HZ_HOSTS.getKey(), "1.1.1.1:1000,1.1.1.1:2000,1.1.1.2:1000"));
  72. TestHazelcastMember member = new TestHazelcastMember(hostsPerMember, m1);
  73. AppNodesClusterHostsConsistency underTest = AppNodesClusterHostsConsistency.setInstance(member, settings, logger);
  74. underTest.check();
  75. verify(logger).accept("The configuration of the current node doesn't match the list of hosts configured in the application nodes that have already joined the cluster:\n" +
  76. m1.getAddress().getHost() + ":" + m1.getAddress().getPort() + " : [1.1.1.1:1000, 1.1.1.1:2000, 1.1.1.2:1000] (current)\n" +
  77. m2.getAddress().getHost() + ":" + m2.getAddress().getPort() + " : [1.1.1.1:1000, 1.1.1.1:2000]\n" +
  78. m3.getAddress().getHost() + ":" + m3.getAddress().getPort() + " : [1.1.1.1:1000, 1.1.1.2:1000]\n" +
  79. "Make sure the configuration is consistent among all application nodes before you restart any node");
  80. verifyNoMoreInteractions(logger);
  81. }
  82. @Test
  83. public void dont_log_if_configured_hosts_are_consistent() throws UnknownHostException {
  84. Map<Member, List<String>> hostsPerMember = new LinkedHashMap<>();
  85. Member m1 = newLocalHostMember(1, true);
  86. Member m2 = newLocalHostMember(2);
  87. Member m3 = newLocalHostMember(3);
  88. hostsPerMember.put(m2, Arrays.asList("1.1.1.1:1000", "1.1.1.1:2000", "1.1.1.2:1000"));
  89. hostsPerMember.put(m3, Arrays.asList("1.1.1.1:1000", "1.1.1.1:2000", "1.1.1.2:1000"));
  90. TestAppSettings settings = new TestAppSettings(ImmutableMap.of(CLUSTER_HZ_HOSTS.getKey(), "1.1.1.1:1000,1.1.1.1:2000,1.1.1.2:1000"));
  91. TestHazelcastMember member = new TestHazelcastMember(hostsPerMember, m1);
  92. AppNodesClusterHostsConsistency underTest = AppNodesClusterHostsConsistency.setInstance(member, settings, logger);
  93. underTest.check();
  94. verifyNoMoreInteractions(logger);
  95. }
  96. @Test
  97. public void setInstance_fails_with_ISE_when_called_twice_with_same_arguments() throws UnknownHostException {
  98. TestHazelcastMember member = new TestHazelcastMember(Collections.emptyMap(), newLocalHostMember(1, true));
  99. TestAppSettings settings = new TestAppSettings();
  100. AppNodesClusterHostsConsistency.setInstance(member, settings);
  101. expectedException.expect(IllegalStateException.class);
  102. expectedException.expectMessage("Instance is already set");
  103. AppNodesClusterHostsConsistency.setInstance(member, settings);
  104. }
  105. @Test
  106. public void setInstance_fails_with_ISE_when_called_twice_with_other_arguments() throws UnknownHostException {
  107. TestHazelcastMember member1 = new TestHazelcastMember(Collections.emptyMap(), newLocalHostMember(1, true));
  108. TestHazelcastMember member2 = new TestHazelcastMember(Collections.emptyMap(), newLocalHostMember(2, true));
  109. AppNodesClusterHostsConsistency.setInstance(member1, new TestAppSettings());
  110. expectedException.expect(IllegalStateException.class);
  111. expectedException.expectMessage("Instance is already set");
  112. AppNodesClusterHostsConsistency.setInstance(member2, new TestAppSettings());
  113. }
  114. private Member newLocalHostMember(int port) throws UnknownHostException {
  115. return newLocalHostMember(port, false);
  116. }
  117. private Member newLocalHostMember(int port, boolean localMember) throws UnknownHostException {
  118. Member member = mock(Member.class);
  119. when(member.localMember()).thenReturn(localMember);
  120. Address address1 = new Address(InetAddress.getLocalHost(), port);
  121. when(member.getAddress()).thenReturn(address1);
  122. return member;
  123. }
  124. private static class TestHazelcastMember implements HazelcastMember {
  125. private final Map<Member, List<String>> hostsPerMember;
  126. private final Cluster cluster = mock(Cluster.class);
  127. private TestHazelcastMember(Map<Member, List<String>> hostsPerMember, Member localMember) {
  128. this.hostsPerMember = hostsPerMember;
  129. when(cluster.getLocalMember()).thenReturn(localMember);
  130. }
  131. @Override
  132. public <E> IAtomicReference<E> getAtomicReference(String name) {
  133. throw new IllegalStateException("not expected to be called");
  134. }
  135. @Override
  136. public <K, V> Map<K, V> getReplicatedMap(String name) {
  137. throw new IllegalStateException("not expected to be called");
  138. }
  139. @Override
  140. public UUID getUuid() {
  141. throw new IllegalStateException("not expected to be called");
  142. }
  143. @Override
  144. public Set<UUID> getMemberUuids() {
  145. throw new IllegalStateException("not expected to be called");
  146. }
  147. @Override
  148. public Lock getLock(String name) {
  149. throw new IllegalStateException("not expected to be called");
  150. }
  151. @Override
  152. public long getClusterTime() {
  153. throw new IllegalStateException("not expected to be called");
  154. }
  155. @Override
  156. public Cluster getCluster() {
  157. return cluster;
  158. }
  159. @Override
  160. public <T> DistributedAnswer<T> call(DistributedCall<T> callable, MemberSelector memberSelector, long timeoutMs) {
  161. throw new IllegalStateException("not expected to be called");
  162. }
  163. @Override
  164. public <T> void callAsync(DistributedCall<T> callable, MemberSelector memberSelector, DistributedCallback<T> callback) {
  165. callback.onComplete((Map<Member, T>) hostsPerMember);
  166. }
  167. @Override
  168. public void close() {
  169. }
  170. }
  171. }