package org.ovirt.engine.core.bll.storage.lsm; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Mockito.doReturn; 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.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.validator.VmValidator; import org.ovirt.engine.core.bll.validator.storage.DiskValidator; import org.ovirt.engine.core.bll.validator.storage.DiskVmElementValidator; import org.ovirt.engine.core.common.action.LiveMigrateDiskParameters; import org.ovirt.engine.core.common.action.LiveMigrateVmDisksParameters; import org.ovirt.engine.core.common.businessentities.StorageDomain; import org.ovirt.engine.core.common.businessentities.StorageDomainStatus; import org.ovirt.engine.core.common.businessentities.StorageDomainType; import org.ovirt.engine.core.common.businessentities.StoragePool; import org.ovirt.engine.core.common.businessentities.VM; import org.ovirt.engine.core.common.businessentities.VMStatus; import org.ovirt.engine.core.common.businessentities.storage.DiskImage; import org.ovirt.engine.core.common.businessentities.storage.StorageType; import org.ovirt.engine.core.common.errors.EngineMessage; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.compat.Version; import org.ovirt.engine.core.dao.DiskImageDao; import org.ovirt.engine.core.dao.SnapshotDao; import org.ovirt.engine.core.dao.StorageDomainDao; import org.ovirt.engine.core.dao.StoragePoolDao; import org.ovirt.engine.core.dao.VmDao; public class LiveMigrateVmDisksCommandTest extends BaseCommandTest { private final Guid diskImageId = Guid.newGuid(); private final Guid diskImageGroupId = Guid.newGuid(); private final Guid srcStorageId = Guid.newGuid(); private final Guid dstStorageId = Guid.newGuid(); private final Guid vmId = Guid.newGuid(); private final Guid quotaId = Guid.newGuid(); private final Guid storagePoolId = Guid.newGuid(); private final Guid diskProfileId = Guid.newGuid(); private StoragePool storagePool; @Mock private DiskImageDao diskImageDao; @Mock private StorageDomainDao storageDomainDao; @Mock private StoragePoolDao storagePoolDao; @Mock private VmDao vmDao; @Mock protected SnapshotDao snapshotDao; @Mock private VmValidator vmValidator; @Mock private SnapshotsValidator snapshotsValidator; @Mock private DiskValidator diskValidator; @Mock private DiskVmElementValidator diskVmElementValidator; /** * The command under test */ @Spy @InjectMocks protected LiveMigrateVmDisksCommand<LiveMigrateVmDisksParameters> command = new LiveMigrateVmDisksCommand<>(new LiveMigrateVmDisksParameters(new ArrayList<>(), vmId), null); @Before public void setupCommand() { initSpyCommand(); initStoragePool(); mockValidators(); } private void initSpyCommand() { doReturn(true).when(command).validateDestDomainsSpaceRequirements(); doReturn(true).when(command).setAndValidateDiskProfiles(); doReturn(true).when(command).validateCreateAllSnapshotsFromVmCommand(); } private List<LiveMigrateDiskParameters> createLiveMigrateVmDisksParameters() { return Collections.singletonList(new LiveMigrateDiskParameters(diskImageId, srcStorageId, dstStorageId, vmId, quotaId, diskProfileId, diskImageGroupId)); } private List<LiveMigrateDiskParameters> createLiveMigrateVmDisksParameters(Guid srcStorageId, Guid dstStorageId) { return Collections.singletonList(new LiveMigrateDiskParameters(diskImageId, srcStorageId, dstStorageId, vmId, quotaId, diskProfileId, diskImageGroupId)); } private void createParameters() { command.getParameters().setParametersList(createLiveMigrateVmDisksParameters()); command.getParameters().setVmId(vmId); } private void createParameters(Guid srcStorageId, Guid dstStorageId) { command.getParameters().setParametersList(createLiveMigrateVmDisksParameters(srcStorageId, dstStorageId)); command.getParameters().setVmId(vmId); } @Test public void validateFailsWhenCreateAllSnapshotFromVmValidationFails() { createParameters(srcStorageId, dstStorageId); StorageDomain srcStorageDomain = initStorageDomain(srcStorageId); srcStorageDomain.setStatus(StorageDomainStatus.Active); StorageDomain dstStorageDomain = initStorageDomain(dstStorageId); dstStorageDomain.setStatus(StorageDomainStatus.Active); initDiskImage(diskImageGroupId, diskImageId); initVm(VMStatus.Up, Guid.newGuid(), diskImageGroupId); doReturn(false).when(command).validateCreateAllSnapshotsFromVmCommand(); assertFalse(command.validate()); } @Test public void validateNoDisksSpecified() { initVm(VMStatus.Up, Guid.newGuid(), null); assertFalse(command.validate()); assertTrue(command.getReturnValue() .getValidationMessages() .contains(EngineMessage.ACTION_TYPE_FAILED_NO_DISKS_SPECIFIED.toString())); } @Test public void validateVmShareableDisk() { createParameters(); DiskImage diskImage = initDiskImage(diskImageGroupId, diskImageId); diskImage.setShareable(true); initVm(VMStatus.Up, Guid.newGuid(), diskImageGroupId); assertFalse(command.validate()); assertTrue(command.getReturnValue() .getValidationMessages() .contains(EngineMessage.ACTION_TYPE_FAILED_SHAREABLE_DISK_NOT_SUPPORTED.toString())); } @Test public void validateMissingTemplateDisk() { createParameters(); DiskImage diskImage = initDiskImage(diskImageGroupId, diskImageId); Guid templateImageId = Guid.newGuid(); diskImage.setImageTemplateId(templateImageId); initDiskImage(Guid.newGuid(), templateImageId); initVm(VMStatus.Up, Guid.newGuid(), diskImageGroupId); assertFalse(command.validate()); assertTrue(command.getReturnValue() .getValidationMessages() .contains(EngineMessage.ACTION_TYPE_FAILED_TEMPLATE_NOT_FOUND_ON_DESTINATION_DOMAIN.toString())); } @Test public void validateInvalidDestinationDomain() { createParameters(); StorageDomain srcStorageDomain = initStorageDomain(srcStorageId); srcStorageDomain.setStatus(StorageDomainStatus.Active); StorageDomain dstStorageDomain = initStorageDomain(dstStorageId); dstStorageDomain.setStatus(StorageDomainStatus.Active); dstStorageDomain.setStorageDomainType(StorageDomainType.ISO); initDiskImage(diskImageGroupId, diskImageId); initVm(VMStatus.Up, Guid.newGuid(), diskImageGroupId); assertFalse(command.validate()); assertTrue(command.getReturnValue() .getValidationMessages() .contains(EngineMessage.ACTION_TYPE_FAILED_STORAGE_DOMAIN_TYPE_ILLEGAL.toString())); } @Test public void validateSameSourceAndDest() throws Exception { createParameters(srcStorageId, srcStorageId); StorageDomain srcStorageDomain = initStorageDomain(srcStorageId); srcStorageDomain.setStatus(StorageDomainStatus.Active); initDiskImage(diskImageGroupId, diskImageId); initVm(VMStatus.Up, Guid.newGuid(), diskImageGroupId); assertFalse(command.validate()); assertTrue(command.getReturnValue() .getValidationMessages() .contains(EngineMessage.ACTION_TYPE_FAILED_SOURCE_AND_TARGET_SAME.name())); } @Test public void validateFileToBlockSupported() { storagePool.setCompatibilityVersion(Version.v3_6); validateInvalidDestinationAndSourceDomainOfDifferentStorageSubtypes(StorageType.NFS, StorageType.ISCSI); } @Test public void validateBlockToFileSupported() { storagePool.setCompatibilityVersion(Version.v3_6); validateInvalidDestinationAndSourceDomainOfDifferentStorageSubtypes(StorageType.ISCSI, StorageType.NFS); } @Test public void validateBlockToBlock() { validateInvalidDestinationAndSourceDomainOfDifferentStorageSubtypes(StorageType.ISCSI, StorageType.ISCSI); } private void validateInvalidDestinationAndSourceDomainOfDifferentStorageSubtypes(StorageType sourceType, StorageType destType) { createParameters(); StorageDomain srcStorageDomain = initStorageDomain(srcStorageId); srcStorageDomain.setStatus(StorageDomainStatus.Active); srcStorageDomain.setStorageType(sourceType); StorageDomain dstStorageDomain = initStorageDomain(dstStorageId); dstStorageDomain.setStatus(StorageDomainStatus.Active); dstStorageDomain.setStorageType(destType); initDiskImage(diskImageGroupId, diskImageId); initVm(VMStatus.Up, Guid.newGuid(), diskImageGroupId); assertTrue(command.validate()); } @Test public void validateVmHavingDeviceSnapshotsPluggedToOtherVmsThatAreNotDown() { createParameters(); initDiskImage(diskImageGroupId, diskImageId); initVm(VMStatus.Up, Guid.newGuid(), diskImageGroupId); doReturn(new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_VM_IS_NOT_DOWN)).when(diskValidator) .isDiskPluggedToVmsThatAreNotDown(anyBoolean(), any()); assertFalse(command.validate()); assertTrue(command.getReturnValue() .getValidationMessages() .contains(EngineMessage.ACTION_TYPE_FAILED_VM_IS_NOT_DOWN.name())); } @Test public void validateFailsOnPassDiscardSupport() { createParameters(); initDiskImage(diskImageGroupId, diskImageId); initVm(VMStatus.Up, Guid.newGuid(), diskImageGroupId); StorageDomain srcSd = initStorageDomain(srcStorageId); srcSd.setStatus(StorageDomainStatus.Active); StorageDomain dstSd = initStorageDomain(dstStorageId); dstSd.setStatus(StorageDomainStatus.Active); when(diskVmElementValidator.isPassDiscardSupported(any(Guid.class))).thenReturn( new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_PASS_DISCARD_NOT_SUPPORTED_BY_DISK_INTERFACE)); ValidateTestUtils.runAndAssertValidateFailure(command, EngineMessage.ACTION_TYPE_FAILED_PASS_DISCARD_NOT_SUPPORTED_BY_DISK_INTERFACE); } @Test public void passDiscardNotSupportedOnDestSd() { Guid dstSd = Guid.newGuid(); when(diskVmElementValidator.isPassDiscardSupported(dstSd)).thenReturn( new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_PASS_DISCARD_NOT_SUPPORTED_BY_DISK_INTERFACE)); assertFalse(command.validatePassDiscardSupportedOnDestinationStorageDomain( new LiveMigrateDiskParameters(Guid.newGuid(), Guid.newGuid(), dstSd, Guid.newGuid(), Guid.newGuid(), Guid.newGuid(), Guid.newGuid()))); } /** Initialize Entities */ private void initVm(VMStatus vmStatus, Guid runOnVds, Guid diskImageId) { VM vm = new VM(); vm.setStatus(vmStatus); vm.setRunOnVds(runOnVds); vm.setStoragePoolId(storagePoolId); doReturn(vm).when(command).getVm(); when(vmDao.get(any(Guid.class))).thenReturn(vm); when(vmDao.getVmsListForDisk(diskImageId, Boolean.FALSE)).thenReturn(Collections.singletonList(vm)); } private DiskImage initDiskImage(Guid diskImageGroupId, Guid diskImageId) { DiskImage diskImage = new DiskImage(); diskImage.setId(diskImageGroupId); diskImage.getImage().setId(diskImageId); diskImage.setStoragePoolId(storagePoolId); diskImage.setStorageIds(new ArrayList<>(Collections.singletonList(srcStorageId))); when(diskImageDao.getAncestor(diskImageId)).thenReturn(diskImage); when(diskImageDao.get(diskImageId)).thenReturn(diskImage); return diskImage; } private StorageDomain initStorageDomain(Guid storageDomainId) { 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); return storageDomain; } private void initStoragePool() { storagePool = new StoragePool(); when(storagePoolDao.get(any(Guid.class))).thenReturn(storagePool); when(command.getStoragePoolId()).thenReturn(storagePoolId); } /** Mock Daos */ private void mockValidators() { doReturn(vmValidator).when(command).createVmValidator(); doReturn(diskValidator).when(command).createDiskValidator(any()); doReturn(diskVmElementValidator).when(command).createDiskVmElementValidator(any(), any()); } }