package org.ovirt.engine.core.bll.storage.disk; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; 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.Collections; import java.util.List; 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.storage.MultipleDiskVmElementValidator; import org.ovirt.engine.core.bll.validator.storage.StorageDomainValidator; import org.ovirt.engine.core.common.action.MoveOrCopyImageGroupParameters; import org.ovirt.engine.core.common.businessentities.StorageDomain; import org.ovirt.engine.core.common.businessentities.StorageDomainStatus; 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.VmEntityType; import org.ovirt.engine.core.common.businessentities.VmTemplate; import org.ovirt.engine.core.common.businessentities.storage.CinderDisk; import org.ovirt.engine.core.common.businessentities.storage.Disk; import org.ovirt.engine.core.common.businessentities.storage.DiskContentType; import org.ovirt.engine.core.common.businessentities.storage.DiskImage; import org.ovirt.engine.core.common.businessentities.storage.ImageOperation; import org.ovirt.engine.core.common.businessentities.storage.ImageStatus; import org.ovirt.engine.core.common.businessentities.storage.LunDisk; import org.ovirt.engine.core.common.businessentities.storage.StorageType; import org.ovirt.engine.core.common.errors.EngineMessage; import org.ovirt.engine.core.common.utils.Pair; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.dao.DiskDao; import org.ovirt.engine.core.dao.DiskImageDao; import org.ovirt.engine.core.dao.DiskVmElementDao; import org.ovirt.engine.core.dao.StorageDomainDao; import org.ovirt.engine.core.dao.VmDao; import org.ovirt.engine.core.dao.VmDeviceDao; public class MoveOrCopyDiskCommandTest extends BaseCommandTest { private final Guid diskImageGuid = Guid.newGuid(); private Guid destStorageId = Guid.newGuid(); private final Guid srcStorageId = Guid.newGuid(); private final VmDevice vmDevice = new VmDevice(); @Mock private DiskDao diskDao; @Mock private DiskImageDao diskImageDao; @Mock private StorageDomainDao storageDomainDao; @Mock private VmDao vmDao; @Mock private VmDeviceDao vmDeviceDao; @Mock private DiskVmElementDao diskVmElementDao; @Mock private SnapshotsValidator snapshotsValidator; /** * The command under test. */ @Spy @InjectMocks protected MoveOrCopyDiskCommand<MoveOrCopyImageGroupParameters> command = new MoveOrCopyDiskCommand<>(new MoveOrCopyImageGroupParameters(diskImageGuid, srcStorageId, destStorageId, ImageOperation.Move), null); @Test public void validateImageNotFound() throws Exception { initializeCommand(new DiskImage()); assertFalse(command.validate()); assertTrue(command.getReturnValue() .getValidationMessages() .contains(EngineMessage.ACTION_TYPE_FAILED_DISK_NOT_EXIST.toString())); } @Test public void validateWrongDiskImageTypeTemplate() throws Exception { initializeCommand(new DiskImage()); initTemplateDiskImage(); assertFalse(command.validate()); assertTrue(command.getReturnValue() .getValidationMessages() .contains(EngineMessage.ACTION_TYPE_FAILED_DISK_IS_NOT_VM_DISK.toString())); } @Test public void moveShareableDiskToGlusterDomain() { initializeCommand(new DiskImage()); initSrcStorageDomain(); initDestStorageDomain(StorageType.GLUSTERFS); initVmDiskImage(true); assertFalse(command.validate()); assertTrue(command.getReturnValue() .getValidationMessages() .contains(EngineMessage.ACTION_TYPE_FAILED_CANT_MOVE_SHAREABLE_DISK_TO_GLUSTERFS.toString())); } @Test public void moveShareableDisk() { initializeCommand(new DiskImage()); initSrcStorageDomain(); initDestStorageDomain(StorageType.NFS); initVmDiskImage(true); assertTrue(command.validate()); } @Test public void moveDiskToGluster() { initializeCommand(new DiskImage()); initSrcStorageDomain(); initDestStorageDomain(StorageType.GLUSTERFS); initVmDiskImage(false); assertTrue(command.validate()); } @Test public void validateSameSourceAndDest() throws Exception { destStorageId = srcStorageId; initializeCommand(new DiskImage()); command.getParameters().setStorageDomainId(destStorageId); command.setStorageDomainId(destStorageId); initVmDiskImage(false); mockGetVmsListForDisk(); initSrcStorageDomain(); assertFalse(command.validate()); assertTrue(command.getReturnValue() .getValidationMessages() .contains(EngineMessage.ACTION_TYPE_FAILED_SOURCE_AND_TARGET_SAME.toString())); } @Test public void validateVmIsNotDown() throws Exception { initializeCommand(new DiskImage()); initVmDiskImage(false); mockGetVmsListForDisk(); initSrcStorageDomain(); initDestStorageDomain(StorageType.NFS); assertFalse(command.validate()); assertTrue(command.getReturnValue() .getValidationMessages() .contains(EngineMessage.ACTION_TYPE_FAILED_VM_IS_NOT_DOWN.toString())); } @Test public void validateDiskIsLocked() throws Exception { initializeCommand(new DiskImage()); initVmDiskImage(false); mockGetVmsListForDisk(); command.getImage().setImageStatus(ImageStatus.LOCKED); assertFalse(command.validate()); assertTrue(command.getReturnValue().getValidationMessages().contains( EngineMessage.ACTION_TYPE_FAILED_DISKS_LOCKED.toString())); } @Test public void validateDiskIsOvfStore() throws Exception { initializeCommand(new DiskImage()); initVmDiskImage(false); command.getImage().setContentType(DiskContentType.OVF_STORE); ValidateTestUtils.runAndAssertValidateFailure(command, EngineMessage.ACTION_TYPE_FAILED_OVF_DISK_NOT_SUPPORTED); } @Test public void validateTemplateImageIsLocked() throws Exception { initializeCommand(new DiskImage()); command.getParameters().setOperation(ImageOperation.Copy); command.init(); initTemplateDiskImage(); command.getImage().setImageStatus(ImageStatus.LOCKED); doReturn(new VmTemplate()).when(command).getTemplateForImage(); command.init(); assertFalse(command.validate()); assertTrue(command.getReturnValue().getValidationMessages().contains( EngineMessage.VM_TEMPLATE_IMAGE_IS_LOCKED.toString())); } @Test public void validateNotEnoughSpace() throws Exception { initializeCommand(new DiskImage()); initVmForSpace(); initVmDiskImage(false); initSrcStorageDomain(); initDestStorageDomain(StorageType.NFS); doReturn(mockStorageDomainValidatorWithoutSpace()).when(command).createStorageDomainValidator(); ValidateTestUtils.runAndAssertValidateFailure(command, EngineMessage.ACTION_TYPE_FAILED_DISK_SPACE_LOW_ON_STORAGE_DOMAIN); } @Test public void validateEnoughSpace() throws Exception { initializeCommand(new DiskImage()); initVmForSpace(); initVmDiskImage(false); initSrcStorageDomain(); initDestStorageDomain(StorageType.NFS); doReturn(mockStorageDomainValidator()).when(command).createStorageDomainValidator(); ValidateTestUtils.runAndAssertValidateSuccess(command); } @Test public void successVmInPreviewForAttachedSnapshot() { initializeCommand(new DiskImage()); initVmForSpace(); initVmDiskImage(false); initSrcStorageDomain(); initDestStorageDomain(StorageType.NFS); vmDevice.setSnapshotId(Guid.newGuid()); ValidateTestUtils.runAndAssertValidateSuccess(command); } @Test public void validateVmInPreview() { initializeCommand(new DiskImage()); initVmForSpace(); initVmDiskImage(false); initSrcStorageDomain(); initDestStorageDomain(StorageType.NFS); when(snapshotsValidator.vmNotInPreview(any())).thenReturn(new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_VM_IN_PREVIEW)); ValidateTestUtils.runAndAssertValidateFailure(command, EngineMessage.ACTION_TYPE_FAILED_VM_IN_PREVIEW); } @Test public void validateFailureOnMovingLunDisk() { initializeCommand(new LunDisk()); ValidateTestUtils.runAndAssertValidateFailure(command, EngineMessage.ACTION_TYPE_FAILED_NOT_SUPPORTED_DISK_STORAGE_TYPE); } @Test public void validateFailureOnCopyingLunDisk() { initializeCommand(new LunDisk()); command.getParameters().setOperation(ImageOperation.Copy); command.init(); ValidateTestUtils.runAndAssertValidateFailure(command, EngineMessage.ACTION_TYPE_FAILED_NOT_SUPPORTED_DISK_STORAGE_TYPE); } @Test public void validateFailureOnMovingVmLunDisk() { initializeCommand(new LunDisk()); vmDevice.setSnapshotId(Guid.newGuid()); ValidateTestUtils.runAndAssertValidateFailure(command, EngineMessage.ACTION_TYPE_FAILED_NOT_SUPPORTED_DISK_STORAGE_TYPE); } @Test public void validateFailureOnMovingCinderDisk() { initializeCommand(new CinderDisk()); ValidateTestUtils.runAndAssertValidateFailure(command, EngineMessage.ACTION_TYPE_FAILED_NOT_SUPPORTED_DISK_STORAGE_TYPE); } @Test public void validateFailureOnCopyingCinderDisk() { initializeCommand(new CinderDisk()); command.getParameters().setOperation(ImageOperation.Copy); command.init(); ValidateTestUtils.runAndAssertValidateFailure(command, EngineMessage.ACTION_TYPE_FAILED_NOT_SUPPORTED_DISK_STORAGE_TYPE); } @Test public void passDiscardSupportedForDestSdMoveOp() { initializeCommand(new DiskImage()); mockPassDiscardSupportedForDestSd(ValidationResult.VALID, ImageOperation.Move); assertTrue(command.validatePassDiscardSupportedForDestinationStorageDomain()); } @Test public void passDiscardSupportedForDestSdCopyTemplateDiskOp() { initializeCommand(new DiskImage()); mockPassDiscardSupportedForDestSd(ValidationResult.VALID, ImageOperation.Copy); initTemplateDiskImage(); assertTrue(command.validatePassDiscardSupportedForDestinationStorageDomain()); } @Test public void passDiscardSupportedForCopyFloatingDiskOp() { initializeCommand(new DiskImage()); command.getParameters().setOperation(ImageOperation.Copy); initTemplateDiskImage(); assertTrue(command.validatePassDiscardSupportedForDestinationStorageDomain()); } @Test public void passDiscardNotSupportedForDestSd() { initializeCommand(new DiskImage()); mockPassDiscardSupportedForDestSd(new ValidationResult( EngineMessage.ACTION_TYPE_FAILED_PASS_DISCARD_NOT_SUPPORTED_BY_DISK_INTERFACE), ImageOperation.Move); assertFalse(command.validatePassDiscardSupportedForDestinationStorageDomain()); } protected void initVmForSpace() { VM vm = new VM(); vm.setStatus(VMStatus.Down); // Re-mock the vmDao to return this specific VM for it to be correlated with the vm list mocked by getVmsWithPlugInfo(..). when(vmDao.get(any())).thenReturn(vm); List<Pair<VM, VmDevice>> vmList = Collections.singletonList(new Pair<>(vm, vmDevice)); when(vmDao.getVmsWithPlugInfo(any())).thenReturn(vmList); } private void mockGetVmsListForDisk() { List<Pair<VM, VmDevice>> vmList = new ArrayList<>(); VM vm1 = new VM(); vm1.setStatus(VMStatus.PoweringDown); VM vm2 = new VM(); vm2.setStatus(VMStatus.Down); VmDevice device1 = new VmDevice(); device1.setPlugged(true); VmDevice device2 = new VmDevice(); device2.setPlugged(true); vmList.add(new Pair<>(vm1, device1)); vmList.add(new Pair<>(vm2, device2)); when(vmDao.getVmsWithPlugInfo(any())).thenReturn(vmList); } private static StorageDomainValidator mockStorageDomainValidatorWithoutSpace() { StorageDomainValidator storageDomainValidator = mockStorageDomainValidator(); when(storageDomainValidator.hasSpaceForDiskWithSnapshots(any(DiskImage.class))).thenReturn( new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_DISK_SPACE_LOW_ON_STORAGE_DOMAIN)); return storageDomainValidator; } private static StorageDomainValidator mockStorageDomainValidator() { return mock(StorageDomainValidator.class); } private void initSrcStorageDomain() { StorageDomain stDomain = new StorageDomain(); stDomain.setStatus(StorageDomainStatus.Active); when(storageDomainDao.getForStoragePool(any(), any())).thenReturn(stDomain); } private void initDestStorageDomain(StorageType storageType) { StorageDomain destDomain = new StorageDomain(); destDomain.setStorageType(storageType); destDomain.setStatus(StorageDomainStatus.Active); doReturn(destDomain).when(command).getStorageDomain(); } protected void initializeCommand(Disk disk) { when(diskDao.get(any())).thenReturn(disk); VM vm = new VM(); vm.setStatus(VMStatus.Down); when(vmDao.get(any())).thenReturn(vm); doReturn(mockStorageDomainValidator()).when(command).createStorageDomainValidator(); doReturn(true).when(command).setAndValidateDiskProfiles(); doReturn(disk.getId()).when(command).getImageGroupId(); } private void initTemplateDiskImage() { DiskImage diskImage = new DiskImage(); diskImage.setVmEntityType(VmEntityType.TEMPLATE); when(diskImageDao.get(any(Guid.class))).thenReturn(diskImage); } private void initVmDiskImage(boolean isShareable) { DiskImage diskImage = new DiskImage(); diskImage.setVmEntityType(VmEntityType.VM); diskImage.setShareable(isShareable); when(diskImageDao.get(any(Guid.class))).thenReturn(diskImage); } private void mockPassDiscardSupportedForDestSd(ValidationResult validationResult, ImageOperation imageOperation) { command.getParameters().setOperation(imageOperation); MultipleDiskVmElementValidator multipleDiskVmElementValidator = mock(MultipleDiskVmElementValidator.class); doReturn(multipleDiskVmElementValidator).when(command).createMultipleDiskVmElementValidator(); when(multipleDiskVmElementValidator.isPassDiscardSupportedForDestSd(any(Guid.class))) .thenReturn(validationResult); } }