package org.ovirt.engine.core.bll.storage.disk;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doCallRealMethod;
import static org.mockito.Mockito.doNothing;
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 static org.ovirt.engine.core.utils.MockConfigRule.mockConfig;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import org.junit.ClassRule;
import org.junit.Rule;
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.context.CommandContext;
import org.ovirt.engine.core.bll.interfaces.BackendInternal;
import org.ovirt.engine.core.bll.quota.QuotaManager;
import org.ovirt.engine.core.bll.quota.QuotaStorageConsumptionParameter;
import org.ovirt.engine.core.bll.snapshots.SnapshotsValidator;
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.StorageDomainParametersBase;
import org.ovirt.engine.core.common.action.VdcActionType;
import org.ovirt.engine.core.common.action.VdcReturnValueBase;
import org.ovirt.engine.core.common.action.VmDiskOperationParameterBase;
import org.ovirt.engine.core.common.businessentities.Quota;
import org.ovirt.engine.core.common.businessentities.StorageDomain;
import org.ovirt.engine.core.common.businessentities.StorageDomainStatus;
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.VmDevice;
import org.ovirt.engine.core.common.businessentities.VmDeviceGeneralType;
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.DiskContentType;
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.businessentities.storage.ImageStatus;
import org.ovirt.engine.core.common.businessentities.storage.QcowCompat;
import org.ovirt.engine.core.common.businessentities.storage.StorageType;
import org.ovirt.engine.core.common.businessentities.storage.VolumeFormat;
import org.ovirt.engine.core.common.config.ConfigValues;
import org.ovirt.engine.core.common.errors.EngineMessage;
import org.ovirt.engine.core.common.osinfo.OsRepository;
import org.ovirt.engine.core.common.utils.Pair;
import org.ovirt.engine.core.common.utils.SimpleDependencyInjector;
import org.ovirt.engine.core.common.utils.SizeConverter;
import org.ovirt.engine.core.common.utils.VmDeviceType;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.core.compat.Version;
import org.ovirt.engine.core.dao.BaseDiskDao;
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.ImageDao;
import org.ovirt.engine.core.dao.QuotaDao;
import org.ovirt.engine.core.dao.StorageDomainDao;
import org.ovirt.engine.core.dao.StorageDomainStaticDao;
import org.ovirt.engine.core.dao.StoragePoolDao;
import org.ovirt.engine.core.dao.VmDao;
import org.ovirt.engine.core.dao.VmDeviceDao;
import org.ovirt.engine.core.dao.VmStaticDao;
import org.ovirt.engine.core.utils.MockConfigRule;
import org.ovirt.engine.core.utils.RandomUtils;
import org.ovirt.engine.core.utils.RandomUtilsSeedingRule;
public class UpdateVmDiskCommandTest extends BaseCommandTest {
private Guid diskImageGuid = Guid.newGuid();
private Guid vmId = Guid.newGuid();
private Guid sdId = Guid.newGuid();
private Guid spId = Guid.newGuid();
@Mock
private VmDao vmDao;
@Mock
private DiskDao diskDao;
@Mock
private VmStaticDao vmStaticDao;
@Mock
private BaseDiskDao baseDiskDao;
@Mock
private ImageDao imageDao;
@Mock
private DiskImageDao diskImageDao;
@Mock
private VmDeviceDao vmDeviceDao;
@Mock
private StoragePoolDao storagePoolDao;
@Mock
private StorageDomainStaticDao storageDomainStaticDao;
@Mock
private StorageDomainDao storageDomainDao;
@Mock
private QuotaDao quotaDao;
@Mock
private DiskValidator diskValidator;
@Mock
private SnapshotsValidator snapshotsValidator;
@Mock
private DiskVmElementValidator diskVmElementValidator;
@Mock
private DiskVmElementDao diskVmElementDao;
@Mock
private OsRepository osRepository;
@Mock
private QuotaManager quotaManager;
@Mock
private BackendInternal backend;
@Rule
public RandomUtilsSeedingRule rusr = new RandomUtilsSeedingRule();
@ClassRule
public static MockConfigRule mcr = new MockConfigRule(
mockConfig(ConfigValues.PassDiscardSupported, Version.v4_0, false));
/**
* The command under test.
*/
@Spy
@InjectMocks
private UpdateVmDiskCommand<VmDiskOperationParameterBase> command =
new UpdateVmDiskCommand<>(createParameters(), CommandContext.createContext(""));
@Test
public void validateFailedVMNotFound() throws Exception {
initializeCommand();
mockNullVm();
ValidateTestUtils.runAndAssertValidateFailure(command, EngineMessage.ACTION_TYPE_FAILED_VM_NOT_FOUND);
}
@Test
public void validateFailedVMHasNotDisk() throws Exception {
initializeCommand();
createNullDisk();
doReturn(new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_DISK_NOT_EXIST)).
when(diskValidator).isDiskExists();
ValidateTestUtils.runAndAssertValidateFailure(command, EngineMessage.ACTION_TYPE_FAILED_DISK_NOT_EXIST);
}
@Test
public void validateFailedShareableDiskVolumeFormatUnsupported() throws Exception {
DiskImage disk = createShareableDisk(VolumeFormat.COW);
StorageDomain storage = addNewStorageDomainToDisk(disk, StorageType.NFS);
command.getParameters().setDiskInfo(disk);
when(diskDao.get(diskImageGuid)).thenReturn(createDiskImage());
when(storageDomainStaticDao.get(storage.getId())).thenReturn(storage.getStorageStaticData());
initializeCommand();
ValidateTestUtils.runAndAssertValidateFailure(command,
EngineMessage.SHAREABLE_DISK_IS_NOT_SUPPORTED_BY_VOLUME_FORMAT);
}
@Test
public void validateFailedUpdateReadOnly() {
when(diskDao.get(diskImageGuid)).thenReturn(createDiskImage());
command.getParameters().getDiskVmElement().setReadOnly(true);
initializeCommand(createVm(VMStatus.Up));
ValidateTestUtils.runAndAssertValidateFailure(command, EngineMessage.ACTION_TYPE_FAILED_VM_IS_NOT_DOWN);
}
@Test
public void validateFailedROVmAttachedToPool() {
when(diskDao.get(diskImageGuid)).thenReturn(createDiskImage());
command.getParameters().getDiskVmElement().setReadOnly(true);
VM vm = createVm(VMStatus.Down);
vm.setVmPoolId(Guid.newGuid());
initializeCommand(vm);
VmDevice vmDevice = stubVmDevice(diskImageGuid, vmId); // Default RO is false
ValidateTestUtils.runAndAssertValidateFailure(command, EngineMessage.ACTION_TYPE_FAILED_VM_ATTACHED_TO_POOL);
vmDevice.setReadOnly(true);
command.getParameters().getDiskVmElement().setReadOnly(false);
ValidateTestUtils.runAndAssertValidateFailure(command,
EngineMessage.ACTION_TYPE_FAILED_VM_ATTACHED_TO_POOL);
}
@Test
public void validateFailedWipeVmAttachedToPool() {
Disk oldDisk = createDiskImage();
oldDisk.setWipeAfterDelete(true);
when(diskDao.get(diskImageGuid)).thenReturn(oldDisk);
command.getParameters().getDiskInfo().setWipeAfterDelete(false);
VM vm = createVm(VMStatus.Down);
vm.setVmPoolId(Guid.newGuid());
initializeCommand(vm);
ValidateTestUtils.runAndAssertValidateFailure(command,
EngineMessage.ACTION_TYPE_FAILED_VM_ATTACHED_TO_POOL);
oldDisk.setWipeAfterDelete(false);
command.getParameters().getDiskInfo().setWipeAfterDelete(true);
ValidateTestUtils.runAndAssertValidateFailure(command,
EngineMessage.ACTION_TYPE_FAILED_VM_ATTACHED_TO_POOL);
}
@Test
public void validateFailedShareableDiskOnGlusterDomain() throws Exception {
DiskImage disk = createShareableDisk(VolumeFormat.RAW);
StorageDomain storage = addNewStorageDomainToDisk(disk, StorageType.GLUSTERFS);
command.getParameters().setDiskInfo(disk);
when(diskDao.get(diskImageGuid)).thenReturn(createDiskImage());
when(storageDomainStaticDao.get(storage.getId())).thenReturn(storage.getStorageStaticData());
initializeCommand();
ValidateTestUtils.runAndAssertValidateFailure(command,
EngineMessage.ACTION_TYPE_FAILED_SHAREABLE_DISKS_NOT_SUPPORTED_ON_GLUSTER_DOMAIN);
}
@Test
public void nullifiedSnapshotOnUpdateDiskToShareable() {
DiskImage disk = createShareableDisk(VolumeFormat.RAW);
StorageDomain storage = addNewStorageDomainToDisk(disk, StorageType.NFS);
command.getParameters().setDiskInfo(disk);
DiskImage oldDisk = createDiskImage();
oldDisk.setVmSnapshotId(Guid.newGuid());
when(diskDao.get(diskImageGuid)).thenReturn(oldDisk);
when(storageDomainStaticDao.get(storage.getId())).thenReturn(storage.getStorageStaticData());
initializeCommand();
mockVdsCommandSetVolumeDescription();
mockInterfaceList();
ValidateTestUtils.runAndAssertValidateSuccess(command);
command.executeVmCommand();
assertNull(oldDisk.getVmSnapshotId());
}
@Test
public void validateMakeDiskBootableSuccess() {
validateMakeDiskBootable(false);
}
@Test
public void validateMakeDiskBootableFail() {
validateMakeDiskBootable(true);
}
private void validateMakeDiskBootable(boolean boot) {
command.getParameters().getDiskVmElement().setBoot(true);
DiskImage otherDisk = new DiskImage();
otherDisk.setId(Guid.newGuid());
otherDisk.setActive(true);
when(diskValidator.isVmNotContainsBootDisk(createVm(VMStatus.Down))).
thenReturn(boot ? new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_DISK_BOOT_IN_USE) : ValidationResult.VALID);
when(diskDao.get(diskImageGuid)).thenReturn(createDiskImage());
initializeCommand();
mockInterfaceList();
// The command should only succeed if there is no other bootable disk
assertEquals(!boot, command.validate());
}
@Test
public void validateUpdateWipeAfterDeleteVmDown() {
validateUpdateWipeAfterDelete(VMStatus.Down);
}
@Test
public void validateUpdateWipeAfterDeleteVmUp() {
validateUpdateWipeAfterDelete(VMStatus.Up);
}
private void validateUpdateWipeAfterDelete(VMStatus status) {
DiskImage disk = createDiskImage();
when(diskDao.get(diskImageGuid)).thenReturn(disk);
command.getParameters().getDiskInfo().setWipeAfterDelete(true);
initializeCommand(createVm(status));
ValidateTestUtils.runAndAssertValidateSuccess(command);
}
@Test
public void validateUpdateDescriptionVmDown() {
validateUpdateDescription(VMStatus.Down);
}
@Test
public void validateUpdateDescriptionVmUp() {
validateUpdateDescription(VMStatus.Up);
}
private void validateUpdateDescription(VMStatus status) {
DiskImage disk = createDiskImage();
when(diskDao.get(diskImageGuid)).thenReturn(disk);
disk.setDescription(RandomUtils.instance().nextString(10));
initializeCommand(createVm(status));
ValidateTestUtils.runAndAssertValidateSuccess(command);
}
@Test
public void clearAddressOnInterfaceChange() {
// update new disk interface so it will be different than the old one
command.getParameters().getDiskVmElement().setDiskInterface(DiskInterface.VirtIO);
DiskImage diskFromDb = createDiskImage();
doReturn(diskFromDb).when(diskDao).get(diskImageGuid);
initializeCommand();
DiskVmElement dve = new DiskVmElement(diskImageGuid, vmId);
dve.setDiskInterface(DiskInterface.IDE);
doReturn(dve).when(command).getOldDiskVmElement();
mockVdsCommandSetVolumeDescription();
assertNotSame(dve.getDiskInterface(), command.getParameters().getDiskVmElement().getDiskInterface());
command.executeVmCommand();
// verify that device address was cleared exactly once
verify(vmDeviceDao).clearDeviceAddress(diskImageGuid);
}
private void mockVdsCommandSetVolumeDescription() {
doNothing().when(command).setVolumeDescription(any(DiskImage.class), any(StorageDomain.class));
}
@Test
public void testUpdateReadOnlyPropertyOnChange() {
// Disk should be updated as Read Only
command.getParameters().getDiskVmElement().setReadOnly(true);
when(diskDao.get(diskImageGuid)).thenReturn(createDiskImage());
initializeCommand();
stubVmDevice(diskImageGuid, vmId);
mockVdsCommandSetVolumeDescription();
command.executeVmCommand();
verify(command, atLeast(1)).updateReadOnlyRequested();
assertTrue(command.updateReadOnlyRequested());
verify(vmDeviceDao).update(any(VmDevice.class));
}
@Test
public void testUpdateDiskInterfaceUnsupported() {
command.getParameters().getDiskVmElement().setDiskInterface(DiskInterface.IDE);
initializeCommand();
mockVdsCommandSetVolumeDescription();
DiskVmElement dve = new DiskVmElement(diskImageGuid, vmId);
dve.setDiskInterface(DiskInterface.VirtIO);
doReturn(dve).when(command).getOldDiskVmElement();
doReturn(createDiskImage()).when(command).getOldDisk();
stubVmDevice(diskImageGuid, vmId);
when(diskVmElementValidator.isDiskInterfaceSupported(any(VM.class))).thenReturn(new ValidationResult(EngineMessage.ACTION_TYPE_DISK_INTERFACE_UNSUPPORTED));
when(command.getDiskValidator(command.getParameters().getDiskInfo())).thenReturn(diskValidator);
ValidateTestUtils.runAndAssertValidateFailure(command, EngineMessage.ACTION_TYPE_DISK_INTERFACE_UNSUPPORTED);
}
@Test
public void testDoNotUpdateDeviceWhenReadOnlyIsNotChanged() {
command.getParameters().getDiskVmElement().setReadOnly(false);
when(diskDao.get(diskImageGuid)).thenReturn(createDiskImage());
initializeCommand();
mockVdsCommandSetVolumeDescription();
command.executeVmCommand();
verify(command, atLeast(1)).updateReadOnlyRequested();
assertFalse(command.updateReadOnlyRequested());
verify(vmDeviceDao, never()).update(any(VmDevice.class));
}
@Test
public void testFailInterfaceCanUpdateReadOnly() {
initializeCommand();
doReturn(true).when(command).updateReadOnlyRequested();
doReturn(new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_INTERFACE_DOES_NOT_SUPPORT_READ_ONLY_ATTR)).
when(diskVmElementValidator).isReadOnlyPropertyCompatibleWithInterface();
assertFalse(command.validateCanUpdateReadOnly());
}
@Test
public void testSucceedInterfaceCanUpdateReadOnly() {
initializeCommand();
doReturn(true).when(command).updateReadOnlyRequested();
assertTrue(command.validateCanUpdateReadOnly());
}
@Test
public void testUpdateOvfDiskNotSupported() {
DiskImage updatedDisk = createDiskImage();
updatedDisk.setDiskAlias("Iron");
DiskImage diskFromDB = createDiskImage();
diskFromDB.setDiskAlias("Maiden");
diskFromDB.setContentType(DiskContentType.OVF_STORE);
when(diskDao.get(diskImageGuid)).thenReturn(diskFromDB);
initializeCommand();
doReturn(new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_OVF_DISK_NOT_SUPPORTED)).
when(diskValidator).isDiskUsedAsOvfStore();
ValidateTestUtils.runAndAssertValidateFailure(command,
EngineMessage.ACTION_TYPE_FAILED_OVF_DISK_NOT_SUPPORTED);
}
@Test
public void testResize() {
DiskImage oldDisk = createDiskImage();
when(diskDao.get(diskImageGuid)).thenReturn(oldDisk);
((DiskImage) command.getParameters().getDiskInfo()).setSize(oldDisk.getSize() * 2L);
initializeCommand();
assertTrue(command.validateCanResizeDisk());
}
@Test
public void testAmend() {
DiskImage oldDisk = createDiskImage();
oldDisk.setVolumeFormat(VolumeFormat.COW);
oldDisk.setQcowCompat(QcowCompat.QCOW2_V2);
oldDisk.setDiskAlias("Test");
oldDisk.setDiskDescription("Test_Desc");
when(diskDao.get(diskImageGuid)).thenReturn(oldDisk);
DiskImage newDisk = DiskImage.copyOf(oldDisk);
newDisk.setQcowCompat(QcowCompat.QCOW2_V3);
command.getParameters().setDiskInfo(newDisk);
initializeCommand();
mockVdsCommandSetVolumeDescription();
command.executeVmCommand();
verify(command, times(1)).amendDiskImage();
}
@Test
public void testAmendWithPropertyChange() {
DiskImage oldDisk = createDiskImage();
oldDisk.setVolumeFormat(VolumeFormat.COW);
oldDisk.setQcowCompat(QcowCompat.QCOW2_V2);
oldDisk.setDiskAlias("Test");
oldDisk.setDiskDescription("Test_Desc");
when(diskDao.get(diskImageGuid)).thenReturn(oldDisk);
DiskImage newDisk = DiskImage.copyOf(oldDisk);
newDisk.setQcowCompat(QcowCompat.QCOW2_V3);
newDisk.setDiskAlias("New Disk Alias");
command.getParameters().setDiskInfo(newDisk);
initializeCommand();
mockVdsCommandSetVolumeDescription();
command.executeVmCommand();
verify(command, times(1)).amendDiskImage();
verify(command, times(1)).setVolumeDescription(any(DiskImage.class), any(StorageDomain.class));
}
@Test
public void testAmendFailedWithPropertyChange() {
DiskImage oldDisk = createDiskImage();
oldDisk.setVolumeFormat(VolumeFormat.COW);
oldDisk.setQcowCompat(QcowCompat.QCOW2_V2);
oldDisk.setDiskAlias("Test");
oldDisk.setDiskDescription("Test_Desc");
when(diskDao.get(diskImageGuid)).thenReturn(oldDisk);
DiskImage newDisk = DiskImage.copyOf(oldDisk);
newDisk.setQcowCompat(QcowCompat.QCOW2_V3);
newDisk.setDiskAlias("New Disk Alias");
command.getParameters().setDiskInfo(newDisk);
initializeCommand();
VdcReturnValueBase ret = new VdcReturnValueBase();
ret.setSucceeded(false);
ArrayList<String> msgList = new ArrayList<>();
msgList.add(EngineMessage.ACTION_TYPE_FAILED_AMEND_NOT_SUPPORTED_BY_DC_VERSION.toString());
ret.setValidationMessages(msgList);
when(backend.runInternalAction(eq(VdcActionType.AmendImageGroupVolumes), any(StorageDomainParametersBase.class), any(CommandContext.class))).thenReturn(ret);
mockVdsCommandSetVolumeDescription();
command.executeVmCommand();
verify(command, times(1)).amendDiskImage();
verify(command, times(1)).setVolumeDescription(any(DiskImage.class), any(StorageDomain.class));
}
@Test
public void testAmendNotRunningWithExtend() {
Guid quotaId = Guid.newGuid();
DiskImage oldDiskImage = createDiskImage();
oldDiskImage.setQuotaId(quotaId);
oldDiskImage.setSize(SizeConverter.convert(3L, SizeConverter.SizeUnit.GiB,
SizeConverter.SizeUnit.BYTES).longValue());
oldDiskImage.setVolumeFormat(VolumeFormat.COW);
oldDiskImage.setQcowCompat(QcowCompat.QCOW2_V2);
DiskImage newDiskImage = createDiskImage();
newDiskImage.setQuotaId(quotaId);
newDiskImage.setSize(SizeConverter.convert(5L, SizeConverter.SizeUnit.GiB,
SizeConverter.SizeUnit.BYTES).longValue());
newDiskImage.setVolumeFormat(VolumeFormat.COW);
newDiskImage.setQcowCompat(QcowCompat.QCOW2_V3);
command.getParameters().setDiskVmElement(new DiskVmElement(newDiskImage.getId(), vmId));
command.getParameters().setDiskInfo(newDiskImage);
when(diskDao.get(diskImageGuid)).thenReturn(oldDiskImage);
initializeCommand();
assertTrue(command.amendDiskRequested());
verify(command, times(0)).amendDiskImage();
}
@Test
public void testFaultyResize() {
when(diskDao.get(diskImageGuid)).thenReturn(createDiskImage());
((DiskImage) command.getParameters().getDiskInfo()).setSize(command.getParameters().getDiskInfo().getSize() / 2L);
initializeCommand();
assertFalse(command.validateCanResizeDisk());
ValidateTestUtils.assertValidationMessages
("wrong failure", command, EngineMessage.ACTION_TYPE_FAILED_REQUESTED_DISK_SIZE_IS_TOO_SMALL);
}
@Test
public void testFailedRoDiskResize() {
((DiskImage) command.getParameters().getDiskInfo()).setSize(command.getParameters().getDiskInfo().getSize() * 2L);
initializeCommand();
DiskImage oldDisk = createDiskImage();
doReturn(oldDisk).when(command).getOldDisk();
VmDevice vmDevice = stubVmDevice(diskImageGuid, vmId);
vmDevice.setReadOnly(true);
assertFalse(command.validateCanResizeDisk());
ValidateTestUtils.assertValidationMessages
("wrong failure", command, EngineMessage.ACTION_TYPE_FAILED_CANNOT_RESIZE_READ_ONLY_DISK);
}
private void initializeCommand() {
initializeCommand(createVmStatusDown());
}
protected void initializeCommand(VM vm) {
mockGetForDisk(vm);
mockGetVmsListForDisk(vm);
doNothing().when(command).reloadDisks();
doAnswer(invocation -> invocation.getArguments()[0] != null ?
invocation.getArguments()[0] : Guid.newGuid())
.when(quotaManager).getDefaultQuotaIfNull(any(Guid.class), any(Guid.class));
doReturn(diskValidator).when(command).getDiskValidator(any(Disk.class));
doReturn(diskVmElementValidator).when(command).getDiskVmElementValidator(any(Disk.class), any(DiskVmElement.class));
doReturn(true).when(command).setAndValidateDiskProfiles();
doReturn(true).when(command).validateQuota();
SimpleDependencyInjector.getInstance().bind(OsRepository.class, osRepository);
mockVmsStoragePoolInfo(vm);
mockToUpdateDiskVm(vm);
StorageDomain sd = new StorageDomain();
sd.setAvailableDiskSize(Integer.MAX_VALUE);
sd.setStatus(StorageDomainStatus.Active);
when(storageDomainDao.getForStoragePool(any(Guid.class), any(Guid.class))).thenReturn(sd);
StorageDomainValidator sdValidator = new StorageDomainValidator(sd);
doReturn(sdValidator).when(command).getStorageDomainValidator(any(DiskImage.class));
VdcReturnValueBase ret = new VdcReturnValueBase();
ret.setSucceeded(true);
when(backend.runInternalAction(eq(VdcActionType.AmendImageGroupVolumes), any(StorageDomainParametersBase.class), any(CommandContext.class))).thenReturn(ret);
command.init();
}
@Test
public void testDiskAliasAdnDescriptionMetaDataShouldNotBeUpdated() {
when(diskDao.get(diskImageGuid)).thenReturn(createDiskImage());
initializeCommand();
mockVdsCommandSetVolumeDescription();
command.executeVmCommand();
}
@Test
public void testUpdateLockedDisk() {
DiskImage disk = createDiskImage();
disk.setImageStatus(ImageStatus.LOCKED);
when(diskDao.get(diskImageGuid)).thenReturn(disk);
initializeCommand();
ValidateTestUtils.runAndAssertValidateFailure(command, EngineMessage.ACTION_TYPE_FAILED_DISKS_LOCKED);
}
@Test
public void testDiskAliasAdnDescriptionMetaDataShouldBeUpdated() {
when(diskDao.get(diskImageGuid)).thenReturn(createDiskImage());
command.getParameters().getDiskInfo().setDiskAlias("New Disk Alias");
command.getParameters().getDiskInfo().setDiskDescription("New Disk Description");
initializeCommand();
mockVdsCommandSetVolumeDescription();
command.executeVmCommand();
verify(command, times(1)).setVolumeDescription(any(DiskImage.class), any(StorageDomain.class));
}
@Test
public void testOnlyDiskAliasChangedMetaDataShouldBeUpdated() {
when(diskDao.get(diskImageGuid)).thenReturn(createDiskImage());
command.getParameters().getDiskInfo().setDiskAlias("New Disk Alias");
initializeCommand();
mockVdsCommandSetVolumeDescription();
command.executeVmCommand();
verify(command, times(1)).setVolumeDescription(any(DiskImage.class), any(StorageDomain.class));
}
@Test
public void testOnlyDescriptionsChangedMetaDataShouldBeUpdated() {
when(diskDao.get(diskImageGuid)).thenReturn(createDiskImage());
command.getParameters().getDiskInfo().setDiskDescription("New Disk Description");
initializeCommand();
mockVdsCommandSetVolumeDescription();
command.executeVmCommand();
verify(command, times(1)).setVolumeDescription(any(DiskImage.class), any(StorageDomain.class));
}
@Test
public void testExtendingDiskWithQuota() {
Guid quotaId = Guid.newGuid();
DiskImage oldDiskImage = createDiskImage();
oldDiskImage.setQuotaId(quotaId);
oldDiskImage.setSize(SizeConverter.convert(3L, SizeConverter.SizeUnit.GiB,
SizeConverter.SizeUnit.BYTES).longValue());
DiskImage newDiskImage = createDiskImage();
newDiskImage.setQuotaId(quotaId);
newDiskImage.setSize(SizeConverter.convert(5L, SizeConverter.SizeUnit.GiB,
SizeConverter.SizeUnit.BYTES).longValue());
command.getParameters().setDiskVmElement(new DiskVmElement(newDiskImage.getId(), vmId));
command.getParameters().setDiskInfo(newDiskImage);
long diskExtendingDiffInGB = newDiskImage.getSizeInGigabytes() - oldDiskImage.getSizeInGigabytes();
when(diskDao.get(diskImageGuid)).thenReturn(oldDiskImage);
initializeCommand();
QuotaStorageConsumptionParameter consumptionParameter =
(QuotaStorageConsumptionParameter) command.getQuotaStorageConsumptionParameters().get(0);
assertEquals(consumptionParameter.getRequestedStorageGB().longValue(), diskExtendingDiffInGB);
}
@Test
public void testExistingQuota() {
Quota quota = new Quota();
quota.setId(Guid.newGuid());
when(quotaDao.getById(any(Guid.class))).thenReturn(null);
when(quotaDao.getById(quota.getId())).thenReturn(quota);
when(diskDao.get(any(Guid.class))).thenReturn(createDiskImage());
((DiskImage) command.getParameters().getDiskInfo()).setQuotaId(quota.getId());
initializeCommand();
StoragePool pool = mockStoragePool();
command.setStoragePoolId(pool.getId());
quota.setStoragePoolId(pool.getId());
doCallRealMethod().when(command).validateQuota();
ValidateTestUtils.runAndAssertValidateSuccess(command);
}
@Test
public void testNonExistingQuota() {
when(quotaDao.getById(any(Guid.class))).thenReturn(null);
when(diskDao.get(any(Guid.class))).thenReturn(createDiskImage());
((DiskImage) command.getParameters().getDiskInfo()).setQuotaId(Guid.newGuid());
initializeCommand();
doCallRealMethod().when(command).validateQuota();
ValidateTestUtils.runAndAssertValidateFailure(command, EngineMessage.ACTION_TYPE_FAILED_QUOTA_NOT_EXIST);
}
private void mockToUpdateDiskVm(VM vm) {
when(vmDao.get(command.getParameters().getVmId())).thenReturn(vm);
when(diskVmElementDao.get(new VmDeviceId(command.getParameters().getDiskInfo().getId(), vm.getId()))).thenReturn(new DiskVmElement());
}
@Test
public void validateDiscardFailedNotSupportedByDiskInterface() {
when(diskDao.get(diskImageGuid)).thenReturn(createDiskImage());
initializeCommand();
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 validateDiscardFailedNotSupportedByDcVersion() {
when(diskDao.get(diskImageGuid)).thenReturn(createDiskImage());
initializeCommand();
command.getParameters().getDiskVmElement().setPassDiscard(true);
DiskVmElement oldDiskVmElement = new DiskVmElement();
oldDiskVmElement.setPassDiscard(false);
doReturn(oldDiskVmElement).when(command).getOldDiskVmElement();
command.getStoragePool().setCompatibilityVersion(Version.v4_0);
ValidateTestUtils.runAndAssertValidateFailure(command,
EngineMessage.ACTION_TYPE_FAILED_PASS_DISCARD_NOT_SUPPORTED_BY_DC_VERSION);
}
@Test
public void validateDiscardSucceeded() {
when(diskDao.get(diskImageGuid)).thenReturn(createDiskImage());
initializeCommand();
ValidateTestUtils.runAndAssertValidateSuccess(command);
}
private void mockNullVm() {
mockGetForDisk(null);
when(vmDao.get(command.getParameters().getVmId())).thenReturn(null);
}
protected void mockInterfaceList() {
when(osRepository.getDiskInterfaces(anyInt(), any(Version.class))).thenReturn
(Arrays.asList("IDE", "VirtIO", "VirtIO_SCSI"));
}
protected VM createVmStatusDown() {
return createVm(VMStatus.Down);
}
protected VM createVm(VMStatus status) {
VM vm = new VM();
vm.setStatus(status);
vm.setGuestOs("rhel6");
vm.setId(vmId);
return vm;
}
private void mockVmsStoragePoolInfo(VM vm) {
StoragePool storagePool = mockStoragePool();
vm.setStoragePoolId(storagePool.getId());
}
private void mockGetForDisk(VM vm) {
when(vmDao.getForDisk(diskImageGuid, true)).thenReturn(
Collections.singletonMap(Boolean.TRUE, Collections.singletonList(vm)));
}
private void mockGetVmsListForDisk(VM vm) {
VmDevice device = createVmDevice(diskImageGuid, vm.getId());
when(vmDao.getVmsWithPlugInfo(diskImageGuid)).thenReturn(Collections.singletonList(new Pair<>(vm, device)));
}
/**
* Mock a {@link StoragePool}.
*/
private StoragePool mockStoragePool() {
Guid storagePoolId = Guid.newGuid();
StoragePool storagePool = new StoragePool();
storagePool.setId(storagePoolId);
when(storagePoolDao.get(storagePoolId)).thenReturn(storagePool);
return storagePool;
}
/**
* @return Valid parameters for the command.
*/
protected VmDiskOperationParameterBase createParameters() {
DiskImage diskInfo = createDiskImage();
return new VmDiskOperationParameterBase(new DiskVmElement(diskInfo.getId(), vmId), diskInfo);
}
/**
* The following method will simulate a situation when disk was not found in DB
*/
private void createNullDisk() {
when(diskDao.get(diskImageGuid)).thenReturn(null);
}
/**
* The following method will create a new DiskImage
*/
private DiskImage createDiskImage() {
DiskImage disk = new DiskImage();
disk.setId(diskImageGuid);
disk.setSize(100000L);
disk.setStorageIds(new ArrayList<>(Collections.singleton(sdId)));
disk.setStoragePoolId(spId);
disk.setVolumeFormat(VolumeFormat.RAW);
disk.setDescription(RandomUtils.instance().nextString(10));
return disk;
}
/**
* The following method will create a Shareable DiskImage with a specified format
*/
private DiskImage createShareableDisk(VolumeFormat volumeFormat) {
DiskImage disk = createDiskImage();
disk.setVolumeFormat(volumeFormat);
disk.setShareable(true);
return disk;
}
private StorageDomain addNewStorageDomainToDisk(DiskImage diskImage, StorageType storageType) {
StorageDomain storage = new StorageDomain();
storage.setId(Guid.newGuid());
storage.setStorageType(storageType);
storage.setStatus(StorageDomainStatus.Active);
diskImage.setStorageIds(new ArrayList<>(Collections.singletonList(storage.getId())));
return storage;
}
private VmDevice createVmDevice(Guid diskId, Guid vmId) {
return new VmDevice(new VmDeviceId(diskId, vmId),
VmDeviceGeneralType.DISK,
VmDeviceType.DISK.getName(),
"",
null,
true,
true,
null,
"",
null,
null,
null);
}
private VmDevice stubVmDevice(Guid diskId, Guid vmId) {
VmDevice vmDevice = createVmDevice(diskId, vmId);
doReturn(vmDevice).when(command).getVmDeviceForVm();
return vmDevice;
}
}