/* * Copyright (c) 2008-2017, Hazelcast, Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.hazelcast.client; import com.hazelcast.client.config.ClientConfig; import com.hazelcast.client.test.TestHazelcastFactory; import com.hazelcast.config.ListenerConfig; import com.hazelcast.core.HazelcastInstance; import com.hazelcast.core.InitialMembershipEvent; import com.hazelcast.core.InitialMembershipListener; import com.hazelcast.core.Member; import com.hazelcast.core.MemberAttributeEvent; import com.hazelcast.core.MembershipEvent; import com.hazelcast.core.MembershipListener; import com.hazelcast.test.AssertTask; import com.hazelcast.test.HazelcastParallelClassRunner; import com.hazelcast.test.HazelcastTestSupport; import com.hazelcast.test.annotation.ParallelTest; import com.hazelcast.test.annotation.QuickTest; import org.junit.After; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; import java.util.EventObject; import java.util.HashSet; import java.util.Set; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.TimeUnit; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.mockito.Mockito.mock; @RunWith(HazelcastParallelClassRunner.class) @Category({QuickTest.class, ParallelTest.class}) public class MembershipListenerTest extends HazelcastTestSupport { private final TestHazelcastFactory hazelcastFactory = new TestHazelcastFactory(); @After public void tearDown() { hazelcastFactory.terminateAll(); } private class MemberShipEventLogger implements MembershipListener { public LinkedBlockingDeque<EventObject> events = new LinkedBlockingDeque<EventObject>(); public void memberAdded(MembershipEvent event) { events.addLast(event); } public void memberRemoved(MembershipEvent event) { events.addLast(event); } public void memberAttributeChanged(MemberAttributeEvent memberAttributeEvent) { } } private class InitialMemberShipEventLogger implements InitialMembershipListener { public LinkedBlockingDeque<EventObject> events = new LinkedBlockingDeque<EventObject>(); public void memberAdded(MembershipEvent event) { events.addLast(event); } public void memberRemoved(MembershipEvent event) { events.addLast(event); } public void memberAttributeChanged(MemberAttributeEvent memberAttributeEvent) { events.addLast(memberAttributeEvent); } @Override public void init(InitialMembershipEvent event) { events.addLast(event); } } @Test public void whenMemberAdded_thenMemberAddedEvent() throws Exception { final HazelcastInstance server1 = hazelcastFactory.newHazelcastInstance(); final MemberShipEventLogger listener = new MemberShipEventLogger(); HazelcastInstance client = hazelcastFactory.newHazelcastClient(); client.getCluster().addMembershipListener(listener); //start a second server and verify that the listener receives it. final HazelcastInstance server2 = hazelcastFactory.newHazelcastInstance(); //verify that the listener receives member added event. assertTrueEventually(new AssertTask() { @Override public void run() { assertNotEquals("Expecting one or more events", 0, listener.events.size()); MembershipEvent event = (MembershipEvent) listener.events.getLast(); assertEquals("Last event should be member added", MembershipEvent.MEMBER_ADDED, event.getEventType()); assertEquals(server2.getCluster().getLocalMember(), event.getMember()); assertEquals(getMembers(server1, server2), event.getMembers()); } }); } @Test public void givenMixOfListenerExists_whenConnect_thenCallInitialMembershipListener() throws Exception { hazelcastFactory.newHazelcastInstance(); final ClientConfig config = new ClientConfig(); // first add bunch of *regular* MembershipListener. They do not implement InitialMembershipListener config.addListenerConfig(new ListenerConfig().setImplementation(new MemberShipEventLogger())); config.addListenerConfig(new ListenerConfig().setImplementation(new MemberShipEventLogger())); config.addListenerConfig(new ListenerConfig().setImplementation(new MemberShipEventLogger())); // now add an InitialMembershipListener // if there is an exception thrown during event delivery to regular listeners // then no event will likely be delivered to InitialMemberShipEventLogger final InitialMemberShipEventLogger initialListener = new InitialMemberShipEventLogger(); config.addListenerConfig(new ListenerConfig().setImplementation(initialListener)); //connect to a grid hazelcastFactory.newHazelcastClient(config); assertTrueEventually(new AssertTask() { @Override public void run() throws Exception { assertEquals("Expecting one event", 1, initialListener.events.size()); InitialMembershipEvent event = (InitialMembershipEvent) initialListener.events.getLast(); assertEquals(1, event.getMembers().size()); } }); } @Test public void whenMemberRemoved_thenMemberRemovedEvent() throws Exception { final HazelcastInstance server1 = hazelcastFactory.newHazelcastInstance(); final MemberShipEventLogger listener = new MemberShipEventLogger(); HazelcastInstance client = hazelcastFactory.newHazelcastClient(); //start a second server and verify that hazelcastFactory listener receives it. final HazelcastInstance server2 = hazelcastFactory.newHazelcastInstance(); client.getCluster().addMembershipListener(listener); final Member server2Member = server2.getCluster().getLocalMember(); server2.shutdown(); //verify that the correct member removed event was received. assertTrueEventually(new AssertTask() { @Override public void run() { assertNotEquals("Expecting one or more events", 0, listener.events.size()); MembershipEvent event = (MembershipEvent) listener.events.getLast(); assertEquals("Last event should be member removed", MembershipEvent.MEMBER_REMOVED, event.getEventType()); assertEquals(server2Member, event.getMember()); assertEquals(getMembers(server1), event.getMembers()); } }); } @Test public void removedPhantomListener_thenFalse() throws Exception { hazelcastFactory.newHazelcastInstance(); HazelcastInstance client = hazelcastFactory.newHazelcastClient(); assertFalse(client.getCluster().removeMembershipListener(randomString())); } @Test(expected = NullPointerException.class) public void removedNullListener_thenException() throws Exception { hazelcastFactory.newHazelcastInstance(); HazelcastInstance client = hazelcastFactory.newHazelcastClient(); assertFalse(client.getCluster().removeMembershipListener(null)); } @Test(expected = java.lang.NullPointerException.class) public void addNullListener_thenException() throws Exception { hazelcastFactory.newHazelcastInstance(); HazelcastInstance client = hazelcastFactory.newHazelcastClient(); client.getCluster().addMembershipListener(null); } private Set<Member> getMembers(HazelcastInstance... instances) { Set<Member> result = new HashSet<Member>(); for (HazelcastInstance hz : instances) { result.add(hz.getCluster().getLocalMember()); } return result; } /** * related to issue #1181 */ @Test public void testAddInitialMembership_whenListenerAddedViaClientConfig() throws InterruptedException { hazelcastFactory.newHazelcastInstance(); ClientConfig clientConfig = new ClientConfig(); clientConfig.addListenerConfig(new ListenerConfig().setImplementation(mock(InitialMembershipListener.class))); hazelcastFactory.newHazelcastClient(clientConfig); } @Test public void initialMemberEvents_whenAddedViaConfig() throws InterruptedException { hazelcastFactory.newHazelcastInstance(); hazelcastFactory.newHazelcastInstance(); ClientConfig clientConfig = new ClientConfig(); final InitialMemberShipEventLogger listener = new InitialMemberShipEventLogger(); clientConfig.addListenerConfig(new ListenerConfig().setImplementation(listener)); hazelcastFactory.newHazelcastClient(clientConfig); EventObject eventObject = listener.events.poll(ASSERT_TRUE_EVENTUALLY_TIMEOUT, TimeUnit.SECONDS); assertInstanceOf(InitialMembershipEvent.class, eventObject); InitialMembershipEvent event = (InitialMembershipEvent) eventObject; assertEquals(2, event.getMembers().size()); assertEquals(0, listener.events.size()); } @Test public void initialMemberEvents_whenAddedAfterClientStarted() throws InterruptedException { hazelcastFactory.newHazelcastInstance(); hazelcastFactory.newHazelcastInstance(); ClientConfig clientConfig = new ClientConfig(); HazelcastInstance client = hazelcastFactory.newHazelcastClient(clientConfig); final InitialMemberShipEventLogger listener = new InitialMemberShipEventLogger(); client.getCluster().addMembershipListener(listener); EventObject eventObject = listener.events.poll(ASSERT_TRUE_EVENTUALLY_TIMEOUT, TimeUnit.SECONDS); assertInstanceOf(InitialMembershipEvent.class, eventObject); InitialMembershipEvent event = (InitialMembershipEvent) eventObject; assertEquals(2, event.getMembers().size()); assertEquals(0, listener.events.size()); } @Test public void initialMemberEvents_whenClusterRestarted() throws InterruptedException { HazelcastInstance instance1 = hazelcastFactory.newHazelcastInstance(); HazelcastInstance instance2 = hazelcastFactory.newHazelcastInstance(); ClientConfig clientConfig = new ClientConfig(); clientConfig.getNetworkConfig().setConnectionAttemptLimit(Integer.MAX_VALUE); final InitialMemberShipEventLogger listener = new InitialMemberShipEventLogger(); clientConfig.addListenerConfig(new ListenerConfig().setImplementation(listener)); hazelcastFactory.newHazelcastClient(clientConfig); EventObject eventObject = listener.events.poll(ASSERT_TRUE_EVENTUALLY_TIMEOUT, TimeUnit.SECONDS); assertInstanceOf(InitialMembershipEvent.class, eventObject); instance1.getLifecycleService().terminate(); eventObject = listener.events.poll(ASSERT_TRUE_EVENTUALLY_TIMEOUT, TimeUnit.SECONDS); assertInstanceOf(MembershipEvent.class, eventObject); assertEquals(MembershipEvent.MEMBER_REMOVED, ((MembershipEvent) eventObject).getEventType()); instance2.getLifecycleService().terminate(); hazelcastFactory.newHazelcastInstance(); eventObject = listener.events.poll(ASSERT_TRUE_EVENTUALLY_TIMEOUT, TimeUnit.SECONDS); assertInstanceOf(MembershipEvent.class, eventObject); assertEquals(MembershipEvent.MEMBER_REMOVED, ((MembershipEvent) eventObject).getEventType()); eventObject = listener.events.poll(ASSERT_TRUE_EVENTUALLY_TIMEOUT, TimeUnit.SECONDS); assertInstanceOf(MembershipEvent.class, eventObject); assertEquals(MembershipEvent.MEMBER_ADDED, ((MembershipEvent) eventObject).getEventType()); } }