/* * Licensed to the Apache Software Foundation (ASF) under one or more contributor license * agreements. See the NOTICE file distributed with this work for additional information regarding * copyright ownership. The ASF licenses this file to You 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 org.apache.geode.distributed.internal.membership.gms.messenger; import static org.junit.Assert.*; import static org.mockito.Matchers.any; import static org.mockito.Mockito.*; import java.io.IOException; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import org.apache.geode.test.junit.categories.IntegrationTest; import org.apache.geode.test.junit.categories.MembershipTest; import org.jgroups.Event; import org.jgroups.JChannel; import org.jgroups.Message; import org.jgroups.Receiver; import org.jgroups.stack.IpAddress; import org.jgroups.util.UUID; import org.junit.Before; import org.junit.Test; import org.junit.experimental.categories.Category; import org.mockito.Mockito; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.apache.geode.distributed.internal.DistributionManager; import org.apache.geode.distributed.internal.membership.InternalDistributedMember; import org.apache.geode.distributed.internal.membership.NetView; import org.apache.geode.test.junit.categories.UnitTest; @Category({IntegrationTest.class, MembershipTest.class}) public class GMSQuorumCheckerJUnitTest { private InternalDistributedMember[] mockMembers; private JChannel channel; private JGAddress address; @Before public void initMocks() throws Exception { mockMembers = new InternalDistributedMember[12]; for (int i = 0; i < mockMembers.length; i++) { mockMembers[i] = new InternalDistributedMember("localhost", 8888 + i); } channel = mock(JChannel.class); address = mock(JGAddress.class); when(channel.getAddress()).thenReturn(new UUID()); when(channel.down(any(Event.class))).thenReturn(mock(IpAddress.class)); Mockito.doCallRealMethod().when(channel).setReceiver(any(Receiver.class)); when(channel.getReceiver()).thenCallRealMethod(); Mockito.doReturn(address).when(channel).down(any(Event.class)); } @Test public void testQuorumCheckerAllRespond() throws Exception { NetView view = prepareView(); Set<Integer> pongResponders = new HashSet<Integer>(); for (int i = 0; i < mockMembers.length; i++) { pongResponders.add(mockMembers[i].getPort()); } PingMessageAnswer answerer = new PingMessageAnswer(channel, pongResponders); Mockito.doAnswer(answerer).when(channel).send(any(Message.class)); GMSQuorumChecker qc = new GMSQuorumChecker(view, 51, channel); qc.initialize(); boolean quorum = qc.checkForQuorum(500); assertTrue(quorum); assertSame(view.getMembers().size(), answerer.getPingCount()); assertTrue(qc.checkForQuorum(500)); assertSame(qc.getMembershipInfo(), channel); } @Test public void testQuorumCheckerMajorityRespond() throws Exception { NetView view = prepareView(); Set<Integer> pongResponders = new HashSet<Integer>(); for (int i = 0; i < mockMembers.length - 1; i++) { pongResponders.add(mockMembers[i].getPort()); } PingMessageAnswer answerer = new PingMessageAnswer(channel, pongResponders); Mockito.doAnswer(answerer).when(channel).send(any(Message.class)); GMSQuorumChecker qc = new GMSQuorumChecker(view, 51, channel); qc.initialize(); boolean quorum = qc.checkForQuorum(500); assertTrue(quorum); assertSame(view.getMembers().size(), answerer.getPingCount()); } @Test public void testQuorumCheckerNotEnoughWeightForQuorum() throws Exception { NetView view = prepareView(); Set<Integer> pongResponders = new HashSet<Integer>(); pongResponders.add(mockMembers[0].getPort()); PingMessageAnswer answerer = new PingMessageAnswer(channel, pongResponders); Mockito.doAnswer(answerer).when(channel).send(any(Message.class)); GMSQuorumChecker qc = new GMSQuorumChecker(view, 51, channel); qc.initialize(); boolean quorum = qc.checkForQuorum(500); assertFalse(quorum); assertSame(view.getMembers().size(), answerer.getPingCount()); } @Test public void testQuorumCheckerNoQuorumNoResponders() throws Exception { NetView view = prepareView(); Set<Integer> pongResponders = new HashSet<Integer>(); PingMessageAnswer answerer = new PingMessageAnswer(channel, pongResponders); Mockito.doAnswer(answerer).when(channel).send(any(Message.class)); GMSQuorumChecker qc = new GMSQuorumChecker(view, 51, channel); qc.initialize(); boolean quorum = qc.checkForQuorum(500); assertFalse(quorum); assertSame(view.getMembers().size(), answerer.getPingCount()); } @Test public void testQuorumChecker10Servers2Locators4ServersLost() throws Exception { NetView view = prepareView(); mockMembers[0].setVmKind(DistributionManager.LOCATOR_DM_TYPE); mockMembers[1].setVmKind(DistributionManager.LOCATOR_DM_TYPE); Set<Integer> pongResponders = new HashSet<Integer>(); for (int i = 0; i < mockMembers.length; i++) { pongResponders.add(mockMembers[i].getPort()); } // remove 4 servers pongResponders.remove(mockMembers[8].getPort()); pongResponders.remove(mockMembers[9].getPort()); pongResponders.remove(mockMembers[10].getPort()); pongResponders.remove(mockMembers[11].getPort()); PingMessageAnswer answerer = new PingMessageAnswer(channel, pongResponders); Mockito.doAnswer(answerer).when(channel).send(any(Message.class)); GMSQuorumChecker qc = new GMSQuorumChecker(view, 51, channel); qc.initialize(); boolean quorum = qc.checkForQuorum(500); assertTrue(quorum); assertSame(view.getMembers().size(), answerer.getPingCount()); } @Test public void testQuorumChecker10Servers2Locators4ServersAnd1LocatorLost() throws Exception { NetView view = prepareView(); mockMembers[0].setVmKind(DistributionManager.LOCATOR_DM_TYPE); mockMembers[1].setVmKind(DistributionManager.LOCATOR_DM_TYPE); Set<Integer> pongResponders = new HashSet<Integer>(); for (int i = 0; i < mockMembers.length; i++) { pongResponders.add(mockMembers[i].getPort()); } // remove 4 servers pongResponders.remove(mockMembers[8].getPort()); pongResponders.remove(mockMembers[9].getPort()); pongResponders.remove(mockMembers[10].getPort()); pongResponders.remove(mockMembers[11].getPort()); // remove 1 locator pongResponders.remove(mockMembers[1].getPort()); PingMessageAnswer answerer = new PingMessageAnswer(channel, pongResponders); Mockito.doAnswer(answerer).when(channel).send(any(Message.class)); GMSQuorumChecker qc = new GMSQuorumChecker(view, 51, channel); qc.initialize(); boolean quorum = qc.checkForQuorum(500); assertTrue(quorum); assertSame(view.getMembers().size(), answerer.getPingCount()); } @Test public void testQuorumChecker10Servers2Locators5ServersAnd2LocatorsButNotLeadMemberLost() throws Exception { NetView view = prepareView(); mockMembers[0].setVmKind(DistributionManager.LOCATOR_DM_TYPE); mockMembers[1].setVmKind(DistributionManager.LOCATOR_DM_TYPE); Set<Integer> pongResponders = new HashSet<Integer>(); for (int i = 0; i < mockMembers.length; i++) { pongResponders.add(mockMembers[i].getPort()); } // remove 5 servers pongResponders.remove(mockMembers[7].getPort()); pongResponders.remove(mockMembers[8].getPort()); pongResponders.remove(mockMembers[9].getPort()); pongResponders.remove(mockMembers[10].getPort()); pongResponders.remove(mockMembers[11].getPort()); // remove locators pongResponders.remove(mockMembers[0].getPort()); pongResponders.remove(mockMembers[1].getPort()); PingMessageAnswer answerer = new PingMessageAnswer(channel, pongResponders); Mockito.doAnswer(answerer).when(channel).send(any(Message.class)); GMSQuorumChecker qc = new GMSQuorumChecker(view, 51, channel); qc.initialize(); boolean quorum = qc.checkForQuorum(500); assertFalse(quorum); assertSame(view.getMembers().size(), answerer.getPingCount()); } @Test public void testQuorumChecker10Servers2Locators5ServerAnd1LocatorWithLeadMemberLost() throws Exception { NetView view = prepareView(); mockMembers[0].setVmKind(DistributionManager.LOCATOR_DM_TYPE); mockMembers[1].setVmKind(DistributionManager.LOCATOR_DM_TYPE); Set<Integer> pongResponders = new HashSet<Integer>(); for (int i = 0; i < mockMembers.length; i++) { pongResponders.add(mockMembers[i].getPort()); } // remove 5 servers pongResponders.remove(mockMembers[2].getPort()); // lead member pongResponders.remove(mockMembers[8].getPort()); pongResponders.remove(mockMembers[9].getPort()); pongResponders.remove(mockMembers[10].getPort()); pongResponders.remove(mockMembers[11].getPort()); // remove locator pongResponders.remove(mockMembers[0].getPort()); PingMessageAnswer answerer = new PingMessageAnswer(channel, pongResponders); Mockito.doAnswer(answerer).when(channel).send(any(Message.class)); GMSQuorumChecker qc = new GMSQuorumChecker(view, 51, channel); qc.initialize(); boolean quorum = qc.checkForQuorum(500); assertFalse(quorum); assertSame(view.getMembers().size(), answerer.getPingCount()); } @Test public void testQuorumChecker2Servers2LocatorsLeadMemberLost() throws Exception { int numMembers = 4; NetView view = prepareView(numMembers); mockMembers[0].setVmKind(DistributionManager.LOCATOR_DM_TYPE); mockMembers[1].setVmKind(DistributionManager.LOCATOR_DM_TYPE); Set<Integer> pongResponders = new HashSet<Integer>(); for (int i = 0; i < numMembers; i++) { pongResponders.add(mockMembers[i].getPort()); } // remove lead member pongResponders.remove(mockMembers[2].getPort()); // lead member PingMessageAnswer answerer = new PingMessageAnswer(channel, pongResponders); Mockito.doAnswer(answerer).when(channel).send(any(Message.class)); GMSQuorumChecker qc = new GMSQuorumChecker(view, 51, channel); qc.initialize(); boolean quorum = qc.checkForQuorum(500); assertTrue(quorum); assertSame(view.getMembers().size(), answerer.getPingCount()); } @Test public void testQuorumChecker2Servers2LocatorsLeadMemberAnd1LocatorLost() throws Exception { int numMembers = 4; NetView view = prepareView(numMembers); mockMembers[0].setVmKind(DistributionManager.LOCATOR_DM_TYPE); mockMembers[1].setVmKind(DistributionManager.LOCATOR_DM_TYPE); Set<Integer> pongResponders = new HashSet<Integer>(); for (int i = 0; i < numMembers; i++) { pongResponders.add(mockMembers[i].getPort()); } // remove members pongResponders.remove(mockMembers[2].getPort()); // lead member pongResponders.remove(mockMembers[0].getPort()); // locator PingMessageAnswer answerer = new PingMessageAnswer(channel, pongResponders); Mockito.doAnswer(answerer).when(channel).send(any(Message.class)); GMSQuorumChecker qc = new GMSQuorumChecker(view, 51, channel); qc.initialize(); boolean quorum = qc.checkForQuorum(500); assertFalse(quorum); assertSame(view.getMembers().size(), answerer.getPingCount()); } private NetView prepareView() throws IOException { return prepareView(mockMembers.length); } private NetView prepareView(int numMembers) throws IOException { int viewId = 1; List<InternalDistributedMember> mbrs = new LinkedList<InternalDistributedMember>(); for (int i = 0; i < numMembers; i++) { mbrs.add(mockMembers[i]); } // prepare the view NetView netView = new NetView(mockMembers[0], viewId, mbrs); return netView; } private static class PingMessageAnswer implements Answer { private int pingCount = 0; private JChannel channel; private GMSPingPonger pingPonger = new GMSPingPonger(); private Set<Integer> simulatedPongRespondersByPort; public PingMessageAnswer(JChannel channel, Set<Integer> simulatedPongRespondersByPort) { this.channel = channel; this.simulatedPongRespondersByPort = simulatedPongRespondersByPort; } @Override public Object answer(InvocationOnMock invocation) throws Throwable { Object[] args = invocation.getArguments(); for (int i = 0; i < args.length; i++) { if (args[i] instanceof Message) { Message msg = (Message) args[i]; Object content = null; content = msg.getBuffer(); if (content instanceof byte[]) { if (pingPonger.isPingMessage((byte[]) content)) { pingCount++; if (simulatedPongRespondersByPort.contains(((JGAddress) msg.getDest()).getPort())) { channel.getReceiver() .receive(pingPonger.createPongMessage(msg.getDest(), msg.getSrc())); } } } } } return null; } public int getPingCount() { return pingCount; } } }