package org.ovirt.engine.core.bll;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
import org.ovirt.engine.core.bll.utils.ClusterUtils;
import org.ovirt.engine.core.bll.utils.GlusterUtil;
import org.ovirt.engine.core.common.AuditLogType;
import org.ovirt.engine.core.common.action.RemoveVdsParameters;
import org.ovirt.engine.core.common.businessentities.Cluster;
import org.ovirt.engine.core.common.businessentities.VDS;
import org.ovirt.engine.core.common.businessentities.VDSStatus;
import org.ovirt.engine.core.common.businessentities.VdsDynamic;
import org.ovirt.engine.core.common.businessentities.gluster.GlusterBrickEntity;
import org.ovirt.engine.core.common.errors.EngineMessage;
import org.ovirt.engine.core.common.interfaces.VDSBrokerFrontend;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.core.dao.ClusterDao;
import org.ovirt.engine.core.dao.StoragePoolDao;
import org.ovirt.engine.core.dao.VdsDao;
import org.ovirt.engine.core.dao.VdsDynamicDao;
import org.ovirt.engine.core.dao.VdsStaticDao;
import org.ovirt.engine.core.dao.VdsStatisticsDao;
import org.ovirt.engine.core.dao.VmStaticDao;
import org.ovirt.engine.core.dao.gluster.GlusterBrickDao;
import org.ovirt.engine.core.dao.gluster.GlusterHooksDao;
import org.ovirt.engine.core.dao.gluster.GlusterVolumeDao;
public class RemoveVdsCommandTest extends BaseCommandTest {
@Mock
private VdsDynamicDao vdsDynamicDao;
@Mock
private StoragePoolDao storagePoolDao;
@Mock
private VmStaticDao vmStaticDao;
@Mock
private VdsDao vdsDao;
@Mock
private Cluster cluster;
@Mock
private GlusterBrickDao glusterBrickDao;
@Mock
private ClusterDao clusterDao;
@Mock
private ClusterUtils clusterUtils;
@Mock
private GlusterUtil glusterUtils;
@Mock
private GlusterVolumeDao volumeDao;
@Mock
private GlusterHooksDao hooksDao;
@Mock
private VDSBrokerFrontend vdsBrokerFrontend;
@Mock
private VdsStaticDao vdsStaticDao;
@Mock
private VdsStatisticsDao vdsStatisticsDao;
/**
* The command under test.
*/
@Spy
@InjectMocks
private RemoveVdsCommand<RemoveVdsParameters> command =
new RemoveVdsCommand<>(new RemoveVdsParameters(Guid.newGuid(), false), null);
private Guid clusterId;
@Before
public void setUp() {
clusterId = Guid.newGuid();
doReturn(cluster).when(clusterDao).get(any(Guid.class));
doReturn(clusterUtils).when(command).getClusterUtils();
when(glusterUtils.getUpServer(clusterId)).thenReturn(getVds(VDSStatus.Up));
}
private void mockHasMultipleClusters(Boolean isMultiple) {
when(command.getClusterId()).thenReturn(clusterId);
when(clusterUtils.hasMultipleServers(clusterId)).thenReturn(isMultiple);
}
private VDS getVds(VDSStatus status) {
VDS vds = new VDS();
vds.setId(Guid.newGuid());
vds.setVdsName("gfs1");
vds.setClusterId(clusterId);
vds.setStatus(status);
return vds;
}
@Test
public void validateSucceeds() throws Exception {
mockVdsWithStatus(VDSStatus.Maintenance);
mockVdsDynamic();
mockVmsPinnedToHost(Collections.emptyList());
mockIsGlusterEnabled(false);
mockHasVolumeOnServer(false);
ValidateTestUtils.runAndAssertValidateSuccess(command);
}
@Test
public void validateFailsWhenGlusterHostHasVolumes() throws Exception {
mockVdsWithStatus(VDSStatus.Maintenance);
mockVdsDynamic();
mockVmsPinnedToHost(Collections.emptyList());
mockIsGlusterEnabled(true);
mockHasVolumeOnServer(true);
ValidateTestUtils.runAndAssertValidateFailure(command,
EngineMessage.VDS_CANNOT_REMOVE_HOST_HAVING_GLUSTER_VOLUME);
}
@Test
public void validateFailsWhenGlusterMultipleHostHasVolumesWithForce() throws Exception {
command.getParameters().setForceAction(true);
mockVdsWithStatus(VDSStatus.Maintenance);
mockHasMultipleClusters(true);
mockIsGlusterEnabled(true);
mockHasVolumeOnServer(true);
ValidateTestUtils.runAndAssertValidateFailure(command,
EngineMessage.VDS_CANNOT_REMOVE_HOST_HAVING_GLUSTER_VOLUME);
}
@Test
public void validateSucceedsWithForceOption() throws Exception {
command.getParameters().setForceAction(true);
mockVdsWithStatus(VDSStatus.Maintenance);
mockVdsDynamic();
mockVmsPinnedToHost(Collections.emptyList());
mockIsGlusterEnabled(true);
mockHasVolumeOnServer(true);
ValidateTestUtils.runAndAssertValidateSuccess(command);
}
@Test
public void validateFailsWhenVMsPinnedToHost() throws Exception {
mockVdsWithStatus(VDSStatus.Maintenance);
mockVdsDynamic();
mockIsGlusterEnabled(true);
mockHasVolumeOnServer(true);
String vmName = "abc";
mockVmsPinnedToHost(Collections.singletonList(vmName));
ValidateTestUtils.runAndAssertValidateFailure(command,
EngineMessage.ACTION_TYPE_FAILED_DETECTED_PINNED_VMS);
boolean foundMessage = false;
for (String message : command.getReturnValue().getValidationMessages()) {
foundMessage |= message.contains(vmName);
}
assertTrue("Can't find VM name in can do action messages", foundMessage);
}
@Test
public void removeWhenMultipleHosts() {
mockVdsWithStatus(VDSStatus.Maintenance);
mockVdsDynamic();
mockIsGlusterEnabled(true);
mockHasMultipleClusters(true);
command.executeCommand();
assertEquals(AuditLogType.USER_REMOVE_VDS, command.getAuditLogTypeValue());
verify(vdsDynamicDao, times(1)).remove(any(Guid.class));
verify(vdsStatisticsDao, times(1)).remove(any(Guid.class));
verify(volumeDao, never()).removeByClusterId(any(Guid.class));
verify(hooksDao, never()).removeAllInCluster(any(Guid.class));
}
@Test
public void removeLastHost() {
mockVdsWithStatus(VDSStatus.Maintenance);
mockVdsDynamic();
mockIsGlusterEnabled(true);
mockHasMultipleClusters(false);
command.executeCommand();
assertEquals(AuditLogType.USER_REMOVE_VDS, command.getAuditLogTypeValue());
verify(vdsDynamicDao, times(1)).remove(any(Guid.class));
verify(vdsStatisticsDao, times(1)).remove(any(Guid.class));
verify(volumeDao, times(1)).removeByClusterId(any(Guid.class));
verify(hooksDao, times(1)).removeAllInCluster(any(Guid.class));
}
/**
* Mocks that a valid {@link VdsDynamic} gets returned.
*/
private void mockVdsDynamic() {
when(vdsDynamicDao.get(command.getParameters().getVdsId())).thenReturn(new VdsDynamic());
}
/**
* Mocks that the given VMs are pinned to the host (List can be empty, but by the API contract can't be
* <code>null</code>).
*
* @param emptyList
* The list of VM names.
*/
private void mockVmsPinnedToHost(List<String> emptyList) {
when(vmStaticDao.getAllNamesPinnedToHost(command.getParameters().getVdsId())).thenReturn(emptyList);
}
/**
* Mocks that a {@link VDS} with the given status is returned.
*
* @param status
* The status of the VDS.
*/
private void mockVdsWithStatus(VDSStatus status) {
VDS vds = new VDS();
vds.setStatus(status);
when(vdsDao.get(command.getParameters().getVdsId())).thenReturn(vds);
}
/**
* Mock that {@link org.ovirt.engine.core.common.businessentities.Cluster} with the given glusterservice status is returned
*
* @param glusterService
* The Cluster with the given glusterservice status
*/
private void mockIsGlusterEnabled(boolean glusterService) {
when(cluster.supportsGlusterService()).thenReturn(glusterService);
}
/**
* Mock that whether the VDS configured with gluster volume. This will return the given volume count
*/
private void mockHasVolumeOnServer(boolean isBricksRequired) {
List<GlusterBrickEntity> bricks = new ArrayList<>();
if (isBricksRequired) {
GlusterBrickEntity brick = new GlusterBrickEntity();
brick.setVolumeId(Guid.newGuid());
brick.setServerId(command.getVdsId());
bricks.add(brick);
}
when(glusterBrickDao.getGlusterVolumeBricksByServerId(command.getVdsId())).thenReturn(bricks);
}
}