blob: ea8a0824fbcb16c7b30361bf0e6831fef0d8bb47 [file] [log] [blame]
/*
* 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.assertFalse;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
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.ClusterDistributionManager;
import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
import org.apache.geode.distributed.internal.membership.NetView;
import org.apache.geode.test.junit.categories.MembershipTest;
@Category({MembershipTest.class})
public class GMSQuorumCheckerJUnitTest {
private InternalDistributedMember[] mockMembers;
private JChannel channel;
private JGAddress address;
@Before
public void initMocks() {
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<>();
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, null);
qc.initialize();
boolean quorum = qc.checkForQuorum(500);
assertTrue(quorum);
assertSame(view.getMembers().size(), answerer.getPingCount());
assertTrue(qc.checkForQuorum(500));
assertSame(MembershipInformation.class, qc.getMembershipInfo().getClass());
assertSame(((MembershipInformation) qc.getMembershipInfo()).getChannel(), channel);
}
@Test
public void testQuorumCheckerMajorityRespond() throws Exception {
NetView view = prepareView();
Set<Integer> pongResponders = new HashSet<>();
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, null);
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<>();
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, null);
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, null);
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(ClusterDistributionManager.LOCATOR_DM_TYPE);
mockMembers[1].setVmKind(ClusterDistributionManager.LOCATOR_DM_TYPE);
Set<Integer> pongResponders = new HashSet<>();
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, null);
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(ClusterDistributionManager.LOCATOR_DM_TYPE);
mockMembers[1].setVmKind(ClusterDistributionManager.LOCATOR_DM_TYPE);
Set<Integer> pongResponders = new HashSet<>();
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, null);
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(ClusterDistributionManager.LOCATOR_DM_TYPE);
mockMembers[1].setVmKind(ClusterDistributionManager.LOCATOR_DM_TYPE);
Set<Integer> pongResponders = new HashSet<>();
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, null);
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(ClusterDistributionManager.LOCATOR_DM_TYPE);
mockMembers[1].setVmKind(ClusterDistributionManager.LOCATOR_DM_TYPE);
Set<Integer> pongResponders = new HashSet<>();
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, null);
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(ClusterDistributionManager.LOCATOR_DM_TYPE);
mockMembers[1].setVmKind(ClusterDistributionManager.LOCATOR_DM_TYPE);
Set<Integer> pongResponders = new HashSet<>();
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, null);
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(ClusterDistributionManager.LOCATOR_DM_TYPE);
mockMembers[1].setVmKind(ClusterDistributionManager.LOCATOR_DM_TYPE);
Set<Integer> pongResponders = new HashSet<>();
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, null);
qc.initialize();
boolean quorum = qc.checkForQuorum(500);
assertFalse(quorum);
assertSame(view.getMembers().size(), answerer.getPingCount());
}
private NetView prepareView() {
return prepareView(mockMembers.length);
}
private NetView prepareView(int numMembers) {
int viewId = 1;
List<InternalDistributedMember> mbrs = new LinkedList<>();
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;
}
}
}