package org.ovirt.engine.core.bll.storage.disk;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
import org.ovirt.engine.core.bll.BaseCommandTest;
import org.ovirt.engine.core.bll.ValidateTestUtils;
import org.ovirt.engine.core.bll.ValidationResult;
import org.ovirt.engine.core.bll.snapshots.SnapshotsValidator;
import org.ovirt.engine.core.bll.utils.VmDeviceUtils;
import org.ovirt.engine.core.bll.validator.storage.DiskValidator;
import org.ovirt.engine.core.bll.validator.storage.DiskVmElementValidator;
import org.ovirt.engine.core.bll.validator.storage.StorageDomainValidator;
import org.ovirt.engine.core.common.action.VmDiskOperationParameterBase;
import org.ovirt.engine.core.common.businessentities.StorageDomain;
import org.ovirt.engine.core.common.businessentities.VDS;
import org.ovirt.engine.core.common.businessentities.VM;
import org.ovirt.engine.core.common.businessentities.VMStatus;
import org.ovirt.engine.core.common.businessentities.VmDevice;
import org.ovirt.engine.core.common.businessentities.VmDeviceId;
import org.ovirt.engine.core.common.businessentities.storage.Disk;
import org.ovirt.engine.core.common.businessentities.storage.DiskImage;
import org.ovirt.engine.core.common.businessentities.storage.DiskInterface;
import org.ovirt.engine.core.common.businessentities.storage.DiskVmElement;
import org.ovirt.engine.core.common.errors.EngineMessage;
import org.ovirt.engine.core.common.osinfo.OsRepository;
import org.ovirt.engine.core.common.utils.SimpleDependencyInjector;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.core.compat.Version;
import org.ovirt.engine.core.dao.DiskDao;
import org.ovirt.engine.core.dao.DiskVmElementDao;
import org.ovirt.engine.core.dao.StorageDomainDao;
import org.ovirt.engine.core.dao.VdsDao;
import org.ovirt.engine.core.dao.VmDao;
import org.ovirt.engine.core.dao.VmDeviceDao;
import org.ovirt.engine.core.dao.network.VmNetworkInterfaceDao;
public class HotPlugDiskToVmCommandTest extends BaseCommandTest {
protected Guid diskImageGuid = Guid.newGuid();
protected Guid vmId = Guid.newGuid();
private VM vm = new VM();
private final Guid storagePoolId = Guid.newGuid();
private final Guid storageDomainId = Guid.newGuid();
protected static final List<String> DISK_HOTPLUGGABLE_INTERFACES = Arrays.asList("VirtIO_SCSI", "VirtIO");
private DiskImage disk = new DiskImage();
private DiskVmElement diskVmElement = new DiskVmElement(diskImageGuid, vmId);
protected VmDevice vmDevice;
@Mock
private VmDao vmDao;
@Mock
private VdsDao vdsDao;
@Mock
protected DiskDao diskDao;
@Mock
private VmDeviceDao vmDeviceDao;
@Mock
private StorageDomainDao storageDomainDao;
@Mock
private VmNetworkInterfaceDao vmNetworkInterfaceDao;
@Mock
private DiskVmElementDao diskVmElementDao;
@Mock
private DiskValidator diskValidator;
@Spy
private DiskVmElementValidator diskVmElementValidator = new DiskVmElementValidator(disk, diskVmElement);
@Mock
private SnapshotsValidator snapshotsValidator;
@Mock
private StorageDomainValidator storageDomainValidator;
protected static OsRepository osRepository;
@Mock
private VmDeviceUtils vmDeviceUtils;
/**
* The command under test.
*/
@Spy
@InjectMocks
protected HotPlugDiskToVmCommand<VmDiskOperationParameterBase> command = createCommand();
@BeforeClass
public static void setUpClass() {
osRepository = mock(OsRepository.class);
SimpleDependencyInjector.getInstance().bind(OsRepository.class, osRepository);
}
@Before
public void setUp() {
mockVds();
mockVmDevice(false);
doReturn(storageDomainValidator).when(command).getStorageDomainValidator(any(StorageDomain.class));
doReturn(diskValidator).when(command).getDiskValidator(disk);
doReturn(diskVmElementValidator).when(command).getDiskVmElementValidator(any(Disk.class), any(DiskVmElement.class));
when(osRepository.getDiskHotpluggableInterfaces(anyInt(), any()))
.thenReturn(new HashSet<>(DISK_HOTPLUGGABLE_INTERFACES));
SimpleDependencyInjector.getInstance().bind(VmDeviceUtils.class, vmDeviceUtils);
}
@Test
public void validateFailedVMNotFound() throws Exception {
mockNullVm();
ValidateTestUtils.runAndAssertValidateFailure(command, EngineMessage.ACTION_TYPE_FAILED_VM_NOT_FOUND);
}
@Test
public void validateFailedVMHasNotDisk() throws Exception {
mockVmStatusUp();
ValidateTestUtils.runAndAssertValidateFailure(command, EngineMessage.ACTION_TYPE_FAILED_DISK_NOT_EXIST);
}
@Test
public void validateFailedVirtIODisk() throws Exception {
mockVmStatusUp();
mockInterfaceList();
when(osRepository.getOsName(0)).thenReturn("RHEL6");
createNotVirtIODisk();
ValidateTestUtils.runAndAssertValidateFailure(command, EngineMessage.HOT_PLUG_IDE_DISK_IS_NOT_SUPPORTED);
}
@Test
public void validateFailedWrongPlugStatus() throws Exception {
mockVmStatusUp();
mockInterfaceList();
createDiskWrongPlug(true);
ValidateTestUtils.runAndAssertValidateFailure(command, EngineMessage.HOT_PLUG_DISK_IS_NOT_UNPLUGGED);
}
@Test
public void validateFailedGuestOsIsNotSupported() {
mockInterfaceList();
VM vm = mockVmStatusUp();
vm.setVmOs(15); // rhel3x64
createVirtIODisk();
when(osRepository.getOsName(15)).thenReturn("RHEL3x64");
when(osRepository.getDiskHotpluggableInterfaces(anyInt(), any())).thenReturn(Collections.emptySet());
ValidateTestUtils.runAndAssertValidateFailure(command, EngineMessage.ACTION_TYPE_FAILED_GUEST_OS_VERSION_IS_NOT_SUPPORTED);
}
@Test
public void validateSuccess() {
mockVmStatusUp();
mockInterfaceList();
createVirtIODisk();
initStorageDomain();
ValidateTestUtils.runAndAssertValidateSuccess(command);
}
@Test
public void validateFailedDiskInterfaceUnsupported() {
mockVmStatusUp();
createVirtIODisk();
initStorageDomain();
when(diskVmElementValidator.isDiskInterfaceSupported(any(VM.class))).thenReturn(new ValidationResult(EngineMessage.ACTION_TYPE_DISK_INTERFACE_UNSUPPORTED));
ValidateTestUtils.runAndAssertValidateFailure(command, EngineMessage.ACTION_TYPE_DISK_INTERFACE_UNSUPPORTED);
}
@Test
public void validateFailedDiscardNotSupported() {
mockVmStatusUp();
mockInterfaceList();
createVirtIODisk();
initStorageDomain();
doReturn(new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_PASS_DISCARD_NOT_SUPPORTED_BY_DISK_INTERFACE))
.when(diskVmElementValidator).isPassDiscardSupported(any(Guid.class));
ValidateTestUtils.runAndAssertValidateFailure(command,
EngineMessage.ACTION_TYPE_FAILED_PASS_DISCARD_NOT_SUPPORTED_BY_DISK_INTERFACE);
}
private void initStorageDomain() {
StorageDomain storageDomain = new StorageDomain();
storageDomain.setId(storageDomainId);
storageDomain.setStoragePoolId(storagePoolId);
when(storageDomainDao.get(any(Guid.class))).thenReturn(storageDomain);
when(storageDomainDao.getForStoragePool(storageDomainId, storagePoolId)).thenReturn(storageDomain);
}
protected HotPlugDiskToVmCommand<VmDiskOperationParameterBase> createCommand() {
return new HotPlugDiskToVmCommand<>(createParameters(), null);
}
private void mockNullVm() {
createVirtIODisk();
}
/**
* Mock a VM in status Up
*/
protected VM mockVmStatusUp() {
vm.setStatus(VMStatus.Up);
vm.setVmOs(8);
vm.setId(vmId);
vm.setRunOnVds(Guid.newGuid());
when(vmDao.get(command.getParameters().getVmId())).thenReturn(vm);
return vm;
}
/**
* Mock VDS
*/
protected void mockVds() {
VDS vds = new VDS();
vds.setClusterCompatibilityVersion(Version.getLast());
when(vdsDao.get(any(Guid.class))).thenReturn(vds);
}
protected void mockInterfaceList() {
ArrayList<String> diskInterfaces = new ArrayList<>(
Arrays.asList(new String[]{
"IDE",
"VirtIO",
"VirtIO_SCSI"
}));
when(osRepository.getDiskInterfaces(anyInt(), any())).thenReturn(diskInterfaces);
}
/**
* @return Valid parameters for the command.
*/
protected VmDiskOperationParameterBase createParameters() {
return new VmDiskOperationParameterBase(diskVmElement);
}
/**
* The following method will create a disk which is not VirtIO
*/
private void createNotVirtIODisk() {
mockDiskImage(DiskInterface.IDE);
command.getParameters().getDiskVmElement().setDiskInterface(DiskInterface.IDE);
}
/**
* The following method will create a VirtIO disk , which is marked as unplugged
*/
protected void createVirtIODisk() {
mockDiskImage(DiskInterface.VirtIO);
command.getParameters().getDiskVmElement().setDiskInterface(DiskInterface.VirtIO);
}
private DiskImage mockDiskImage(DiskInterface iface) {
disk.setImageId(diskImageGuid);
ArrayList<Guid> storageIdList = new ArrayList<>();
storageIdList.add(storageDomainId);
disk.setStorageIds(storageIdList);
disk.setStoragePoolId(storagePoolId);
disk.setActive(true);
disk.setId(Guid.newGuid());
when(diskDao.get(diskImageGuid)).thenReturn(disk);
DiskVmElement dve = new DiskVmElement(disk.getId(), vmId);
dve.setDiskInterface(iface);
when(diskVmElementDao.get(new VmDeviceId(disk.getId(), vmId))).thenReturn(dve);
return disk;
}
/**
* The following method will create a VirtIO disk with provided plug option
* @param plugged - the value which will be set to plug field
*/
protected void createDiskWrongPlug(boolean plugged) {
createVirtIODisk();
vmDevice.setPlugged(plugged);
}
protected void mockVmDevice(boolean plugged) {
vmDevice = new VmDevice();
vmDevice.setId(new VmDeviceId());
vmDevice.setPlugged(plugged);
when(vmDeviceDao.get(any(VmDeviceId.class))).thenReturn(vmDevice);
}
}