1919
2020import static org .junit .Assert .assertEquals ;
2121import static org .junit .Assert .assertFalse ;
22+ import static org .junit .Assert .assertNotNull ;
2223import static org .junit .Assert .assertNull ;
24+ import static org .junit .Assert .assertThrows ;
2325import static org .junit .Assert .assertTrue ;
2426import static org .mockito .ArgumentMatchers .any ;
27+ import static org .mockito .ArgumentMatchers .anyList ;
2528import static org .mockito .ArgumentMatchers .anyLong ;
2629import static org .mockito .ArgumentMatchers .anyString ;
2730import static org .mockito .ArgumentMatchers .eq ;
2831import static org .mockito .Mockito .doNothing ;
2932import static org .mockito .Mockito .doReturn ;
33+ import static org .mockito .Mockito .doThrow ;
3034import static org .mockito .Mockito .mock ;
3135import static org .mockito .Mockito .never ;
3236import static org .mockito .Mockito .times ;
4347import java .util .UUID ;
4448import java .util .stream .Collectors ;
4549
50+ import com .cloud .agent .api .UnmanageInstanceAnswer ;
51+ import com .cloud .agent .api .UnmanageInstanceCommand ;
52+ import com .cloud .agent .api .to .DataTO ;
53+ import com .cloud .agent .api .to .DiskTO ;;
54+ import com .cloud .network .Network ;
55+ import com .cloud .network .NetworkModel ;
4656import com .cloud .resource .ResourceManager ;
4757import org .apache .cloudstack .api .ApiConstants ;
4858import org .apache .cloudstack .context .CallContext ;
4959import org .apache .cloudstack .engine .subsystem .api .storage .StoragePoolAllocator ;
60+ import org .apache .cloudstack .engine .subsystem .api .storage .VolumeDataFactory ;
61+ import org .apache .cloudstack .engine .subsystem .api .storage .VolumeInfo ;
5062import org .apache .cloudstack .framework .config .ConfigKey ;
5163import org .apache .cloudstack .framework .config .impl .ConfigDepotImpl ;
5264import org .apache .cloudstack .framework .extensions .dao .ExtensionDetailsDao ;
6173import org .junit .Before ;
6274import org .junit .Test ;
6375import org .junit .runner .RunWith ;
76+ import org .mockito .ArgumentCaptor ;
6477import org .mockito .InOrder ;
6578import org .mockito .InjectMocks ;
6679import org .mockito .Mock ;
@@ -192,6 +205,7 @@ public class VirtualMachineManagerImplTest {
192205 private StoragePoolVO storagePoolVoMock ;
193206 private long storagePoolVoMockId = 11L ;
194207 private long storagePoolVoMockClusterId = 234L ;
208+ private String vmName = "vm1" ;
195209
196210 @ Mock
197211 private VolumeVO volumeVoMock ;
@@ -254,6 +268,12 @@ public class VirtualMachineManagerImplTest {
254268 NicDao _nicsDao ;
255269 @ Mock
256270 NetworkService networkService ;
271+ @ Mock
272+ NetworkModel networkModel ;
273+ @ Mock
274+ VolumeDataFactory volumeDataFactoryMock ;
275+ @ Mock
276+ StorageManager storageManager ;
257277
258278 private ConfigDepotImpl configDepotImpl ;
259279 private boolean updatedConfigKeyDepot = false ;
@@ -263,6 +283,7 @@ public void setup() {
263283 ReflectionTestUtils .getField (VirtualMachineManager .VmMetadataManufacturer , "s_depot" );
264284 virtualMachineManagerImpl .setHostAllocators (new ArrayList <>());
265285
286+ when (vmInstanceMock .getName ()).thenReturn (vmName );
266287 when (vmInstanceMock .getId ()).thenReturn (vmInstanceVoMockId );
267288 when (vmInstanceMock .getServiceOfferingId ()).thenReturn (2L );
268289 when (hostMock .getId ()).thenReturn (hostMockId );
@@ -1361,7 +1382,7 @@ public void recreateCheckpointsKvmOnVmAfterMigrationTestAgentUnavailableThrowsCl
13611382 Mockito .doReturn (HypervisorType .KVM ).when (vmInstanceMock ).getHypervisorType ();
13621383 Mockito .doReturn (List .of (new VolumeObjectTO ())).when (virtualMachineManagerImpl ).getVmVolumesWithCheckpointsToRecreate (Mockito .any ());
13631384
1364- Mockito . doThrow (new AgentUnavailableException (0 )).when (agentManagerMock ).send (Mockito .anyLong (), (Command ) any ());
1385+ doThrow (new AgentUnavailableException (0 )).when (agentManagerMock ).send (Mockito .anyLong (), (Command ) any ());
13651386 Mockito .doNothing ().when (snapshotManagerMock ).endSnapshotChainForVolume (Mockito .anyLong (), Mockito .any ());
13661387
13671388 virtualMachineManagerImpl .recreateCheckpointsKvmOnVmAfterMigration (vmInstanceMock , 0 );
@@ -1374,7 +1395,7 @@ public void recreateCheckpointsKvmOnVmAfterMigrationTestOperationTimedoutExcepti
13741395 Mockito .doReturn (HypervisorType .KVM ).when (vmInstanceMock ).getHypervisorType ();
13751396 Mockito .doReturn (List .of (new VolumeObjectTO ())).when (virtualMachineManagerImpl ).getVmVolumesWithCheckpointsToRecreate (Mockito .any ());
13761397
1377- Mockito . doThrow (new OperationTimedoutException (null , 0 , 0 , 0 , false )).when (agentManagerMock ).send (Mockito .anyLong (), (Command ) any ());
1398+ doThrow (new OperationTimedoutException (null , 0 , 0 , 0 , false )).when (agentManagerMock ).send (Mockito .anyLong (), (Command ) any ());
13781399 Mockito .doNothing ().when (snapshotManagerMock ).endSnapshotChainForVolume (Mockito .anyLong (), Mockito .any ());
13791400
13801401 virtualMachineManagerImpl .recreateCheckpointsKvmOnVmAfterMigration (vmInstanceMock , 0 );
@@ -1641,4 +1662,152 @@ public void processPrepareExternalProvisioning_externalHypervisor_sendsCommand()
16411662 virtualMachineManagerImpl .processPrepareExternalProvisioning (true , host , vmProfile , mock (DataCenter .class ));
16421663 verify (agentManagerMock ).send (anyLong (), any (Command .class ));
16431664 }
1665+
1666+ @ Test
1667+ public void testPrepVMSpecForUnmanageInstance () {
1668+ // Arrange
1669+ final Long accountId = 1L ;
1670+ final Long offeringId = 1L ;
1671+ final Long templateId = 1L ;
1672+
1673+ // Mock vm
1674+ VMInstanceVO vm = Mockito .mock (VMInstanceVO .class );
1675+ when (vm .getId ()).thenReturn (vmInstanceVoMockId );
1676+ when (vm .getAccountId ()).thenReturn (accountId );
1677+ when (vm .getServiceOfferingId ()).thenReturn (offeringId );
1678+ when (vm .getTemplateId ()).thenReturn (templateId );
1679+ when (vm .getHypervisorType ()).thenReturn (HypervisorType .KVM );
1680+ when (vmInstanceDaoMock .findById (vmInstanceVoMockId )).thenReturn (vm );
1681+
1682+ // Mock owner
1683+ AccountVO owner = Mockito .mock (AccountVO .class );
1684+ when (_entityMgr .findById (Account .class , accountId )).thenReturn (owner );
1685+
1686+ ServiceOfferingVO offering = Mockito .mock (ServiceOfferingVO .class );
1687+ when (serviceOfferingDaoMock .findById (vmInstanceVoMockId , offeringId )).thenReturn (offering );
1688+
1689+ VMTemplateVO template = Mockito .mock (VMTemplateVO .class );
1690+ when (_entityMgr .findByIdIncludingRemoved (VirtualMachineTemplate .class , templateId )).thenReturn (template );
1691+
1692+ when (hostMock .getClusterId ()).thenReturn (clusterMockId );
1693+
1694+ // Mock cpuOvercommitRatio and ramOvercommitRatio
1695+ ClusterDetailsVO cpuOvercommitRatio = Mockito .mock (ClusterDetailsVO .class );
1696+ when (cpuOvercommitRatio .getValue ()).thenReturn ("1.0" );
1697+ when (_clusterDetailsDao .findDetail (clusterMockId , VmDetailConstants .CPU_OVER_COMMIT_RATIO )).thenReturn (cpuOvercommitRatio );
1698+ ClusterDetailsVO ramOvercommitRatio = Mockito .mock (ClusterDetailsVO .class );
1699+ when (ramOvercommitRatio .getValue ()).thenReturn ("1.0" );
1700+ when (_clusterDetailsDao .findDetail (clusterMockId , VmDetailConstants .MEMORY_OVER_COMMIT_RATIO )).thenReturn (ramOvercommitRatio );
1701+
1702+ // Mock NICs
1703+ List <NicVO > nics = new ArrayList <>();
1704+ NicVO nic1 = Mockito .mock (NicVO .class );
1705+ when (nic1 .getDeviceId ()).thenReturn (1 );
1706+ nics .add (nic1 );
1707+ NicVO nic2 = Mockito .mock (NicVO .class );
1708+ when (nic2 .getDeviceId ()).thenReturn (0 );
1709+ nics .add (nic2 );
1710+ when (_nicsDao .listByVmId (vmInstanceVoMockId )).thenReturn (nics );
1711+
1712+ Network networkMock = Mockito .mock (Network .class );
1713+ when (networkModel .getNetwork (anyLong ())).thenReturn (networkMock );
1714+
1715+ when (volumeVoMock .getVolumeType ()).thenReturn (Volume .Type .ROOT );
1716+ when (volumeVoMock .getDeviceId ()).thenReturn (0L );
1717+ when (volumeVoMock .getPath ()).thenReturn ("/" );
1718+ when (volumeVoMock .getDiskOfferingId ()).thenReturn (1L );
1719+ when (volumeDaoMock .findUsableVolumesForInstance (vmInstanceVoMockId )).thenReturn (List .of (volumeVoMock ));
1720+
1721+ VolumeInfo volumeInfo = mock (VolumeInfo .class );
1722+ DataTO dataTO = mock (DataTO .class );
1723+ when (volumeInfo .getTO ()).thenReturn (dataTO );
1724+ when (volumeDataFactoryMock .getVolume (anyLong ())).thenReturn (volumeInfo );
1725+ when (storageManager .getDiskWithThrottling (any (), any (), anyLong (), anyString (), anyLong (), anyLong ())).thenReturn (Mockito .mock (DiskTO .class ));
1726+
1727+ Map <String , String > details = new HashMap <>();
1728+ details .put (VirtualMachineProfile .Param .BootType .getName (), "BIOS" );
1729+ details .put (VirtualMachineProfile .Param .BootMode .getName (), "LEGACY" );
1730+ details .put (VirtualMachineProfile .Param .UefiFlag .getName (), "Yes" );
1731+ when (vmInstanceDetailsDao .listDetailsKeyPairs (anyLong (), anyList ())).thenReturn (details );
1732+
1733+ com .cloud .hypervisor .HypervisorGuru guru = Mockito .mock (com .cloud .hypervisor .HypervisorGuru .class );
1734+ when (_hvGuruMgr .getGuru (HypervisorType .KVM )).thenReturn (guru );
1735+ VirtualMachineTO vmTO = new VirtualMachineTO () {};
1736+ when (guru .implement (any (VirtualMachineProfile .class ))).thenAnswer ((Answer <VirtualMachineTO >) invocation -> {
1737+ VirtualMachineProfile profile = invocation .getArgument (0 );
1738+ assertEquals ("BIOS" , profile .getParameter (VirtualMachineProfile .Param .BootType ));
1739+ return vmTO ;
1740+ });
1741+
1742+ // Act
1743+ VirtualMachineTO result = virtualMachineManagerImpl .prepVmSpecForUnmanageCmd (vmInstanceVoMockId , hostMockId );
1744+
1745+ // Assert
1746+ assertNotNull (result );
1747+ assertEquals (vmTO , result );
1748+ verify (_clusterDetailsDao , times (2 )).findDetail (eq (clusterMockId ), anyString ());
1749+ verify (vmInstanceDetailsDao ).listDetailsKeyPairs (anyLong (), anyList ());
1750+ }
1751+
1752+ @ Test
1753+ public void testPersistDomainForKvmForRunningVmSuccess () throws AgentUnavailableException , OperationTimedoutException {
1754+ when (vmInstanceMock .getState ()).thenReturn (VirtualMachine .State .Running );
1755+ when (vmInstanceMock .getHostId ()).thenReturn (hostMockId );
1756+ UnmanageInstanceAnswer successAnswer = new UnmanageInstanceAnswer (null , true , "success" );
1757+ when (agentManagerMock .send (anyLong (), any (Command .class ))).thenReturn (successAnswer );
1758+ virtualMachineManagerImpl .persistDomainForKVM (vmInstanceMock );
1759+ ArgumentCaptor <Long > hostIdCaptor = ArgumentCaptor .forClass (Long .class );
1760+ ArgumentCaptor <UnmanageInstanceCommand > commandCaptor = ArgumentCaptor .forClass (UnmanageInstanceCommand .class );
1761+ verify (agentManagerMock ).send (hostIdCaptor .capture (), commandCaptor .capture ());
1762+ assertEquals (hostMockId , hostIdCaptor .getValue ().longValue ());
1763+ }
1764+
1765+ @ Test
1766+ public void testPersistDomainForKvmForStoppedVmSuccess () throws AgentUnavailableException , OperationTimedoutException {
1767+ when (vmInstanceMock .getState ()).thenReturn (VirtualMachine .State .Stopped );
1768+ when (vmInstanceMock .getLastHostId ()).thenReturn (1L );
1769+ VirtualMachineTO vmTO = new VirtualMachineTO () {};
1770+ vmTO .setName (vmName );
1771+ doReturn (vmTO ).when (virtualMachineManagerImpl ).prepVmSpecForUnmanageCmd (vmInstanceVoMockId , 1L );
1772+ UnmanageInstanceAnswer successAnswer = new UnmanageInstanceAnswer (null , true , "success" );
1773+ when (agentManagerMock .send (anyLong (), any (UnmanageInstanceCommand .class ))).thenReturn (successAnswer );
1774+ virtualMachineManagerImpl .persistDomainForKVM (vmInstanceMock );
1775+ ArgumentCaptor <Long > hostIdCaptor = ArgumentCaptor .forClass (Long .class );
1776+ ArgumentCaptor <UnmanageInstanceCommand > commandCaptor = ArgumentCaptor .forClass (UnmanageInstanceCommand .class );
1777+ verify (agentManagerMock ).send (hostIdCaptor .capture (), commandCaptor .capture ());
1778+ assertEquals (1L , hostIdCaptor .getValue ().longValue ());
1779+ UnmanageInstanceCommand sentCommand = commandCaptor .getValue ();
1780+ assertNotNull (sentCommand .getVm ());
1781+ assertEquals (vmTO , sentCommand .getVm ());
1782+ assertEquals (vmName , sentCommand .getInstanceName ());
1783+ verify (virtualMachineManagerImpl ).prepVmSpecForUnmanageCmd (vmInstanceVoMockId , 1L );
1784+ }
1785+
1786+ @ Test
1787+ public void testPersistDomainForKvmForRunningVmAgentFailure () throws AgentUnavailableException , OperationTimedoutException {
1788+ when (vmInstanceMock .getState ()).thenReturn (VirtualMachine .State .Running );
1789+ when (vmInstanceMock .getHostId ()).thenReturn (hostMockId );
1790+ UnmanageInstanceAnswer failureAnswer = new UnmanageInstanceAnswer (null , false , "failure" );
1791+ when (agentManagerMock .send (anyLong (), any (UnmanageInstanceCommand .class ))).thenReturn (failureAnswer );
1792+ CloudRuntimeException exception = assertThrows (CloudRuntimeException .class , () -> virtualMachineManagerImpl .persistDomainForKVM (vmInstanceMock ));
1793+ assertEquals ("Failed to persist domainXML for instance: " + vmName , exception .getMessage ());
1794+ }
1795+
1796+ @ Test
1797+ public void testPersistDomainForKvmAgentUnavailable () throws AgentUnavailableException , OperationTimedoutException {
1798+ when (vmInstanceMock .getState ()).thenReturn (VirtualMachine .State .Running );
1799+ when (vmInstanceMock .getHostId ()).thenReturn (hostMockId );
1800+ doThrow (new AgentUnavailableException ("Agent down" , hostMockId )).when (agentManagerMock ).send (anyLong (), any (UnmanageInstanceCommand .class ));
1801+ CloudRuntimeException exception = assertThrows (CloudRuntimeException .class , () -> virtualMachineManagerImpl .persistDomainForKVM (vmInstanceMock ));
1802+ assertEquals ("Failed to send command, agent unavailable" , exception .getMessage ());
1803+ }
1804+
1805+ @ Test
1806+ public void testPersistDomainForKvmOperationTimedOut () throws AgentUnavailableException , OperationTimedoutException {
1807+ when (vmInstanceMock .getState ()).thenReturn (VirtualMachine .State .Running );
1808+ when (vmInstanceMock .getHostId ()).thenReturn (hostMockId );
1809+ doThrow (new OperationTimedoutException (null , hostMockId , 123L , 60 , false )).when (agentManagerMock ).send (anyLong (), any (UnmanageInstanceCommand .class ));
1810+ CloudRuntimeException exception = assertThrows (CloudRuntimeException .class , () -> virtualMachineManagerImpl .persistDomainForKVM (vmInstanceMock ));
1811+ assertEquals ("Failed to send command, operation timed out" , exception .getMessage ());
1812+ }
16441813}
0 commit comments