/**
* VMware Continuent Tungsten Replicator
* Copyright (C) 2015 VMware, 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.
*
* Initial developer(s): Robert Hodges
* Contributor(s):
*/
package com.continuent.tungsten.common.cluster.resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import org.junit.Assert;
import org.junit.Test;
import com.continuent.tungsten.common.exception.ClusterMembershipValidationException;
import com.continuent.tungsten.common.utils.CLUtils;
/**
* Implements a unit test of IndexedLRUCache features.
*
* @author <a href="mailto:robert.hodges@continuent.com">Robert Hodges</a>
* @version 1.0
*/
public class ClusterMembershipDigestTest
{
/**
* Verify that we can create a membership digest instance that returns a
* correctly computed quorum set and witnesses.
*/
@Test
public void testInstantiationNormal() throws Exception
{
List<String> configuredDBMembers = Arrays.asList("a", "b", "c");
List<String> configuredActiveWitnessMembers = null;
List<String> viewDBMembers = Arrays.asList("a", "b", "c");
List<String> viewActiveWitnesses = null;
List<String> witnesses = null;
ClusterMembershipDigest digest = new ClusterMembershipDigest("myname",
configuredDBMembers, configuredActiveWitnessMembers,
viewDBMembers, viewActiveWitnesses, witnesses);
// Test that values are correctly returned.
List<String> quorumSet = Arrays.asList("a", "b", "c");
Assert.assertEquals("myname", digest.getName());
Assert.assertEquals("Configured member size", 3, digest
.getConfiguredDBSetMembers().size());
Assert.assertEquals("Configured view size", 3, digest
.getViewDBSetMembers().size());
Assert.assertEquals("Witness set size", 0, digest
.getWitnessSetMembers().size());
assertEqualSet("Quorum set", quorumSet,
digest.getPotentialQuorumMembersSetNames());
}
/**
* Verify that we can create a membership digest instance that returns a
* correctly computed quorum set and witnesses.
*/
@Test
public void testInstantiationActiveWitnesses() throws Exception
{
List<String> configuredDBMembers = Arrays.asList("a", "b");
List<String> configuredActiveWitnessMembers = Arrays.asList("c");
List<String> viewDBMembers = Arrays.asList("a", "b");
List<String> viewActiveWitnesses = Arrays.asList("c");
;
List<String> witnesses = null;
ClusterMembershipDigest digest = new ClusterMembershipDigest("myname",
configuredDBMembers, configuredActiveWitnessMembers,
viewDBMembers, viewActiveWitnesses, witnesses);
// Test that values are correctly returned.
List<String> quorumSet = Arrays.asList("a", "b", "c");
Assert.assertEquals("myname", digest.getName());
Assert.assertEquals("Configured member size", 2, digest
.getConfiguredDBSetMembers().size());
Assert.assertEquals("Configured DB view size", 2, digest
.getViewDBSetMembers().size());
Assert.assertEquals("Configured Active Witness view size", 1, digest
.getViewActiveWitnessSetMembers().size());
Assert.assertEquals("Witness set size", 0, digest
.getWitnessSetMembers().size());
assertEqualSet("Quorum set", quorumSet,
digest.getPotentialQuorumMembersSetNames());
}
/**
* Verify that we can create a membership digest instance that returns a
* correctly computed quorum set and witnesses.
*/
@Test
public void testInstantiationPassiveWitnesses() throws Exception
{
List<String> configuredDBMembers = Arrays.asList("a", "b", "c");
List<String> configuredActiveWitnessMembers = null;
List<String> viewDBMembers = Arrays.asList("a", "b", "c");
List<String> viewActiveWitnesses = null;
List<String> witnesses = Arrays.asList("d");
ClusterMembershipDigest digest = new ClusterMembershipDigest("myname",
configuredDBMembers, configuredActiveWitnessMembers,
viewDBMembers, viewActiveWitnesses, witnesses);
// Test that values are correctly returned.
List<String> quorumSet = Arrays.asList("a", "b", "c", "d");
Assert.assertEquals("myname", digest.getName());
Assert.assertEquals("Configured member size", 3, digest
.getConfiguredDBSetMembers().size());
Assert.assertEquals("Configured view size", 3, digest
.getViewDBSetMembers().size());
Assert.assertEquals("Witness set size", 1, digest
.getWitnessSetMembers().size());
assertEqualSet("Quorum set", quorumSet,
digest.getPotentialQuorumMembersSetNames());
}
/**
* Verify that the digest correctly indicates membership is valid if all
* members are validated and otherwise returns false.
*/
@Test
public void testMembershipValidity() throws Exception
{
List<String> configured = Arrays.asList("a", "b");
List<String> view = Arrays.asList("a", "b", "c", "d");
ClusterMembershipDigest digest = new ClusterMembershipDigest("a",
configured, null, view, null, null);
// Assert that the membership is invalid as long as not all members are
// validated.
for (String member : view)
{
Assert.assertFalse("Before member validated: " + member,
digest.isValidMembership(false));
digest.setValidated(member, true);
}
// Now it should be valid.
Assert.assertTrue("All members are valid",
digest.isValidMembership(false));
}
/**
* Verify that a quorum set of one validated node is a primary partition.
*/
@Test
public void testMajorityOfOne() throws Exception
{
List<String> configuredDBMembers = Arrays.asList("a");
List<String> configuredActiveWitnessMembers = null;
List<String> viewDBMembers = Arrays.asList("a");
List<String> viewActiveWitnesses = null;
List<String> witnesses = null;
ClusterMembershipDigest digest = new ClusterMembershipDigest("a",
configuredDBMembers, configuredActiveWitnessMembers,
viewDBMembers, viewActiveWitnesses, witnesses);
// If we have not validated the node, we don't have a majority.
Assert.assertFalse("Unvalidated member cannot create majority",
digest.isInPrimaryPartition(true));
// Once the node is validated, we have a majority.
digest.setValidated("a", true);
Assert.assertTrue("Single validated member constitutes a majority",
digest.isInPrimaryPartition(true));
}
/**
* Verify that a quorum set is a primary partition if there is a simple
* majority of nodes where all nodes in the view are validated.
*/
@Test
public void testSimpleMajority() throws Exception
{
List<String> configuredDBMembers = Arrays.asList("a", "b", "c");
List<String> configuredActiveWitnessMembers = null;
List<String> viewDBMembers = Arrays.asList("a", "b");
List<String> viewActiveWitnesses = null;
List<String> witnesses = null;
ClusterMembershipDigest digest = new ClusterMembershipDigest("a",
configuredDBMembers, configuredActiveWitnessMembers,
viewDBMembers, viewActiveWitnesses, witnesses);
// If we have not validated a majority, we are not in a primary
// partition.
Assert.assertFalse("0 of 3 validated is not majority",
digest.isInPrimaryPartition(true));
// I need to be sure that 'myself' is validated. But that's not enough
// for a majority.
CLUtils.println("About to set validated for a");
digest.setValidated("a", true);
Assert.assertFalse("1 of 3 validated is not majority",
digest.isInPrimaryPartition(true));
// 2 of 3 is a majority but only if the view is valid.
digest.setValidated("b", true);
Assert.assertTrue("2 of 3 validated is a majority",
digest.isInPrimaryPartition(true));
/*
* Test for a majority of three out of four configured members.
*/
configuredDBMembers = Arrays.asList("a", "b", "c", "d");
viewDBMembers = Arrays.asList("a", "b", "c");
digest = new ClusterMembershipDigest("a", configuredDBMembers,
configuredActiveWitnessMembers, viewDBMembers,
viewActiveWitnesses, witnesses);
// I need to be sure that 'myself' is validated. But that's not enough
// for a majority.
digest.setValidated("a", true);
Assert.assertFalse("1 of 4 validated is not majority",
digest.isInPrimaryPartition(true));
// 2 of 4 is not a majority.
digest.setValidated("b", true);
Assert.assertFalse("2 of 4 validated is not a majority",
digest.isInPrimaryPartition(true));
// 3 of 4 is a majority.
digest.setValidated("c", true);
Assert.assertTrue("3 of 4 validated is a majority",
digest.isInPrimaryPartition(true));
}
/**
* Verify that a quorum set with an even number of validate nodes plus a
* reachable witness is a primary partition.
*/
@Test
public void testWitness() throws Exception
{
List<String> configuredDBMembers = Arrays.asList("a", "b", "c");
List<String> configuredActiveWitnessMembers = null;
List<String> viewDBMembers = Arrays.asList("a");
List<String> viewActiveWitnesses = null;
List<String> witnesses = Arrays.asList("d");
ClusterMembershipDigest digest = new ClusterMembershipDigest("a",
configuredDBMembers, configuredActiveWitnessMembers,
viewDBMembers, viewActiveWitnesses, witnesses);
// Always validate ourself, but that is not enough for a quorum...
digest.setValidated("a", true);
Assert.assertFalse(
"1 of 2 validated without witnesses is not majority",
digest.isInPrimaryPartition(true));
digest.setReachable("a", true);
Assert.assertFalse(
"1 of 2 validated without all witnesses reachable is not majority",
digest.isInPrimaryPartition(true));
// 1 of 2 with all reachable witnesses is a majority.
digest.setReachable("d", true);
Assert.assertTrue(
"1 of 2 validated with all witnesses reachable is majority",
digest.isInPrimaryPartition(true));
// To be thorough ensure we properly fail if witnesses are null.
digest = new ClusterMembershipDigest("a", configuredDBMembers,
configuredActiveWitnessMembers, viewDBMembers,
viewActiveWitnesses, null);
digest.setValidated("a", true);
Assert.assertFalse(
"1 of 2 validated with null witnesses is not majority",
digest.isInPrimaryPartition(true));
/*
* Add one more witness and then test to make sure that a primary
* partition only exists if 1 of 2 members is present plus ALL passive
* witnesses.
*/
witnesses = Arrays.asList("d", "e");
digest = new ClusterMembershipDigest("a", configuredDBMembers,
configuredActiveWitnessMembers, viewDBMembers,
viewActiveWitnesses, witnesses);
// Always validate ourself, but that is not enough for a quorum...
digest.setValidated("a", true);
Assert.assertFalse(
"1 of 2 validated without witnesses is not majority",
digest.isInPrimaryPartition(true));
digest.setReachable("a", true);
Assert.assertFalse(
"1 of 2 validated without all witnesses reachable is not majority",
digest.isInPrimaryPartition(true));
// 1 of 2 with all reachable witnesses is a majority.
digest.setReachable("d", true);
Assert.assertFalse(
"1 of 2 validated with only 1 of 2 witnesses is not a primary partition",
digest.isInPrimaryPartition(true));
digest.setReachable("e", true);
Assert.assertTrue(
"1 of 2 validated with 2 of 2 witnesses is a primary partition",
digest.isInPrimaryPartition(true));
}
/**
* Test to make sure that we detect inconsistent views i.e a view in which
* all of the members cannot be verified. This type of issue occurs
* frequently during a JGroups group transition where the process of a group
* member has just exited but JGroups has not updated the internal view yet.
* It has also happened, historically, due to bugs in JGroups in which the
* protocol to remove members from the view was not working as designed.
*
* @throws Exception
*/
@Test
public void testInconsistentViewDetection() throws Exception
{
List<String> configuredDBMembers = Arrays.asList("a", "b", "c");
List<String> configuredActiveWitnessMembers = null;
List<String> viewDBMembers = Arrays.asList("a", "b", "c");
List<String> viewActiveWitnesses = null;
List<String> witnesses = null;
ClusterMembershipDigest digest = new ClusterMembershipDigest("a",
configuredDBMembers, configuredActiveWitnessMembers,
viewDBMembers, viewActiveWitnesses, witnesses);
// If we have not validated a majority, we are not in a primary
// partition.
Assert.assertFalse("0 of 3 validated is not majority",
digest.isInPrimaryPartition(true));
// I need to be sure that 'myself' is validated. But that's not enough
// for a majority.
CLUtils.println("About to set validated for a");
digest.setValidated("a", true);
Assert.assertFalse("1 of 3 validated is not majority",
digest.isInPrimaryPartition(true));
/*
* We should detect an inconsistent view here because only 2 of 3
* members of the view are validated.
*/
CLUtils.println("About to set validated for b");
digest.setValidated("b", true);
Assert.assertFalse("2 of 3 validated is a majority",
digest.isInPrimaryPartition(true));
CLUtils.println("About to set validated for c");
digest.setValidated("c", true);
Assert.assertTrue("3 of 3 validated is a majority",
digest.isInPrimaryPartition(true));
}
@Test
public void testAttemptToValidateMemberThatIsNotInView() throws Exception
{
List<String> configuredDBMembers = Arrays.asList("a", "b", "c");
List<String> configuredActiveWitnessMembers = Arrays.asList("d");
List<String> viewDBMembers = Arrays.asList("a", "c");
List<String> viewActiveWitnesses = Arrays.asList("d");
List<String> witnesses = null;
ClusterMembershipDigest digest = new ClusterMembershipDigest("a",
configuredDBMembers, configuredActiveWitnessMembers,
viewDBMembers, viewActiveWitnesses, witnesses);
digest.setValidated("a", true);
Assert.assertTrue("Verified that 'a' is validated",
digest.isValidated("a"));
/*
* Try to validate a member that does not exist at all.
*/
try
{
digest.setValidated("doesNotExist", true);
}
catch (ClusterMembershipValidationException c)
{
Assert.assertTrue(
"Got an exception when validating a member that is not in the quorum set",
c.getMessage()
.equals("Cannot validate member 'doesNotExist' because it does not appear in the potential quorum member set."));
}
/*
* Try to validate a member that does not exist in the view.
*/
try
{
digest.setValidated("b", true);
}
catch (ClusterMembershipValidationException c)
{
Assert.assertTrue(
"Got an exception when validating a member that is not in the quorum set",
c.getMessage()
.equals("Cannot validate member 'b' because it does not appear in the view."));
}
}
/**
* Active witnesses should be used to establish a quorum only if a quorum
* cannot be derived from existing DB members. Also, active witnesses should
* never count in the initial calculation of the simple majority.
*
* @throws Exception
*/
@Test
public void testUsingActiveWitnessOnlyIfNeeded() throws Exception
{
List<String> configuredDBMembers = Arrays.asList("a", "b", "c");
List<String> configuredActiveWitnessMembers = Arrays.asList("d");
List<String> viewDBMembers = Arrays.asList("a", "d");
List<String> viewActiveWitnesses = Arrays.asList("d");
List<String> witnesses = null;
ClusterMembershipDigest digest = new ClusterMembershipDigest("a",
configuredDBMembers, configuredActiveWitnessMembers,
viewDBMembers, viewActiveWitnesses, witnesses);
/* simple majority should be 3/2 + 1 == 2 */
Assert.assertTrue("simple majority is equal to 2",
digest.getSimpleMajoritySize() == 2);
/*
* Validate one DB member and then test for a primary partition - should
* fail.
*/
digest.setValidated("a", true);
Assert.assertFalse(
"Only a single validated member - not in a primary partition",
digest.isInPrimaryPartition(true));
/*
* Now validate the active witness and check for a primary partition. In
* this case we should have a primary partition since simple majority=2
* and one validated DB host plus one validated active witness == 2.
*/
digest.setValidated("d", true);
Assert.assertTrue(
"One validated DB member and one validated active witness is a primary partition",
digest.isInPrimaryPartition(true));
/*
* Also check to be sure that the decision was made for the right reason
* i.e. that we have 2 DB members as the majority.
*/
Assert.assertTrue(
"The conclusion was based solely on the 1 DB member and 1 active witness",
digest.getConclusion()
.equals("CONCLUSION: I AM IN A PRIMARY PARTITION WITH 1 VALIDATED DB MEMBERS AND 1 VALIDATED ACTIVE WITNESSES"));
/*
* Add a DB member to the view and validate both of them, then check for
* a primary partition. Should still get a valid primary partition, but
* should only use the DB members.
*/
viewDBMembers = Arrays.asList("a", "b");
viewActiveWitnesses = Arrays.asList("d");
digest = new ClusterMembershipDigest("a", configuredDBMembers,
configuredActiveWitnessMembers, viewDBMembers,
viewActiveWitnesses, witnesses);
digest.setValidated("a", true);
digest.setValidated("b", true);
digest.setValidated("d", true);
Assert.assertTrue("Two validated DB members is a primary partition",
digest.isInPrimaryPartition(true));
/*
* Also check to be sure that the decision was made for the right reason
* i.e. that we have 2 DB members as the majority.
*/
Assert.assertTrue(
"The conclusion was based solely on the 2 DB members",
digest.getConclusion()
.equals("CONCLUSION: I AM IN A PRIMARY PARTITION OF 2 DB MEMBERS OUT OF THE REQUIRED MAJORITY OF 2"));
/*
* Try everything with 4 members plus 2 active witnesses. The simple
* majority should always be 3 and everything else should work
* correctly.
*/
configuredDBMembers = Arrays.asList("a", "b", "c", "d");
configuredActiveWitnessMembers = Arrays.asList("e");
witnesses = null;
viewDBMembers = Arrays.asList("a", "b", "c", "d");
viewActiveWitnesses = Arrays.asList("e");
digest = new ClusterMembershipDigest("a", configuredDBMembers,
configuredActiveWitnessMembers, viewDBMembers,
viewActiveWitnesses, witnesses);
digest.setValidated("a", true);
digest.setValidated("b", true);
/* simple majority should be 4/2 + 1 == 3 */
Assert.assertTrue("simple majority is equal to 3",
digest.getSimpleMajoritySize() == 3);
Assert.assertFalse(
"Two validated DB members is NOT a primary partition",
digest.isInPrimaryPartition(true));
Assert.assertTrue(
"NOT a primary partition because the view is inconsistent",
digest.getConclusion()
.equals("CONCLUSION: MEMBERSHIP IS INVALID"));
digest.setValidated("c", true);
digest.setValidated("d", true);
digest.setValidated("e", true);
Assert.assertTrue("In a valid partition - 4 out of 4 DB members",
digest.isInPrimaryPartition(true));
Assert.assertTrue(
"In a primary partition because we have 4 validated DB members",
digest.getConclusion()
.equals("CONCLUSION: I AM IN A PRIMARY PARTITION OF 4 DB MEMBERS OUT OF THE REQUIRED MAJORITY OF 3"));
}
@Test
public void testTwoDBNodesAndOnePassiveWitness() throws Exception
{
List<String> configuredDBMembers = Arrays.asList("a", "b");
List<String> configuredActiveWitnessMembers = null;
List<String> viewDBMembers = Arrays.asList("a", "b");
List<String> viewActiveWitnesses = null;
List<String> passiveWitnesses = Arrays.asList("c");
ClusterMembershipDigest digest = new ClusterMembershipDigest("a",
configuredDBMembers, configuredActiveWitnessMembers,
viewDBMembers, viewActiveWitnesses, passiveWitnesses);
/* simple majority should be 2/2 + 1 == 2 */
Assert.assertTrue("simple majority is equal to 2",
digest.getSimpleMajoritySize() == 2);
/*
* Validate one DB member and then test for a primary partition - should
* fail.
*/
digest.setValidated("a", true);
Assert.assertFalse(
"Only a single validated member - not in a primary partition",
digest.isInPrimaryPartition(true));
/*
* Now make the passive witness reachable and re-test for a primary
* partition. Should fail because we have a problem with view/validated
* consistency .
*/
digest.setReachable("c", true);
Assert.assertFalse(
"One validated DB member and one reachable passive witness is not primary partition - invalid membership",
digest.isInPrimaryPartition(true));
Assert.assertTrue(
"We don't have a primary partition becaues of problems with the memberhship",
digest.getConclusion()
.equals("CONCLUSION: MEMBERSHIP IS INVALID"));
/*
* Now make the second DB node validated. Should establish a primary
* partition due to having two validated DB nodes.
*/
digest.setValidated("b", true);
Assert.assertTrue("Two validated DB members is a primary partition",
digest.isInPrimaryPartition(true));
Assert.assertTrue(
"We arrived at a primary partition for the correct reason - 2 validated DB members",
digest.getConclusion()
.equals("CONCLUSION: I AM IN A PRIMARY PARTITION OF 2 DB MEMBERS OUT OF THE REQUIRED MAJORITY OF 2"));
}
@Test
public void testTwoDBNodesWithOneInViewAndTwoPassiveWitnesses()
throws Exception
{
List<String> configuredDBMembers = Arrays.asList("a", "b");
List<String> configuredActiveWitnessMembers = null;
List<String> viewDBMembers = Arrays.asList("a");
List<String> viewActiveWitnesses = null;
List<String> passiveWitnesses = Arrays.asList("c", "d");
ClusterMembershipDigest digest = new ClusterMembershipDigest("a",
configuredDBMembers, configuredActiveWitnessMembers,
viewDBMembers, viewActiveWitnesses, passiveWitnesses);
/* simple majority should be 2/2 + 1 == 2 */
Assert.assertTrue("simple majority is equal to 2",
digest.getSimpleMajoritySize() == 2);
/*
* Validate one DB member and then test for a primary partition - should
* fail.
*/
digest.setValidated("a", true);
Assert.assertFalse(
"Only a single validated member - not in a primary partition",
digest.isInPrimaryPartition(true));
/*
* Now make the passive witness reachable and re-test for a primary
* partition. Should fail to get a primary partition decision because
* all witnesses must be reachable in this case.
*/
digest.setReachable("c", true);
Assert.assertFalse(
"One validated DB member and one reachable passive witness is a primary partition",
digest.isInPrimaryPartition(true));
/*
* Now set the second witness as reachable and re-test. Should succeed.
*/
digest.setReachable("d", true);
Assert.assertTrue(
"One validated DB member and two (all) reachable passive witness is a primary partition",
digest.isInPrimaryPartition(true));
Assert.assertTrue(
"We arrived at a primary partition for the correct reason - 1 DB member and 1 passive witness",
digest.getConclusion()
.equals("CONCLUSION: I AM IN A PRIMARY PARTITION OF 2 MEMBERS, WITH 1 VALIDATED DB MEMBERS AND ALL (2) REACHABLE PASSIVE WITNESSES"));
}
@Test
public void testTwoDBNodesWithTwoInViewAndOnePassiveWitness()
throws Exception
{
List<String> configuredDBMembers = Arrays.asList("a", "b");
List<String> configuredActiveWitnessMembers = null;
List<String> viewDBMembers = Arrays.asList("a", "b");
List<String> viewActiveWitnesses = null;
List<String> passiveWitnesses = Arrays.asList("c", "d");
ClusterMembershipDigest digest = new ClusterMembershipDigest("a",
configuredDBMembers, configuredActiveWitnessMembers,
viewDBMembers, viewActiveWitnesses, passiveWitnesses);
/* simple majority should be 2/2 + 1 == 2 */
Assert.assertTrue("simple majority is equal to 2",
digest.getSimpleMajoritySize() == 2);
/*
* Validate one DB member and then test for a primary partition - should
* fail.
*/
digest.setValidated("a", true);
Assert.assertFalse(
"Only a single validated member - not in a primary partition",
digest.isInPrimaryPartition(true));
/*
* Now make the passive witness reachable and re-test for a primary
* partition. Should fail to get a primary partition decision because
* all witnesses must be reachable in this case.
*/
digest.setReachable("c", true);
Assert.assertFalse(
"One validated DB member and one reachable passive witness is a primary partition",
digest.isInPrimaryPartition(true));
/*
* Now set the second witness as reachable and re-test. Should fail
* because we still have an inconsistency between the view and validated
* members.
*/
digest.setReachable("d", true);
Assert.assertFalse(
"One validated DB member and two (all) reachable passive witness is still not a primary partition",
digest.isInPrimaryPartition(true));
Assert.assertTrue(
"We still don't have a primary partition because the membership IS INVALID",
digest.getConclusion()
.equals("CONCLUSION: MEMBERSHIP IS INVALID"));
/*
* Now make the second DB node validated. Should establish a primary
* partition due to having two validated DB nodes.
*/
digest.setValidated("b", true);
Assert.assertTrue("Two validated DB members is a primary partition",
digest.isInPrimaryPartition(true));
Assert.assertTrue(
"We arrived at a primary partition for the correct reason - 2 validated DB members",
digest.getConclusion()
.equals("CONCLUSION: I AM IN A PRIMARY PARTITION OF 2 DB MEMBERS OUT OF THE REQUIRED MAJORITY OF 2"));
}
@Test
public void testThreeDBNodesAndOnePassiveWitness() throws Exception
{
List<String> configuredDBMembers = Arrays.asList("a", "b", "c");
List<String> configuredActiveWitnessMembers = null;
List<String> viewDBMembers = Arrays.asList("a", "b", "c");
List<String> viewActiveWitnesses = null;
List<String> passiveWitnesses = Arrays.asList("d");
ClusterMembershipDigest digest = new ClusterMembershipDigest("a",
configuredDBMembers, configuredActiveWitnessMembers,
viewDBMembers, viewActiveWitnesses, passiveWitnesses);
/* simple majority should be 3/2 + 1 == 2 */
Assert.assertTrue("simple majority is equal to 2",
digest.getSimpleMajoritySize() == 2);
/*
* Validate one DB member and then test for a primary partition - should
* fail.
*/
digest.setValidated("a", true);
Assert.assertFalse(
"Only a single validated member - not in a primary partition",
digest.isInPrimaryPartition(true));
/*
* Validate a second DB member and then test for a primary partition -
* should fail because of view/validated member consistency problems.
*/
digest.setValidated("b", true);
Assert.assertFalse(
"Two validated members out of a view of 3 - not in a primary partition",
digest.isInPrimaryPartition(true));
/*
* Now flesh out the validated members and re-test. Should succeed.
*/
digest.setValidated("c", true);
Assert.assertTrue("Three validated DB members is a primary partition",
digest.isInPrimaryPartition(true));
Assert.assertTrue(
"We arrived at a primary partition for the correct reason - 2 validated DB members",
digest.getConclusion()
.equals("CONCLUSION: I AM IN A PRIMARY PARTITION OF 3 DB MEMBERS OUT OF THE REQUIRED MAJORITY OF 2"));
}
@Test
public void testTwoDBNodesAndOneActiveWitness()
{
}
@Test
public void testThreeDBNodesAndOneActiveWitness()
{
}
/**
* Verify that invalid configurations are properly caught. This includes a
* configuration where the member name is not included in the quorum set,
* where the quorum set is empty, or where the view is empty.
*/
@Test
public void testInvalidConfigurations() throws Exception
{
List<String> configured = Arrays.asList("a", "b");
List<String> view = Arrays.asList("a", "b");
// Confirm that member name must be in quorum set.
ClusterMembershipDigest badMemberName = new ClusterMembershipDigest(
"c", configured, view, null, view, view);
Assert.assertFalse("Member must be in quorum set",
badMemberName.isValidPotentialQuorumMembersSet(true));
// Confirm that quorum set must be non-null.
ClusterMembershipDigest emptyQuorum = new ClusterMembershipDigest("a",
new ArrayList<String>(), null, null, view, view);
Assert.assertFalse("Quorum set must non-null",
emptyQuorum.isValidPotentialQuorumMembersSet(true));
// Confirm that GC view contains members.
ClusterMembershipDigest emptyView = new ClusterMembershipDigest("a",
configured, null, null, view, view);
Assert.assertFalse("View must have members",
emptyView.isValidPotentialQuorumMembersSet(true));
// Confirm that GC view contains the member name.
ClusterMembershipDigest memberNotInView = new ClusterMembershipDigest(
"a", configured, Arrays.asList("b"), null, view, view);
Assert.assertFalse("View must contain the member name",
memberNotInView.isValidPotentialQuorumMembersSet(true));
// Confirm that configured list has at least one member.
ClusterMembershipDigest noConfiguredNames = new ClusterMembershipDigest(
"a", null, Arrays.asList("a"), null, view, view);
Assert.assertFalse("Configured names must include at least one name",
noConfiguredNames.isValidPotentialQuorumMembersSet(true));
}
// Assert that two lists contain identical members.
private void assertEqualSet(String message, List<String> first,
List<String> second)
{
Set<String> a = new TreeSet<String>(first);
Set<String> b = new TreeSet<String>(second);
Assert.assertTrue(message, a.equals(b));
}
}