content: // Licensed to the Apache Software Foundation (ASF) under one
  // or more contributor license agreements.  See the NOTICE file
  // distributed with this work for additional information
  // regarding copyright ownership.  The ASF licenses this file
  // to you under the Apache License, Version 2.0 (the
  // "License"); you may not use this file except in compliance
  // with the License.  You may obtain a copy of the License at
  //
  //   http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing,
  // software distributed under the License is distributed on an
  // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  // KIND, either express or implied.  See the License for the
  // specific language governing permissions and limitations
  // under the License.
  package org.apache.cloudstack.api.command.admin.vm;
  
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  
  import org.apache.cloudstack.api.ApiConstants;
  import org.apache.cloudstack.api.ResponseGenerator;
  import org.apache.cloudstack.api.ResponseObject;
  import org.apache.cloudstack.api.ServerApiException;
  import org.apache.cloudstack.api.response.SystemVmResponse;
  import org.apache.cloudstack.api.response.UserVmResponse;
  import org.junit.Assert;
  import org.junit.Before;
  import org.junit.Test;
  import org.junit.runner.RunWith;
  import org.mockito.InjectMocks;
  import org.mockito.Mock;
  import org.mockito.Mockito;
  import org.mockito.Spy;
  import org.mockito.junit.MockitoJUnitRunner;
  import org.springframework.test.util.ReflectionTestUtils;
  
  import com.cloud.exception.InvalidParameterValueException;
  import com.cloud.exception.ManagementServerException;
  import com.cloud.exception.ResourceUnavailableException;
  import com.cloud.exception.VirtualMachineMigrationException;
  import com.cloud.host.Host;
  import com.cloud.resource.ResourceService;
  import com.cloud.uservm.UserVm;
  import com.cloud.utils.db.UUIDManager;
  import com.cloud.vm.UserVmService;
  import com.cloud.vm.VirtualMachine;
  
  @RunWith(MockitoJUnitRunner.class)
  public class MigrateVirtualMachineWithVolumeCmdTest {
      @Mock
      UserVmService userVmServiceMock;
  
      @Mock
      UUIDManager uuidManagerMock;
  
      @Mock
      ResourceService resourceServiceMock;
  
      @Mock
      ResponseGenerator responseGeneratorMock;
  
      @Mock
      VirtualMachine virtualMachineMock;
  
      @Mock
      Host hostMock;
  
      @Mock
      private Object job;
  
      @Mock
      private Object _responseObject;
  
      @Spy
      @InjectMocks
      MigrateVirtualMachineWithVolumeCmd cmdSpy;
  
      private Long hostId = 1L;
      private Long virtualMachineId = 1L;
      private String virtualMachineName = "VM-name";
      private  Map<String, String> migrateVolumeTo = null;
      private SystemVmResponse systemVmResponse = new SystemVmResponse();
      private UserVmResponse userVmResponse = new UserVmResponse();
  
      @Before
      public void setUp() throws Exception {
          ReflectionTestUtils.setField(cmdSpy, "virtualMachineId", virtualMachineId);
          migrateVolumeTo = new HashMap<>();
          migrateVolumeTo.put("volume", "abc");
          migrateVolumeTo.put("pool", "xyz");
      }
  
      @Test
      public void executeTestRequiredArgsNullThrowsInvalidParameterValueException() {
          ReflectionTestUtils.setField(cmdSpy, "hostId", null);
          ReflectionTestUtils.setField(cmdSpy, "migrateVolumeTo", null);
          ReflectionTestUtils.setField(cmdSpy, "autoSelect", null);
  
          try {
              cmdSpy.execute();
          } catch (Exception e) {
              Assert.assertEquals(InvalidParameterValueException.class, e.getClass());
              String expected = String.format("Either %s or %s must be passed or %s must be true for migrating the VM.", ApiConstants.HOST_ID, ApiConstants.MIGRATE_TO, ApiConstants.AUTO_SELECT);
              Assert.assertEquals(expected , e.getMessage());
          }
      }
  
      @Test
      public void executeTestVMIsStoppedAndHostIdIsNotNullThrowsInvalidParameterValueException() {
          ReflectionTestUtils.setField(cmdSpy, "hostId", hostId);
          ReflectionTestUtils.setField(cmdSpy, "migrateVolumeTo", migrateVolumeTo);
  
          Mockito.when(userVmServiceMock.getVm(Mockito.anyLong())).thenReturn(virtualMachineMock);
          Mockito.when(virtualMachineMock.getState()).thenReturn(VirtualMachine.State.Stopped);
          Mockito.when(virtualMachineMock.toString()).thenReturn(String.format("VM [uuid: %s, name: %s]", virtualMachineId, virtualMachineName));
  
          try {
              cmdSpy.execute();
          } catch (Exception e) {
              Assert.assertEquals(InvalidParameterValueException.class, e.getClass());
              String expected = String.format("%s is not in the Running state to migrate it to the new host.", virtualMachineMock);
              Assert.assertEquals(expected , e.getMessage());
          }
      }
  
      @Test
      public void executeTestVMIsRunningHostIdIsNullAndAutoSelectIsFalseThrowsInvalidParameterValueException() {
          ReflectionTestUtils.setField(cmdSpy, "hostId", null);
          ReflectionTestUtils.setField(cmdSpy, "autoSelect", false);
          ReflectionTestUtils.setField(cmdSpy, "migrateVolumeTo", migrateVolumeTo);
  
          Mockito.when(userVmServiceMock.getVm(Mockito.anyLong())).thenReturn(virtualMachineMock);
          Mockito.when(virtualMachineMock.getState()).thenReturn(VirtualMachine.State.Running);
          Mockito.when(virtualMachineMock.toString()).thenReturn(String.format("VM [uuid: %s, name: %s]", virtualMachineId, virtualMachineName));
  
          try {
              cmdSpy.execute();
          } catch (Exception e) {
              Assert.assertEquals(InvalidParameterValueException.class, e.getClass());
              String expected = String.format("%s is not in the Stopped state to migrate, use the %s or %s parameter to migrate it to a new host.", virtualMachineMock,
                      ApiConstants.HOST_ID, ApiConstants.AUTO_SELECT);
              Assert.assertEquals(expected , e.getMessage());
          }
      }
  
      @Test
      public void executeTestHostIdIsNullThrowsInvalidParameterValueException() {
          ReflectionTestUtils.setField(cmdSpy, "virtualMachineId", virtualMachineId);
          ReflectionTestUtils.setField(cmdSpy, "hostId", hostId);
          ReflectionTestUtils.setField(cmdSpy, "migrateVolumeTo", migrateVolumeTo);
          ReflectionTestUtils.setField(cmdSpy, "autoSelect", false);
  
          Mockito.when(userVmServiceMock.getVm(Mockito.anyLong())).thenReturn(virtualMachineMock);
          Mockito.when(virtualMachineMock.getState()).thenReturn(VirtualMachine.State.Running);
          Mockito.when(resourceServiceMock.getHost(Mockito.anyLong())).thenReturn(null);
  
          try {
              cmdSpy.execute();
          } catch (Exception e) {
              Assert.assertEquals(InvalidParameterValueException.class, e.getClass());
              String expected = "Unable to find the specified host to migrate the VM.";
              Assert.assertEquals(expected , e.getMessage());
          }
      }
  
      private Map getMockedMigrateVolumeToApiCmdParam() {
          Map<String, String> migrateVolumeTo = new HashMap<>();
          migrateVolumeTo.put("volume", "abc");
          migrateVolumeTo.put("pool", "xyz");
          return Map.of("", migrateVolumeTo);
      }
  
      @Test
      public void executeTestHostIsNotNullMigratedVMIsNullThrowsServerApiException() throws ManagementServerException, ResourceUnavailableException, VirtualMachineMigrationException {
          ReflectionTestUtils.setField(cmdSpy, "hostId", hostId);
          ReflectionTestUtils.setField(cmdSpy, "migrateVolumeTo", getMockedMigrateVolumeToApiCmdParam());
  
          Mockito.when(userVmServiceMock.getVm(Mockito.anyLong())).thenReturn(virtualMachineMock);
          Mockito.when(virtualMachineMock.getState()).thenReturn(VirtualMachine.State.Running);
          Mockito.when(resourceServiceMock.getHost(hostId)).thenReturn(hostMock);
          Mockito.when(userVmServiceMock.migrateVirtualMachineWithVolume(Mockito.anyLong(), Mockito.any(), Mockito.anyMap())).thenReturn(null);
  
          try {
              cmdSpy.execute();
          } catch (Exception e) {
              Assert.assertEquals(ServerApiException.class, e.getClass());
              String expected = "Failed to migrate vm";
              Assert.assertEquals(expected , e.getMessage());
          }
      }
  
      @Test
      public void executeTestHostIsNullMigratedVMIsNullThrowsServerApiException() {
          ReflectionTestUtils.setField(cmdSpy, "hostId", null);
          ReflectionTestUtils.setField(cmdSpy, "migrateVolumeTo", getMockedMigrateVolumeToApiCmdParam());
  
          Mockito.when(userVmServiceMock.getVm(Mockito.anyLong())).thenReturn(virtualMachineMock);
          Mockito.when(virtualMachineMock.getState()).thenReturn(VirtualMachine.State.Stopped);
          Mockito.when(userVmServiceMock.vmStorageMigration(Mockito.anyLong(), Mockito.anyMap())).thenReturn(null);
  
          try {
              cmdSpy.execute();
          } catch (Exception e) {
              Assert.assertEquals(ServerApiException.class, e.getClass());
              String expected = "Failed to migrate vm";
              Assert.assertEquals(expected , e.getMessage());
          }
      }
  
      @Test
      public void executeTestSystemVMMigratedWithSuccess() {
          ReflectionTestUtils.setField(cmdSpy, "hostId", null);
          ReflectionTestUtils.setField(cmdSpy, "migrateVolumeTo", getMockedMigrateVolumeToApiCmdParam());
  
          Mockito.when(userVmServiceMock.getVm(Mockito.anyLong())).thenReturn(virtualMachineMock);
          Mockito.when(virtualMachineMock.getState()).thenReturn(VirtualMachine.State.Stopped);
          Mockito.when(userVmServiceMock.vmStorageMigration(Mockito.anyLong(), Mockito.anyMap())).thenReturn(virtualMachineMock);
          Mockito.when(virtualMachineMock.getType()).thenReturn(VirtualMachine.Type.ConsoleProxy);
          Mockito.when(responseGeneratorMock.createSystemVmResponse(virtualMachineMock)).thenReturn(systemVmResponse);
  
          cmdSpy.execute();
  
          Mockito.verify(responseGeneratorMock, Mockito.times(1)).createSystemVmResponse(virtualMachineMock);
      }
  
      @Test
      public void executeTestUserVMMigratedWithSuccess() {
          UserVm userVmMock = Mockito.mock(UserVm.class);
          ReflectionTestUtils.setField(cmdSpy, "hostId", null);
          ReflectionTestUtils.setField(cmdSpy, "migrateVolumeTo", getMockedMigrateVolumeToApiCmdParam());
  
          Mockito.when(userVmServiceMock.getVm(Mockito.anyLong())).thenReturn(userVmMock);
          Mockito.when(userVmMock.getState()).thenReturn(VirtualMachine.State.Stopped);
          Mockito.when(userVmServiceMock.vmStorageMigration(Mockito.anyLong(), Mockito.anyMap())).thenReturn(userVmMock);
          Mockito.when(userVmMock.getType()).thenReturn(VirtualMachine.Type.User);
          Mockito.when(responseGeneratorMock.createUserVmResponse(ResponseObject.ResponseView.Full, "virtualmachine", userVmMock)).thenReturn(List.of(userVmResponse));
  
          cmdSpy.execute();
  
          Mockito.verify(responseGeneratorMock, Mockito.times(1)).createUserVmResponse(ResponseObject.ResponseView.Full, "virtualmachine", userVmMock);
      }
  }
  