@Test
  public void clearAddressOnInterfaceChange() {
    final UpdateVmDiskParameters parameters = createParameters();
    // update new disk interface so it will be different than the old one
    parameters.getDiskInfo().setDiskInterface(DiskInterface.VirtIO_SCSI);

    // creating old disk with interface different than interface of disk from parameters
    // have to return original disk on each request to dao,
    // since the command updates retrieved instance of disk
    when(diskDao.get(diskImageGuid))
        .thenAnswer(
            new Answer<Object>() {
              @Override
              public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
                final DiskImage oldDisk = createDiskImage();
                oldDisk.setDiskInterface(DiskInterface.VirtIO);
                assertNotSame(
                    oldDisk.getDiskInterface(), parameters.getDiskInfo().getDiskInterface());
                return oldDisk;
              }
            });
    initializeCommand(parameters);
    mockVdsCommandSetVolumeDescription();
    command.executeVmCommand();

    // verify that device address was cleared exactly once
    verify(vmDeviceDao).clearDeviceAddress(diskImageGuid);
  }
  private void canDoActionMakeDiskBootableOnOtherVm(boolean boot) {
    UpdateVmDiskParameters parameters = createParameters();
    Disk newDisk = parameters.getDiskInfo();
    newDisk.setBoot(true);

    Guid otherVmId = Guid.newGuid();
    VM otherVm = new VM();
    otherVm.setId(otherVmId);

    DiskImage otherDisk = new DiskImage();
    otherDisk.setId(Guid.newGuid());
    otherDisk.setActive(true);
    otherDisk.setBoot(boot);
    if (boot) {
      when(diskDao.getVmBootActiveDisk(otherVmId)).thenReturn(otherDisk);
    }
    when(diskDao.get(diskImageGuid)).thenReturn(createDiskImage());

    initializeCommand(parameters, Arrays.asList(createVmStatusDown(), otherVm));

    mockInterfaceList();

    // The command should only succeed if there is no other bootable disk
    assertEquals(!boot, command.canDoAction());
  }
  @Test
  public void testUpdateDiskInterfaceUnsupported() {
    final UpdateVmDiskParameters parameters = createParameters();
    parameters.getDiskInfo().setDiskInterface(DiskInterface.IDE);
    when(diskDao.get(diskImageGuid))
        .thenAnswer(
            new Answer<Object>() {
              @Override
              public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
                final DiskImage oldDisk = createDiskImage();
                oldDisk.setDiskInterface(DiskInterface.VirtIO);
                assertNotSame(
                    oldDisk.getDiskInterface(), parameters.getDiskInfo().getDiskInterface());
                return oldDisk;
              }
            });

    initializeCommand(parameters);
    doReturn(true).when(command).validatePciAndIdeLimit(anyListOf(VM.class));
    mockVdsCommandSetVolumeDescription();

    when(diskValidator.isReadOnlyPropertyCompatibleWithInterface())
        .thenReturn(ValidationResult.VALID);
    when(diskValidator.isDiskInterfaceSupported(any(VM.class)))
        .thenReturn(new ValidationResult(EngineMessage.ACTION_TYPE_DISK_INTERFACE_UNSUPPORTED));
    when(command.getDiskValidator(parameters.getDiskInfo())).thenReturn(diskValidator);
    CanDoActionTestUtils.runAndAssertCanDoActionFailure(
        command, EngineMessage.ACTION_TYPE_DISK_INTERFACE_UNSUPPORTED);
  }
  @Test
  public void canDoActionFailedUpdateReadOnly() {
    when(diskDao.get(diskImageGuid)).thenReturn(createDiskImage());
    UpdateVmDiskParameters parameters = createParameters();
    parameters.getDiskInfo().setReadOnly(true);
    initializeCommand(parameters, Collections.singletonList(createVm(VMStatus.Up)));

    CanDoActionTestUtils.runAndAssertCanDoActionFailure(
        command, EngineMessage.ACTION_TYPE_FAILED_VM_IS_NOT_DOWN);
  }
  @Test
  public void testResize() {
    DiskImage oldDisk = createDiskImage();
    when(diskDao.get(diskImageGuid)).thenReturn(oldDisk);

    UpdateVmDiskParameters parameters = createParameters();
    ((DiskImage) parameters.getDiskInfo()).setSize(oldDisk.getSize() * 2);
    initializeCommand(parameters);

    assertTrue(command.validateCanResizeDisk());
  }
  private void canDoActionUpdateDescription(VMStatus status) {
    DiskImage disk = createDiskImage();
    disk.setReadOnly(false);
    when(diskDao.get(diskImageGuid)).thenReturn(disk);
    UpdateVmDiskParameters parameters = createParameters();
    parameters.getDiskInfo().setReadOnly(false);
    disk.setDescription(RandomUtils.instance().nextString(10));
    initializeCommand(parameters, Collections.singletonList(createVm(status)));

    CanDoActionTestUtils.runAndAssertCanDoActionSuccess(command);
  }
  @Test
  public void canDoActionFailedShareableDiskVolumeFormatUnsupported() throws Exception {
    UpdateVmDiskParameters parameters = createParameters();
    DiskImage disk = createShareableDisk(VolumeFormat.COW);
    StorageDomain storage = addNewStorageDomainToDisk(disk, StorageType.NFS);
    parameters.setDiskInfo(disk);

    when(diskDao.get(diskImageGuid)).thenReturn(createDiskImage());
    when(storageDomainStaticDao.get(storage.getId())).thenReturn(storage.getStorageStaticData());
    initializeCommand(parameters);

    CanDoActionTestUtils.runAndAssertCanDoActionFailure(
        command, EngineMessage.SHAREABLE_DISK_IS_NOT_SUPPORTED_BY_VOLUME_FORMAT);
  }
  @Test
  public void testDoNotUpdateDeviceWhenReadOnlyIsNotChanged() {
    final UpdateVmDiskParameters parameters = createParameters();
    parameters.getDiskInfo().setReadOnly(false);

    when(diskDao.get(diskImageGuid)).thenReturn(createDiskImage());
    initializeCommand(parameters);
    mockVdsCommandSetVolumeDescription();
    command.executeVmCommand();

    verify(command, atLeast(1)).updateReadOnlyRequested();
    assertFalse(command.updateReadOnlyRequested());
    verify(vmDeviceDao, never()).update(any(VmDevice.class));
  }
  @Test
  public void canDoActionFailedShareableDiskOnGlusterDomain() throws Exception {
    UpdateVmDiskParameters parameters = createParameters();
    DiskImage disk = createShareableDisk(VolumeFormat.RAW);
    StorageDomain storage = addNewStorageDomainToDisk(disk, StorageType.GLUSTERFS);
    parameters.setDiskInfo(disk);

    when(diskDao.get(diskImageGuid)).thenReturn(createDiskImage());
    when(storageDomainStaticDao.get(storage.getId())).thenReturn(storage.getStorageStaticData());
    initializeCommand(parameters);

    CanDoActionTestUtils.runAndAssertCanDoActionFailure(
        command, EngineMessage.ACTION_TYPE_FAILED_SHAREABLE_DISKS_NOT_SUPPORTED_ON_GLUSTER_DOMAIN);
  }
  @Test
  public void testFaultyResize() {
    when(diskDao.get(diskImageGuid)).thenReturn(createDiskImage());

    UpdateVmDiskParameters parameters = createParameters();
    ((DiskImage) parameters.getDiskInfo()).setSize(parameters.getDiskInfo().getSize() / 2);
    initializeCommand(parameters);

    assertFalse(command.validateCanResizeDisk());
    CanDoActionTestUtils.assertCanDoActionMessages(
        "wrong failure",
        command,
        EngineMessage.ACTION_TYPE_FAILED_REQUESTED_DISK_SIZE_IS_TOO_SMALL);
  }
  @Test
  public void testOnlyDiskAliasChangedMetaDataShouldBeUpdated() {
    // Disk should be updated as Read Only
    final UpdateVmDiskParameters parameters = createParameters();
    when(diskDao.get(diskImageGuid)).thenReturn(createDiskImage());

    parameters.getDiskInfo().setDiskAlias("New Disk Alias");
    initializeCommand(parameters);
    mockVdsCommandSetVolumeDescription();
    command.executeVmCommand();
    verify(command, times(1))
        .runVdsCommand(
            eq(VDSCommandType.SetVolumeDescription),
            any(SetVolumeDescriptionVDSCommandParameters.class));
  }
  @Test
  public void testUpdateReadOnlyPropertyOnChange() {
    // Disk should be updated as Read Only
    final UpdateVmDiskParameters parameters = createParameters();
    parameters.getDiskInfo().setReadOnly(true);

    when(diskDao.get(diskImageGuid)).thenReturn(createDiskImage());
    initializeCommand(parameters);
    stubVmDevice(diskImageGuid, vmId);
    mockVdsCommandSetVolumeDescription();
    command.executeVmCommand();

    verify(command, atLeast(1)).updateReadOnlyRequested();
    assertTrue(command.updateReadOnlyRequested());
    verify(vmDeviceDao).update(any(VmDevice.class));
  }
  @Test
  public void getOtherVmDisks() {
    UpdateVmDiskParameters parameters = createParameters();

    DiskImage otherDisk = new DiskImage();
    otherDisk.setId(Guid.newGuid());
    otherDisk.setActive(true);
    when(diskDao.getAllForVm(vmId))
        .thenReturn(new LinkedList<>(Arrays.asList(parameters.getDiskInfo(), otherDisk)));
    when(diskDao.get(diskImageGuid)).thenReturn(createDiskImage());
    initializeCommand(parameters);

    VM vm = createVmStatusDown();
    mockCtorRelatedDaoCalls(Collections.singletonList(vm));
    List<Disk> otherDisks = command.getOtherVmDisks(vm.getId());
    assertEquals("Wrong number of other disks", 1, otherDisks.size());
    assertFalse("Wrong other disk", otherDisks.contains(parameters.getDiskInfo()));
  }
  @Test
  public void canDoActionFailedROVmAttachedToPool() {
    when(diskDao.get(diskImageGuid)).thenReturn(createDiskImage());
    UpdateVmDiskParameters parameters = createParameters();
    parameters.getDiskInfo().setReadOnly(true);
    VM vm = createVm(VMStatus.Down);
    vm.setVmPoolId(Guid.newGuid());
    initializeCommand(parameters, Collections.singletonList(vm));

    VmDevice vmDevice = stubVmDevice(diskImageGuid, vmId); // Default RO is false
    CanDoActionTestUtils.runAndAssertCanDoActionFailure(
        command, EngineMessage.ACTION_TYPE_FAILED_VM_ATTACHED_TO_POOL);

    vmDevice.setIsReadOnly(true);
    parameters.getDiskInfo().setReadOnly(false);
    CanDoActionTestUtils.runAndAssertCanDoActionFailure(
        command, EngineMessage.ACTION_TYPE_FAILED_VM_ATTACHED_TO_POOL);
  }
  @Test
  public void canDoActionFailedWipeVmAttachedToPool() {
    Disk oldDisk = createDiskImage();
    oldDisk.setWipeAfterDelete(true);
    when(diskDao.get(diskImageGuid)).thenReturn(oldDisk);

    UpdateVmDiskParameters parameters = createParameters();
    parameters.getDiskInfo().setWipeAfterDelete(false);
    VM vm = createVm(VMStatus.Down);
    vm.setVmPoolId(Guid.newGuid());
    initializeCommand(parameters, Collections.singletonList(vm));

    CanDoActionTestUtils.runAndAssertCanDoActionFailure(
        command, EngineMessage.ACTION_TYPE_FAILED_VM_ATTACHED_TO_POOL);

    oldDisk.setWipeAfterDelete(false);
    parameters.getDiskInfo().setWipeAfterDelete(true);
    CanDoActionTestUtils.runAndAssertCanDoActionFailure(
        command, EngineMessage.ACTION_TYPE_FAILED_VM_ATTACHED_TO_POOL);
  }
  @Test
  public void testFailedRoDiskResize() {
    StorageDomain sd = new StorageDomain();
    sd.setAvailableDiskSize(Integer.MAX_VALUE);
    sd.setStatus(StorageDomainStatus.Active);
    when(storageDomainDao.getForStoragePool(any(Guid.class), any(Guid.class))).thenReturn(sd);

    UpdateVmDiskParameters parameters = createParameters();
    ((DiskImage) parameters.getDiskInfo()).setSize(parameters.getDiskInfo().getSize() * 2);
    initializeCommand(parameters);

    DiskImage oldDisk = createDiskImage();
    doReturn(oldDisk).when(command).getOldDisk();

    VmDevice vmDevice = stubVmDevice(diskImageGuid, vmId);
    vmDevice.setIsReadOnly(true);

    assertFalse(command.validateCanResizeDisk());
    CanDoActionTestUtils.assertCanDoActionMessages(
        "wrong failure", command, EngineMessage.ACTION_TYPE_FAILED_CANNOT_RESIZE_READ_ONLY_DISK);
  }
  @Test
  public void nullifiedSnapshotOnUpdateDiskToShareable() {
    UpdateVmDiskParameters parameters = createParameters();
    DiskImage disk = createShareableDisk(VolumeFormat.RAW);
    parameters.setDiskInfo(disk);
    StorageDomain storage = addNewStorageDomainToDisk(disk, StorageType.NFS);
    parameters.setDiskInfo(disk);

    DiskImage oldDisk = createDiskImage();
    oldDisk.setVmSnapshotId(Guid.newGuid());

    when(diskDao.get(diskImageGuid)).thenReturn(oldDisk);
    when(storageDomainStaticDao.get(storage.getId())).thenReturn(storage.getStorageStaticData());

    initializeCommand(parameters);
    mockVdsCommandSetVolumeDescription();
    mockInterfaceList();

    CanDoActionTestUtils.runAndAssertCanDoActionSuccess(command);
    command.executeVmCommand();
    assertTrue(oldDisk.getVmSnapshotId() == null);
  }