package org.ovirt.engine.core.bll.gluster; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.doReturn; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedList; import java.util.List; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner.Silent; import org.ovirt.engine.core.common.businessentities.Cluster; import org.ovirt.engine.core.common.businessentities.gluster.GlusterBrickEntity; import org.ovirt.engine.core.common.businessentities.gluster.GlusterStatus; import org.ovirt.engine.core.common.businessentities.gluster.GlusterVolumeEntity; import org.ovirt.engine.core.common.businessentities.gluster.GlusterVolumeType; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.dao.gluster.GlusterBrickDao; import org.ovirt.engine.core.dao.gluster.GlusterVolumeDao; @RunWith(Silent.class) public class GlusterHostValidatorTest { private static final Guid CLUSTER_ID = new Guid("ae956031-6be2-43d6-bb8f-5191c9253314"); private static final Guid VOL_ID_1 = new Guid("0c3f45f6-3fe9-4b35-a30c-be0d1a835ea8"); private static final Guid VOL_ID_2 = new Guid("b2cb2f73-fab3-4a42-93f0-d5e4c069a43e"); private static final Guid SERVER_ID_1 = new Guid("23f6d691-5dfb-472b-86dc-9e1d2d3c18f3"); private static final Guid SERVER_ID_2 = new Guid("2001751e-549b-4e7a-aff6-32d36856c125"); private static final Guid SERVER_ID_3 = new Guid("2001751e-549b-4e7a-aff6-32d36856c126"); private static final Guid DUMMY_SERVER_ID = new Guid("2001751e-549b-4e7a-aff6-32d36856c127"); @Mock private GlusterVolumeDao volumeDao; @Mock private GlusterBrickDao brickDao; private GlusterHostValidator hostValidator; @Before public void setUp() throws Exception { setupMock(); hostValidator = new GlusterHostValidator(volumeDao, brickDao); } private void setupMock() throws Exception { doReturn(getBricksFromServer(SERVER_ID_1, GlusterStatus.UP)).when(brickDao) .getGlusterVolumeBricksByServerId(SERVER_ID_1); doReturn(getBricksFromServer(SERVER_ID_2, GlusterStatus.UP)).when(brickDao) .getGlusterVolumeBricksByServerId(SERVER_ID_2); doReturn(getBricksFromServer(SERVER_ID_3, GlusterStatus.UP)).when(brickDao) .getGlusterVolumeBricksByServerId(SERVER_ID_3); doReturn(getGlusterVolumes(CLUSTER_ID, GlusterStatus.UP)).when(volumeDao).getByClusterId(CLUSTER_ID); } @Test public void testCheckGlusterQuorumWithoutGluster() { Cluster cluster = getCluster(false, CLUSTER_ID); Iterable<Guid> hostIds = new LinkedList<>(); assertTrue("Quorum checks runs for Cluster without gluster service", hostValidator.checkGlusterQuorum(cluster, hostIds).isEmpty()); } @Test public void testCheckGlusterQuorumWithoutBricks() { Cluster cluster = getCluster(true, CLUSTER_ID); Iterable<Guid> hostIds = Arrays.asList(DUMMY_SERVER_ID, SERVER_ID_1); assertTrue(hostValidator.checkGlusterQuorum(cluster, hostIds).isEmpty()); } @Test public void testCheckGlusterQuorumWithoutRequiredVolumeOptions() { Cluster cluster = getCluster(true, CLUSTER_ID); Iterable<Guid> hostIds = Arrays.asList(SERVER_ID_1, SERVER_ID_2); // Reset the quroum related volume options List<GlusterVolumeEntity> glusterVolumes = getGlusterVolumes(CLUSTER_ID, GlusterStatus.UP); for (GlusterVolumeEntity volume : glusterVolumes) { volume.setOptions(""); } doReturn(glusterVolumes).when(volumeDao).getByClusterId(CLUSTER_ID); assertTrue(hostValidator.checkGlusterQuorum(cluster, hostIds).isEmpty()); } @Test public void testCheckGlusterQuorumTwoServersUp() { Cluster cluster = getCluster(true, CLUSTER_ID); Iterable<Guid> hostIds = Arrays.asList(SERVER_ID_1); assertTrue(hostValidator.checkGlusterQuorum(cluster, hostIds).isEmpty()); } @Test public void testCheckGlusterQuorumWithTwoServersDown() { Cluster cluster = getCluster(true, CLUSTER_ID); Iterable<Guid> hostIds = Arrays.asList(SERVER_ID_1, SERVER_ID_2); assertTrue("Quorum check is failing", hostValidator.checkGlusterQuorum(cluster, hostIds).size() == 2); assertTrue(Arrays.asList("Vol-1", "Vol-2").equals(hostValidator.checkGlusterQuorum(cluster, hostIds))); } @Test public void testCheckGlusterQuorumWithBricksDown() { Cluster cluster = getCluster(true, CLUSTER_ID); // Make sure first brick in all the subvolumes are down List<GlusterVolumeEntity> glusterVolumes = getGlusterVolumes(CLUSTER_ID, GlusterStatus.UP); for (GlusterVolumeEntity volume : glusterVolumes) { for (int index = 0; index < volume.getBricks().size(); index += volume.getReplicaCount()) { volume.getBricks().get(index).setStatus(GlusterStatus.DOWN); } } doReturn(glusterVolumes).when(volumeDao).getByClusterId(CLUSTER_ID); Iterable<Guid> hostIds = Arrays.asList(SERVER_ID_2); assertTrue("Quorum check is failing", hostValidator.checkGlusterQuorum(cluster, hostIds).size() == 2); assertTrue(Arrays.asList("Vol-1", "Vol-2").equals(hostValidator.checkGlusterQuorum(cluster, hostIds))); } @Test public void testCheckGlusterQuorumWithVolumeDown() { Cluster cluster = getCluster(true, CLUSTER_ID); doReturn(getGlusterVolumes(CLUSTER_ID, GlusterStatus.DOWN)).when(volumeDao).getByClusterId(CLUSTER_ID); Iterable<Guid> hostIds = Arrays.asList(SERVER_ID_1, SERVER_ID_2); assertTrue("Quorum check is failing with volumes in down status", hostValidator.checkGlusterQuorum(cluster, hostIds).isEmpty()); } @Test public void testcheckUnsyncedEntriesWithDownBricks() { doReturn(getBricksFromServer(SERVER_ID_1, GlusterStatus.DOWN)).when(brickDao) .getGlusterVolumeBricksByServerId(SERVER_ID_1); assertTrue("Unsynced entries test is failing for bricks with down status", hostValidator.checkUnsyncedEntries(Arrays.asList(SERVER_ID_1)).isEmpty()); } @Test public void testcheckUnsyncedEntriesWithoutUnSyncedEntries() { doReturn(getBricksFromServer(SERVER_ID_1, GlusterStatus.UP)).when(brickDao) .getGlusterVolumeBricksByServerId(SERVER_ID_1); assertTrue("Unsynced entries test is failing for bricks without unsynced entries", hostValidator.checkUnsyncedEntries(Arrays.asList(SERVER_ID_1)).isEmpty()); } @Test public void testcheckUnsyncedEntriesWithUnSyncedEntries() { List<GlusterBrickEntity> bricks = getBricksFromServer(SERVER_ID_1, GlusterStatus.UP); bricks.get(0).setUnSyncedEntries(100); bricks.get(1).setUnSyncedEntries(10); bricks.get(2).setUnSyncedEntries(0); doReturn(bricks).when(brickDao).getGlusterVolumeBricksByServerId(SERVER_ID_1); assertTrue("Unsynced entries test is failing for bricks with unsynced entries", hostValidator.checkUnsyncedEntries(Arrays.asList(SERVER_ID_1, SERVER_ID_2)) .get(SERVER_ID_1) .size() == 2); } private Cluster getCluster(boolean supportGlusterService, Guid clusterId) { Cluster cluster = new Cluster(); cluster.setId(clusterId); cluster.setGlusterService(supportGlusterService); return cluster; } private List<GlusterVolumeEntity> getGlusterVolumes(Guid clusterId, GlusterStatus status) { List<GlusterVolumeEntity> volumesList = new ArrayList<>(); String volumeOptions = "cluster.quorum-type=fixed,cluster.quorum-count=2"; volumesList.add(getGlusterVolume("Vol-1", VOL_ID_1, GlusterVolumeType.REPLICATE, 3, volumeOptions, getBricksForVolume(1), status)); volumesList.add(getGlusterVolume("Vol-2", VOL_ID_2, GlusterVolumeType.DISTRIBUTED_REPLICATE, 3, "cluster.quorum-type=auto", getBricksForVolume(2), status)); return volumesList; } private List<GlusterBrickEntity> getBricksFromServer(Guid serverId, GlusterStatus status) { List<GlusterBrickEntity> bricks = new ArrayList<>(); bricks.add(getGlusterBrick(status, serverId)); bricks.add(getGlusterBrick(status, serverId)); bricks.add(getGlusterBrick(status, serverId)); return bricks; } private List<GlusterBrickEntity> getBricksForVolume(int bricksPerServer) { List<GlusterBrickEntity> bricks = new ArrayList<>(); for (int i = 0; i < bricksPerServer; i++) { bricks.add(getGlusterBrick(GlusterStatus.UP, SERVER_ID_1)); bricks.add(getGlusterBrick(GlusterStatus.UP, SERVER_ID_2)); bricks.add(getGlusterBrick(GlusterStatus.UP, SERVER_ID_3)); } return bricks; } private GlusterVolumeEntity getGlusterVolume(String name, Guid volumeID, GlusterVolumeType volumeType, int replicaCount, String volumeOptions, List<GlusterBrickEntity> bricks, GlusterStatus status) { GlusterVolumeEntity volume = new GlusterVolumeEntity(); volume.setName(name); volume.setId(volumeID); volume.setReplicaCount(replicaCount); volume.setVolumeType(volumeType); volume.setOptions(volumeOptions); volume.setBricks(bricks); volume.setStatus(status); return volume; } private GlusterBrickEntity getGlusterBrick(GlusterStatus status, Guid serverId) { GlusterBrickEntity brick = new GlusterBrickEntity(); brick.setStatus(status); brick.setServerId(serverId); return brick; } }