blob: e5239a6512306b2e95e4b9c8b92149c053f88962 [file]
// 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 com.cloud.hypervisor;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.utils.bytescale.ByteScaleUtils;
import org.junit.After;
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 com.cloud.agent.api.to.NicTO;
import com.cloud.agent.api.to.VirtualMachineTO;
import com.cloud.configuration.ConfigurationManagerImpl;
import com.cloud.host.HostVO;
import com.cloud.host.dao.HostDao;
import com.cloud.hypervisor.kvm.dpdk.DpdkHelper;
import com.cloud.offering.ServiceOffering;
import com.cloud.service.ServiceOfferingDetailsVO;
import com.cloud.service.ServiceOfferingVO;
import com.cloud.service.dao.ServiceOfferingDao;
import com.cloud.service.dao.ServiceOfferingDetailsDao;
import com.cloud.storage.GuestOSHypervisorVO;
import com.cloud.storage.GuestOSVO;
import com.cloud.storage.dao.GuestOSDao;
import com.cloud.storage.dao.GuestOSHypervisorDao;
import com.cloud.utils.Pair;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachineProfile;
import org.apache.cloudstack.framework.config.impl.ConfigDepotImpl;
import java.math.BigDecimal;
import java.math.RoundingMode;
@RunWith(MockitoJUnitRunner.class)
public class KVMGuruTest {
@Mock
HostDao hostDao;
@Mock
ServiceOfferingDetailsDao serviceOfferingDetailsDao;
@Spy
@InjectMocks
private KVMGuru guru = new KVMGuru();
@Mock
VirtualMachineTO vmTO;
@Mock
VirtualMachineProfile vmProfile;
@Mock
VirtualMachine vm;
@Mock
HostVO host;
@Mock
ServiceOffering serviceOffering;
@Mock
ServiceOfferingDetailsVO detail1;
@Mock
ServiceOfferingDetailsVO detail2;
@Mock
ServiceOfferingVO serviceOfferingVoMock;
@Mock
VirtualMachine virtualMachineMock;
@Mock
ServiceOfferingDao serviceOfferingDaoMock;
@Mock
DpdkHelper dpdkHelperMock;
@Mock
GuestOSVO guestOsVoMock;
@Mock
GuestOSHypervisorVO guestOsMappingMock;
@Mock
GuestOSHypervisorDao guestOSHypervisorDaoMock;
@Mock
GuestOSDao guestOsDaoMock;
private static final long hostId = 1L;
private static final Long offeringId = 1L;
private static final String detail1Key = ApiConstants.EXTRA_CONFIG + "-config-1";
private static final String detail1Value = "value1";
private static final String detail2Key = "detail2";
private static final String detail2Value = "value2";
private ConfigKey<Integer> originalVmServiceOfferingMaxCpuCores;
private ConfigKey<Integer> originalVmServiceOfferingMaxRAMSize;
@Before
public void setup() throws UnsupportedEncodingException {
// Preserve the original value for restoration in tearDown
originalVmServiceOfferingMaxCpuCores = ConfigurationManagerImpl.VM_SERVICE_OFFERING_MAX_CPU_CORES;
originalVmServiceOfferingMaxRAMSize = ConfigurationManagerImpl.VM_SERVICE_OFFERING_MAX_RAM_SIZE;
Mockito.when(vmTO.isLimitCpuUse()).thenReturn(true);
Mockito.when(vmProfile.getVirtualMachine()).thenReturn(vm);
Mockito.when(vm.getHostId()).thenReturn(hostId);
Mockito.when(hostDao.findById(hostId)).thenReturn(host);
Mockito.lenient().when(host.getCpus()).thenReturn(3);
Mockito.when(host.getSpeed()).thenReturn(1995L);
Mockito.when(vmTO.getMaxSpeed()).thenReturn(500);
Mockito.lenient().when(serviceOffering.getId()).thenReturn(offeringId);
Mockito.lenient().when(vmProfile.getServiceOffering()).thenReturn(serviceOffering);
Mockito.lenient().when(detail1.getName()).thenReturn(detail1Key);
Mockito.lenient().when(detail1.getValue()).thenReturn(detail1Value);
Mockito.lenient().when(detail1.getResourceId()).thenReturn(offeringId);
Mockito.lenient().when(detail2.getName()).thenReturn(detail2Key);
Mockito.lenient().when(detail2.getResourceId()).thenReturn(offeringId);
Mockito.lenient().when(detail2.getValue()).thenReturn(detail2Value);
Mockito.lenient().when(serviceOfferingDetailsDao.listDetails(offeringId)).thenReturn(
Arrays.asList(detail1, detail2));
}
@After
public void tearDown() {
// Restore the original value
ConfigurationManagerImpl.VM_SERVICE_OFFERING_MAX_CPU_CORES = originalVmServiceOfferingMaxCpuCores;
ConfigurationManagerImpl.VM_SERVICE_OFFERING_MAX_RAM_SIZE = originalVmServiceOfferingMaxRAMSize;
}
@Test
public void testSetVmQuotaPercentage() {
guru.setVmQuotaPercentage(vmTO, vmProfile);
Mockito.verify(vmTO).setCpuQuotaPercentage(Mockito.anyDouble());
}
@Test
public void testSetVmQuotaPercentageNullHost() {
Mockito.when(hostDao.findById(hostId)).thenReturn(null);
guru.setVmQuotaPercentage(vmTO, vmProfile);
Mockito.verify(vmTO, Mockito.never()).setCpuQuotaPercentage(Mockito.anyDouble());
}
@Test
public void testSetVmQuotaPercentageZeroDivision() {
Mockito.when(host.getSpeed()).thenReturn(0l);
guru.setVmQuotaPercentage(vmTO, vmProfile);
Mockito.verify(vmTO, Mockito.never()).setCpuQuotaPercentage(Mockito.anyDouble());
}
@Test
public void testSetVmQuotaPercentageNotCPULimit() {
Mockito.when(vmTO.isLimitCpuUse()).thenReturn(false);
guru.setVmQuotaPercentage(vmTO, vmProfile);
Mockito.verify(vmProfile, Mockito.never()).getVirtualMachine();
Mockito.verify(vmTO, Mockito.never()).setCpuQuotaPercentage(Mockito.anyDouble());
}
@Test
public void testSetVmQuotaPercentageOverProvision() {
Mockito.when(vmTO.getMaxSpeed()).thenReturn(3000);
guru.setVmQuotaPercentage(vmTO, vmProfile);
Mockito.verify(vmTO).setCpuQuotaPercentage(1d);
}
@Test
public void getVmMaxMemoryTestConsiderKvmMemoryDynamicScalingCapacitySettingWhenItIsGreaterThanZero() {
int maxMemoryConfigValue = 64;
ConfigDepotImpl configDepotMock = Mockito.mock(ConfigDepotImpl.class);
ConfigKey.init(configDepotMock);
Mockito.when(configDepotMock.getConfigStringValue(Mockito.any(), Mockito.any(), Mockito.any()))
.thenReturn(String.valueOf(maxMemoryConfigValue));
long result = guru.getVmMaxMemory(serviceOfferingVoMock, "Vm description", 1L, 1L);
ConfigKey.init(null);
Assert.assertEquals(ByteScaleUtils.mebibytesToBytes(maxMemoryConfigValue), result);
}
@Test
public void getVmMaxMemoryTestConsiderHostMaxMemoryWhenKvmMemoryDynamicScalingCapacitySettingIsEqualToZero() {
long maxHostMemory = ByteScaleUtils.mebibytesToBytes(2000);
long result = guru.getVmMaxMemory(serviceOfferingVoMock, "Vm description", maxHostMemory, 1L);
Assert.assertEquals(maxHostMemory, result);
}
@Test
public void getVmMaxCpuCoresTestConsiderKvmCpuDynamicScalingCapacitySettingWhenItIsGreaterThanZero() {
int maxCpuCoresConfig = 16;
ConfigDepotImpl configDepotMock = Mockito.mock(ConfigDepotImpl.class);
ConfigKey.init(configDepotMock);
Mockito.when(configDepotMock.getConfigStringValue(Mockito.any(), Mockito.any(), Mockito.any()))
.thenReturn(String.valueOf(maxCpuCoresConfig));
long result = guru.getVmMaxCpuCores(serviceOfferingVoMock, "Vm description", 1, 1L);
ConfigKey.init(null);
Assert.assertEquals(maxCpuCoresConfig, result);
}
@Test
public void getVmMaxCpuCoresTestConsiderHostMaxCpuWhenKvmCpuDynamicScalingCapacitySettingIsEqualToZero() {
int maxHostCpuCores = 64;
long result = guru.getVmMaxCpuCores(serviceOfferingVoMock, "Vm description", maxHostCpuCores, 1L);
Assert.assertEquals(maxHostCpuCores, result);
}
@Test
public void validateGetHostMaxMemoryAndCpuCoresHostNotNull(){
Long maxMemory = 2048l;
Integer maxCpuCores = 16;
Mockito.when(host.getTotalMemory()).thenReturn(maxMemory);
Mockito.when(host.getCpus()).thenReturn(maxCpuCores);
Pair<Long, Integer> result = guru.getHostMaxMemoryAndCpuCores(host, virtualMachineMock, "Vm description");
Assert.assertEquals(new Pair<>(maxMemory, maxCpuCores), result);
}
@Test
public void validateGetHostMaxMemoryAndCpuCoresHostNullAndLastHostIdNull(){
Long maxMemory = Long.MAX_VALUE;
Integer maxCpuCores = Integer.MAX_VALUE;
Pair<Long, Integer> result = guru.getHostMaxMemoryAndCpuCores(null, virtualMachineMock, "Vm description");
Assert.assertEquals(new Pair<>(maxMemory, maxCpuCores), result);
}
@Test
public void validateGetHostMaxMemoryAndCpuCoresHostNullAndLastHostIdNotNullAndLastHostNull(){
Long maxMemory = Long.MAX_VALUE;
Integer maxCpuCores = Integer.MAX_VALUE;
guru.hostDao = hostDao;
Mockito.when(virtualMachineMock.getLastHostId()).thenReturn(1l);
Mockito.doReturn(null).when(hostDao).findById(Mockito.any());
Pair<Long, Integer> result = guru.getHostMaxMemoryAndCpuCores(null, virtualMachineMock, "Vm description");
Assert.assertEquals(new Pair<>(maxMemory, maxCpuCores), result);
}
@Test
public void validateGetHostMaxMemoryAndCpuCoresHostNullAndLastHostIdNotNullAndLastHostNotNull(){
Long maxMemory = 2048l;
Integer maxCpuCores = 16;
guru.hostDao = hostDao;
Mockito.when(virtualMachineMock.getLastHostId()).thenReturn(1l);
Mockito.doReturn(host).when(hostDao).findById(Mockito.any());
Mockito.when(host.getTotalMemory()).thenReturn(maxMemory);
Mockito.when(host.getCpus()).thenReturn(maxCpuCores);
Pair<Long, Integer> result = guru.getHostMaxMemoryAndCpuCores(null, virtualMachineMock, "Vm description");
Assert.assertEquals(new Pair<>(maxMemory, maxCpuCores), result);
}
@Test
public void validateConfigureVmMemoryAndCpuCoresServiceOfferingIsDynamicAndVmIsDynamicCallGetMethods(){
guru.serviceOfferingDao = serviceOfferingDaoMock;
Mockito.doReturn(serviceOfferingVoMock).when(serviceOfferingDaoMock).findById(Mockito.anyLong(), Mockito.anyLong());
Mockito.doReturn(true).when(guru).isVmDynamicScalable(Mockito.any(), Mockito.any());
guru.configureVmMemoryAndCpuCores(vmTO, host, virtualMachineMock, vmProfile);
Mockito.verify(guru).getVmMaxMemory(Mockito.any(ServiceOfferingVO.class), Mockito.anyString(), Mockito.anyLong(), Mockito.anyLong());
Mockito.verify(guru).getVmMaxCpuCores(Mockito.any(ServiceOfferingVO.class), Mockito.anyString(), Mockito.anyInt(), Mockito.anyLong());
}
@Test
public void validateConfigureVmMemoryAndCpuCoresServiceOfferingIsNotDynamicAndVmIsDynamicDoNotCallGetMethods(){
guru.serviceOfferingDao = serviceOfferingDaoMock;
Mockito.doReturn(false).when(guru).isVmDynamicScalable(Mockito.any(), Mockito.any());
guru.configureVmMemoryAndCpuCores(vmTO, host, virtualMachineMock, vmProfile);
Mockito.verify(guru, Mockito.never()).getVmMaxMemory(Mockito.any(ServiceOfferingVO.class), Mockito.anyString(), Mockito.anyLong(), Mockito.anyLong());
Mockito.verify(guru, Mockito.never()).getVmMaxCpuCores(Mockito.any(ServiceOfferingVO.class), Mockito.anyString(), Mockito.anyInt(), Mockito.anyLong());
}
@Test
public void validateConfigureVmMemoryAndCpuCoresServiceOfferingIsDynamicAndVmIsNotDynamicDoNotCallGetMethods(){
guru.serviceOfferingDao = serviceOfferingDaoMock;
Mockito.doReturn(false).when(vmTO).isEnableDynamicallyScaleVm();
guru.configureVmMemoryAndCpuCores(vmTO, host, virtualMachineMock, vmProfile);
Mockito.verify(guru, Mockito.never()).getVmMaxMemory(Mockito.any(ServiceOfferingVO.class), Mockito.anyString(), Mockito.anyLong(), Mockito.anyLong());
Mockito.verify(guru, Mockito.never()).getVmMaxCpuCores(Mockito.any(ServiceOfferingVO.class), Mockito.anyString(), Mockito.anyInt(), Mockito.anyLong());
}
@Test
public void validateEnableDpdkIfNeededCallDpdkHelperSetDpdkVhostUserMode() {
Mockito.when(dpdkHelperMock.isDpdkvHostUserModeSettingOnServiceOffering(vmProfile)).thenReturn(Boolean.TRUE);
guru.enableDpdkIfNeeded(vmProfile, vmTO);
Mockito.verify(dpdkHelperMock).setDpdkVhostUserMode(vmTO, vmProfile);
}
@Test
public void validateEnableDpdkIfNeededDoNotCallDpdkHelperSetDpdkVhostUserMode() {
Mockito.when(dpdkHelperMock.isDpdkvHostUserModeSettingOnServiceOffering(vmProfile)).thenReturn(Boolean.FALSE);
guru.enableDpdkIfNeeded(vmProfile, vmTO);
Mockito.verify(dpdkHelperMock, Mockito.times(0)).setDpdkVhostUserMode(vmTO, vmProfile);
}
@Test
public void validateEnableDpdkIfNeededNicSetDpdkEnabledTrue() {
Map<String, String> map = new HashMap<>();
map.put(DpdkHelper.DPDK_NUMA, "test1");
map.put(DpdkHelper.DPDK_HUGE_PAGES, "test2");
NicTO nicTo1 = Mockito.mock(NicTO.class);
NicTO nicTo2 = Mockito.mock(NicTO.class);
NicTO nicTo3 = Mockito.mock(NicTO.class);
NicTO[] nics = {nicTo1, nicTo2, nicTo3};
Mockito.when(vmTO.getType()).thenReturn(VirtualMachine.Type.User);
Mockito.when(vmTO.getExtraConfig()).thenReturn(map);
Mockito.when(vmTO.getNics()).thenReturn(nics);
guru.enableDpdkIfNeeded(vmProfile, vmTO);
for (NicTO nic : nics) {
Mockito.verify(nic).setDpdkEnabled(true);
}
}
@Test
public void validateConfigureVmOsDescriptionHostNotNullAndGuestOsMappingNotNullAndGuestOsDisplayNameNotNull(){
guru._guestOsDao = guestOsDaoMock;
guru._guestOsHypervisorDao = guestOSHypervisorDaoMock;
VirtualMachineTO virtualMachineTo = new VirtualMachineTO() {};
String platformEmulator = "Ubuntu";
Mockito.doReturn(guestOsVoMock).when(guestOsDaoMock).findByIdIncludingRemoved(Mockito.any());
Mockito.doReturn(guestOsMappingMock).when(guestOSHypervisorDaoMock).findByOsIdAndHypervisor(Mockito.anyLong(), Mockito.anyString(), Mockito.any());
Mockito.doReturn(platformEmulator).when(guestOsMappingMock).getGuestOsName();
guru.configureVmOsDescription(virtualMachineMock, virtualMachineTo, host);
Assert.assertEquals(platformEmulator, virtualMachineTo.getPlatformEmulator());
}
@Test
public void validateConfigureVmOsDescriptionHostNotNullAndGuestOsMappingNullAndGuestOsDisplayNameNull(){
guru._guestOsDao = guestOsDaoMock;
guru._guestOsHypervisorDao = guestOSHypervisorDaoMock;
VirtualMachineTO virtualMachineTo = new VirtualMachineTO() {};
Mockito.doReturn(guestOsVoMock).when(guestOsDaoMock).findByIdIncludingRemoved(Mockito.any());
Mockito.doReturn(null).when(guestOSHypervisorDaoMock).findByOsIdAndHypervisor(Mockito.anyLong(), Mockito.anyString(), Mockito.any());
guru.configureVmOsDescription(virtualMachineMock, virtualMachineTo, host);
Assert.assertEquals("Other", virtualMachineTo.getPlatformEmulator());
}
@Test
public void validateConfigureVmOsDescriptionHostNotNullAndGuestOsMappingNullAndGuestOsDisplayNameNotNull(){
guru._guestOsDao = guestOsDaoMock;
guru._guestOsHypervisorDao = guestOSHypervisorDaoMock;
VirtualMachineTO virtualMachineTo = new VirtualMachineTO() {};
String platformEmulator = "Ubuntu";
Mockito.doReturn(guestOsVoMock).when(guestOsDaoMock).findByIdIncludingRemoved(Mockito.any());
Mockito.doReturn(null).when(guestOSHypervisorDaoMock).findByOsIdAndHypervisor(Mockito.anyLong(), Mockito.anyString(), Mockito.any());
Mockito.doReturn(platformEmulator).when(guestOsVoMock).getDisplayName();
guru.configureVmOsDescription(virtualMachineMock, virtualMachineTo, host);
Assert.assertEquals(platformEmulator, virtualMachineTo.getPlatformEmulator());
}
@Test
public void validateConfigureVmOsDescriptionHostNullAndGuestOsMappingNullAndGuestOsDisplayNameNull(){
guru._guestOsDao = guestOsDaoMock;
VirtualMachineTO virtualMachineTo = new VirtualMachineTO() {};
Mockito.doReturn(guestOsVoMock).when(guestOsDaoMock).findByIdIncludingRemoved(Mockito.any());
guru.configureVmOsDescription(virtualMachineMock, virtualMachineTo, host);
Assert.assertEquals("Other", virtualMachineTo.getPlatformEmulator());
}
@Test
public void validateConfigureVmOsDescriptionHostNullAndGuestOsMappingNullAndGuestOsDisplayNameNotNull(){
guru._guestOsDao = guestOsDaoMock;
VirtualMachineTO virtualMachineTo = new VirtualMachineTO() {};
String platformEmulator = "Ubuntu";
Mockito.doReturn(guestOsVoMock).when(guestOsDaoMock).findByIdIncludingRemoved(Mockito.any());
Mockito.doReturn(platformEmulator).when(guestOsVoMock).getDisplayName();
guru.configureVmOsDescription(virtualMachineMock, virtualMachineTo, host);
Assert.assertEquals(platformEmulator, virtualMachineTo.getPlatformEmulator());
}
@Test
public void testGetClusterIdFromVMHost() {
Mockito.when(vm.getHostId()).thenReturn(123l);
HostVO vo = new HostVO("");
Long expected = 5l;
vo.setClusterId(expected);
Mockito.when(hostDao.findById(123l)).thenReturn(vo);
Long clusterId = guru.findClusterOfVm(vm);
Assert.assertEquals(expected, clusterId);
}
@Test
public void testGetClusterIdFromLastVMHost() {
Mockito.when(vm.getHostId()).thenReturn(null);
Mockito.when(vm.getLastHostId()).thenReturn(321l);
HostVO vo = new HostVO("");
Long expected = 7l;
vo.setClusterId(expected);
Mockito.when(hostDao.findById(321l)).thenReturn(vo);
Long clusterId = guru.findClusterOfVm(vm);
Assert.assertEquals(expected, clusterId);
}
@Test
public void testGetNullWhenVMThereIsNoInformationOfUsedHosts() {
Mockito.when(vm.getHostId()).thenReturn(null);
Mockito.when(vm.getLastHostId()).thenReturn(null);
Long clusterId = guru.findClusterOfVm(vm);
Assert.assertNull(clusterId);
}
@Test
public void getCpuQuotaPercentageTestAssertQuotaEqualsVmSpeedDividedByHostSpeed() {
double hostSpeed = 3000;
double vmSpeed = 500;
double expectedQuota = new BigDecimal(vmSpeed / hostSpeed).setScale(2, RoundingMode.HALF_DOWN).doubleValue();
double actualQuota = guru.getCpuQuotaPercentage(vmSpeed, hostSpeed);
Assert.assertEquals(expectedQuota, actualQuota, 0.0001);
}
@Test
public void getCpuQuotaPercentageTestAssertQuotaEqualsOneWhenVmSpeedIsGreaterThanHostSpeed() {
double hostSpeed = 3000;
double vmSpeed = 6000;
double expectedQuota = 1;
double actualQuota = guru.getCpuQuotaPercentage(vmSpeed, hostSpeed);
Assert.assertEquals(expectedQuota, actualQuota, 0.0001);
}
@Test
public void getCpuQuotaPercentageTestReturnNullWhenANumberFormatExceptionIsThrown() {
double hostSpeed = 0;
double vmSpeed = 6000;
Double actualQuota = guru.getCpuQuotaPercentage(vmSpeed, hostSpeed);
Assert.assertNull(actualQuota);
}
}