package org.ovirt.engine.core.bll;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.powermock.api.mockito.PowerMockito.doReturn;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
import static org.powermock.api.mockito.PowerMockito.spy;
import static org.powermock.api.mockito.PowerMockito.when;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Matchers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.ovirt.engine.core.bll.interfaces.BackendInternal;
import org.ovirt.engine.core.common.action.AddVmFromTemplateParameters;
import org.ovirt.engine.core.common.action.VmManagementParametersBase;
import org.ovirt.engine.core.common.businessentities.DiskImage;
import org.ovirt.engine.core.common.businessentities.DiskImageBase;
import org.ovirt.engine.core.common.businessentities.DiskImageTemplate;
import org.ovirt.engine.core.common.businessentities.StorageDomainStatus;
import org.ovirt.engine.core.common.businessentities.StorageDomainType;
import org.ovirt.engine.core.common.businessentities.VDSGroup;
import org.ovirt.engine.core.common.businessentities.VM;
import org.ovirt.engine.core.common.businessentities.VmDynamic;
import org.ovirt.engine.core.common.businessentities.VmNetworkInterface;
import org.ovirt.engine.core.common.businessentities.VmStatic;
import org.ovirt.engine.core.common.businessentities.VmTemplate;
import org.ovirt.engine.core.common.businessentities.storage_domain_dynamic;
import org.ovirt.engine.core.common.businessentities.storage_domains;
import org.ovirt.engine.core.common.config.Config;
import org.ovirt.engine.core.common.config.ConfigValues;
import org.ovirt.engine.core.common.interfaces.VDSBrokerFrontend;
import org.ovirt.engine.core.common.queries.VdcQueryParametersBase;
import org.ovirt.engine.core.common.queries.VdcQueryReturnValue;
import org.ovirt.engine.core.common.queries.VdcQueryType;
import org.ovirt.engine.core.common.vdscommands.VDSCommandType;
import org.ovirt.engine.core.common.vdscommands.VDSParametersBase;
import org.ovirt.engine.core.common.vdscommands.VDSReturnValue;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.core.compat.LogCompat;
import org.ovirt.engine.core.compat.LogFactoryCompat;
import org.ovirt.engine.core.compat.NGuid;
import org.ovirt.engine.core.dal.VdcBllMessages;
import org.ovirt.engine.core.dal.dbbroker.DbFacade;
import org.ovirt.engine.core.dao.DiskImageDAO;
import org.ovirt.engine.core.dao.StorageDomainDAO;
import org.ovirt.engine.core.dao.StorageDomainDynamicDAO;
import org.ovirt.engine.core.dao.VdsGroupDAO;
import org.ovirt.engine.core.dao.VmDAO;
import org.ovirt.engine.core.dao.VmTemplateDAO;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
@RunWith(PowerMockRunner.class)
@PrepareForTest({ DbFacade.class, Backend.class, VmHandler.class, Config.class, VmTemplateHandler.class })
public class AddVmCommandTest {
private final int REQUIRED_DISK_SIZE_GB = 10;
private final int AVAILABLE_SPACE_GB = 11;
private final int USED_SPACE_GB = 4;
private final Guid STORAGE_POOL_ID = Guid.NewGuid();
private VmTemplate vmTemplate = null;
@Mock
DbFacade db;
@Mock
VmDAO vmDao;
@Mock
StorageDomainDAO sdDAO;
@Mock
VmTemplateDAO vmTemplateDAO;
@Mock
DiskImageDAO diskImageDAO;
@Mock
StorageDomainDynamicDAO storageDomainDynamicDAO;
@Mock
BackendInternal backend;
@Mock
VDSBrokerFrontend vdsBrokerFrontend;
@Mock
VdsGroupDAO vdsGroupDAO;
public AddVmCommandTest() {
MockitoAnnotations.initMocks(this);
mockStatic(DbFacade.class);
mockStatic(Backend.class);
mockStatic(VmHandler.class);
mockStatic(Config.class);
mockStatic(VmTemplateHandler.class);
}
@Before
public void testSetup() {
mockBackend();
mockDbFacade();
}
@Test
public void create10GBVmWith11GbAvailableAndA5GbBuffer() throws Exception {
setupAllMocks();
VM vm = createVm(REQUIRED_DISK_SIZE_GB);
AddVmFromTemplateCommand<AddVmFromTemplateParameters> cmd = createVmFromTemplateCommand(vm);
mockStorageDomainDAOGet(AVAILABLE_SPACE_GB);
mockUninterestingMethods(cmd);
assertFalse("If the disk is too big, canDoAction should fail", cmd.canDoAction());
assertTrue("canDoAction failed for the wrong reason",
cmd.getReturnValue()
.getCanDoActionMessages()
.contains(VdcBllMessages.ACTION_TYPE_FAILED_DISK_SPACE_LOW.toString()));
}
@Test
public void selectStorageDomainNoneUnderSpaceThreshold() {
final int domainSpaceGB = 5;
final VmTemplate template = setupSelectStorageDomainTests(domainSpaceGB, 10, 0);
assertTrue("acceptable storage domains were found",
Guid.Empty.equals(AddVmCommand.SelectStorageDomain(template)));
}
@Test
public void selectStorageDomainNoneUnderPctThreshold() {
final int sizeRequired = 0;
final int pctRequired = 95;
final int totalDiskGB = 50;
final int domainSpaceGB = totalDiskGB - USED_SPACE_GB; // results in 92% free space
final VmTemplate template = setupSelectStorageDomainTests(domainSpaceGB, sizeRequired, pctRequired);
assertTrue("acceptable storage domains were found",
Guid.Empty.equals(AddVmCommand.SelectStorageDomain(template)));
}
@Test
public void selectStorageDomain() {
final VmTemplate template = setupSelectStorageDomainTests(AVAILABLE_SPACE_GB, 0, 0);
assertFalse("no acceptable storage domains were found",
Guid.Empty.equals(AddVmCommand.SelectStorageDomain(template)));
}
@Test
public void canAddVm() {
ArrayList<String> reasons = new ArrayList<String>();
final int domainSizeGB = 20;
final int sizeRequired = 5;
final int pctRequired = 10;
AddVmCommand<VmManagementParametersBase> cmd = setupCanAddVmTests(domainSizeGB, sizeRequired, pctRequired);
assertTrue("vm could not be added", cmd.CanAddVm(new Object(), reasons));
}
@Test
public void canAddVmFailSpaceThreshold() {
ArrayList<String> reasons = new ArrayList<String>();
final int sizeRequired = 10;
final int pctRequired = 0;
final int domainSizeGB = 4;
AddVmCommand<VmManagementParametersBase> cmd = setupCanAddVmTests(domainSizeGB, sizeRequired, pctRequired);
assertFalse("vm could not be added", cmd.CanAddVm(new Object(), reasons));
assertTrue("canDoAction failed for the wrong reason",
reasons.contains(VdcBllMessages.ACTION_TYPE_FAILED_DISK_SPACE_LOW.toString()));
}
@Test
public void canAddVmFailPctThreshold() {
ArrayList<String> reasons = new ArrayList<String>();
final int sizeRequired = 0;
final int pctRequired = 95;
final int domainSizeGB = 10;
AddVmCommand<VmManagementParametersBase> cmd = setupCanAddVmTests(domainSizeGB, sizeRequired, pctRequired);
assertFalse("vm could not be added", cmd.CanAddVm(new Object(), reasons));
assertTrue("canDoAction failed for the wrong reason",
reasons.contains(VdcBllMessages.ACTION_TYPE_FAILED_DISK_SPACE_LOW.toString()));
}
@Test
public void canAddThinVmFromTemplateWithManyDisks() {
ArrayList<String> reasons = new ArrayList<String>();
final int domainSizeGB = 20;
final int sizeRequired = 10;
final int pctRequired = 10;
AddVmCommand<VmManagementParametersBase> cmd = setupCanAddVmTests(domainSizeGB, sizeRequired, pctRequired);
// Adding 10 disks, which each one should consume the default sparse size (which is 1GB).
setNewDisksForTemplate(10, cmd.getVmTemplate().getDiskMap());
doReturn(createVmTemplate()).when(cmd).getVmTemplate();
assertFalse("Thin vm could not be added due to storage sufficient", cmd.CanAddVm(new Object(), reasons));
assertTrue("canDoAction failed for insufficient disk size",
reasons.contains(VdcBllMessages.ACTION_TYPE_FAILED_DISK_SPACE_LOW.toString()));
}
@Test
public void canAddCloneVmFromTemplate() {
ArrayList<String> reasons = new ArrayList<String>();
final int domainSizeGB = 15;
final int sizeRequired = 4;
final int pctRequired = 10;
AddVmFromTemplateCommand<AddVmFromTemplateParameters> cmd = setupCanAddVmFromTemplateTests(domainSizeGB, sizeRequired, pctRequired);
// Set new Disk Image map with 3GB.
setNewImageDiskMapForTemplate(new Long("3000000000"), cmd.getVmTemplate().getDiskImageMap());
assertFalse("Clone vm could not be added due to storage sufficient", cmd.CanAddVm(new Object(), reasons));
assertTrue("canDoAction failed for insufficient disk size",
reasons.contains(VdcBllMessages.ACTION_TYPE_FAILED_DISK_SPACE_LOW.toString()));
}
@Test
public void canAddCloneVmFromTemplateInvalidPercentage() {
ArrayList<String> reasons = new ArrayList<String>();
final int domainSizeGB = 30;
final int sizeRequired = 6;
final int pctRequired = 53;
AddVmFromTemplateCommand<AddVmFromTemplateParameters> cmd = setupCanAddVmFromTemplateTests(domainSizeGB, sizeRequired, pctRequired);
setNewImageDiskMapForTemplate(new Long("3000000000"), cmd.getVmTemplate().getDiskImageMap());
assertFalse("Thin vm could not be added due to storage sufficient", cmd.CanAddVm(new Object(), reasons));
assertTrue("canDoAction failed for insufficient disk size",
reasons.contains(VdcBllMessages.ACTION_TYPE_FAILED_DISK_SPACE_LOW.toString()));
}
private VmTemplate setupSelectStorageDomainTests(final int domainSpaceGB,
final int sizeRequired,
final int pctRequired) {
mockDiskImageDAOGetSnapshotById();
mockStorageDomainDAOGetForStoragePool(domainSpaceGB);
mockGetImageDomainsListVdsCommand();
mockConfig();
mockConfigSizeRequirements(sizeRequired, pctRequired);
VmTemplate template = new VmTemplate();
template.setstorage_pool_id(Guid.NewGuid());
DiskImageTemplate image = new DiskImageTemplate();
template.addDiskImageTemplate(image);
return template;
}
private AddVmFromTemplateCommand<AddVmFromTemplateParameters> createVmFromTemplateCommand(VM vm) {
AddVmFromTemplateParameters param = new AddVmFromTemplateParameters();
param.setVm(vm);
AddVmFromTemplateCommand<AddVmFromTemplateParameters> concrete = new AddVmFromTemplateCommand<AddVmFromTemplateParameters>(param);
return spy(concrete);
}
private AddVmFromTemplateCommand<AddVmFromTemplateParameters> setupCanAddVmFromTemplateTests(final int domainSizeGB,
final int sizeRequired,
final int pctRequired) {
VM vm = initializeMock(domainSizeGB, sizeRequired, pctRequired);
AddVmFromTemplateCommand<AddVmFromTemplateParameters> cmd = createVmFromTemplateCommand(vm);
initCommandMethods(cmd);
return cmd;
}
private AddVmCommand<VmManagementParametersBase> setupCanAddVmTests(final int domainSizeGB,
final int sizeRequired,
final int pctRequired) {
VM vm = initializeMock(domainSizeGB, sizeRequired, pctRequired);
AddVmCommand<VmManagementParametersBase> cmd = createCommand(vm);
initCommandMethods(cmd);
return cmd;
}
private <T extends VmManagementParametersBase> void initCommandMethods(AddVmCommand<T> cmd) {
doReturn(Guid.NewGuid()).when(cmd).getStoragePoolId();
doReturn(true).when(cmd).CanAddVm(Matchers.<Object> anyObject(), Matchers.<ArrayList> any(ArrayList.class),
anyInt(), anyString(), Matchers.<Guid> any(Guid.class), anyInt());
doReturn(STORAGE_POOL_ID).when(cmd).getStoragePoolId();
}
private VM initializeMock(final int domainSizeGB, final int sizeRequired, final int pctRequired) {
mockVmTemplateDAOReturnVmTemplate();
mockDiskImageDAOGetSnapshotById();
mockStorageDomainDAOGetForStoragePool(domainSizeGB);
mockStorageDomainDAOGet(domainSizeGB);
mockStorageDomainDynamicDAOGet(domainSizeGB, USED_SPACE_GB);
mockGetImageDomainsListVdsCommand();
mockConfig();
mockConfigSizeRequirements(sizeRequired, pctRequired);
VM vm = createVm(8);
return vm;
}
private void setNewDisksForTemplate(int numberOfNewDisks, Map<String, DiskImageTemplate> disksMap) {
for (int newDiskInd = 0; newDiskInd < numberOfNewDisks; newDiskInd++) {
DiskImageTemplate diskImageTempalte = new DiskImageTemplate();
diskImageTempalte.setId(Guid.NewGuid());
disksMap.put(Guid.NewGuid().toString(), diskImageTempalte);
}
}
private void setNewImageDiskMapForTemplate(long diskSize, Map<String, DiskImage> diskImageMap) {
DiskImage diskImage = new DiskImage();
diskImage.setactual_size(diskSize);
diskImageMap.put(Guid.NewGuid().toString(), diskImage);
}
private void setupAllMocks() {
mockVmDAOGetById();
mockStorageDomainDAOGetForStoragePool();
mockVmTemplateDAOReturnVmTemplate();
mockDiskImageDAOGetSnapshotById();
mockStorageDomainDynamicDAOGet();
mockVdsGroupDAOGet();
mockGetImageDomainsListVdsCommand();
mockVmHandler();
mockConfig();
mockConfigSizeDefaults();
}
private void mockBackend() {
when(Backend.getInstance()).thenReturn(backend);
VdcQueryReturnValue returnValue = new VdcQueryReturnValue();
returnValue.setReturnValue(Boolean.FALSE);
when(backend.runInternalQuery(Matchers.<VdcQueryType> any(VdcQueryType.class),
Matchers.any(VdcQueryParametersBase.class))).thenReturn(returnValue);
when(backend.getResourceManager()).thenReturn(vdsBrokerFrontend);
}
private void mockDbFacade() {
when(db.getVmDAO()).thenReturn(vmDao);
when(db.getStorageDomainDAO()).thenReturn(sdDAO);
when(db.getVmTemplateDAO()).thenReturn(vmTemplateDAO);
when(db.getDiskImageDAO()).thenReturn(diskImageDAO);
when(db.getStorageDomainDynamicDAO()).thenReturn(storageDomainDynamicDAO);
when(db.getVdsGroupDAO()).thenReturn(vdsGroupDAO);
when(DbFacade.getInstance()).thenReturn(db);
}
private void mockVmDAOGetById() {
when(vmDao.getById(any(Guid.class))).thenReturn(null);
}
private void mockStorageDomainDAOGetForStoragePool(int domainSpaceGB) {
when(sdDAO.getForStoragePool(Matchers.<Guid> any(Guid.class), Matchers.<NGuid> any(NGuid.class))).thenReturn(createStorageDomain(domainSpaceGB));
}
private void mockStorageDomainDAOGet(int domainSpaceGB) {
when(sdDAO.get(any(Guid.class))).thenReturn(createStorageDomain(domainSpaceGB));
}
private void mockStorageDomainDAOGetForStoragePool() {
mockStorageDomainDAOGetForStoragePool(AVAILABLE_SPACE_GB);
}
private void mockVmTemplateDAOReturnVmTemplate() {
when(vmTemplateDAO.get(Matchers.<Guid> any(Guid.class))).thenReturn(createVmTemplate());
}
private VmTemplate createVmTemplate() {
if (vmTemplate == null) {
vmTemplate = new VmTemplate();
vmTemplate.setstorage_pool_id(STORAGE_POOL_ID);
vmTemplate.addDiskImageTemplate(createDiskImageTemplate());
Map<String, DiskImage> diskImageMap = new HashMap<String, DiskImage>(1);
diskImageMap.put("disk1", createDiskImage());
vmTemplate.setDiskImageMap(diskImageMap);
}
return vmTemplate;
}
private DiskImageTemplate createDiskImageTemplate() {
DiskImageTemplate i = new DiskImageTemplate();
i.setSizeInGigabyte(USED_SPACE_GB + AVAILABLE_SPACE_GB);
i.setId(Guid.NewGuid());
return i;
}
private void mockDiskImageDAOGetSnapshotById() {
when(diskImageDAO.getSnapshotById(Matchers.<Guid> any(Guid.class))).thenReturn(createDiskImage());
}
private DiskImage createDiskImage() {
DiskImage img = new DiskImage();
img.setSizeInGigabytes(REQUIRED_DISK_SIZE_GB);
img.setActualSize(REQUIRED_DISK_SIZE_GB);
img.setimage_group_id(Guid.NewGuid());
return img;
}
private void mockStorageDomainDynamicDAOGet(int freeSpace, int usedSpace) {
when(storageDomainDynamicDAO.get(Matchers.<Guid> any(Guid.class))).thenReturn(createStorageDomainDynamic(freeSpace,
usedSpace));
}
private void mockStorageDomainDynamicDAOGet() {
mockStorageDomainDynamicDAOGet(AVAILABLE_SPACE_GB, USED_SPACE_GB);
}
public void mockVdsGroupDAOGet() {
when(vdsGroupDAO.get(Matchers.<Guid> any(Guid.class))).thenReturn(new VDSGroup());
}
private storage_domain_dynamic createStorageDomainDynamic(final int freeSpace, final int usedSpace) {
return new storage_domain_dynamic(freeSpace, Guid.NewGuid(), usedSpace);
}
private void mockGetImageDomainsListVdsCommand() {
ArrayList<Guid> guids = new ArrayList<Guid>(1);
guids.add(Guid.NewGuid());
VDSReturnValue returnValue = new VDSReturnValue();
returnValue.setReturnValue(guids);
when(vdsBrokerFrontend.RunVdsCommand(eq(VDSCommandType.GetImageDomainsList),
Matchers.<VDSParametersBase> any(VDSParametersBase.class))).thenReturn(returnValue);
}
private storage_domains createStorageDomain(int availableSpace) {
storage_domains sd = new storage_domains();
sd.setstorage_domain_type(StorageDomainType.Master);
sd.setstatus(StorageDomainStatus.Active);
sd.setavailable_disk_size(availableSpace);
sd.setused_disk_size(USED_SPACE_GB);
return sd;
}
private void mockVmHandler() {
when(
VmHandler.VerifyAddVm(
Matchers.<ArrayList> any(ArrayList.class),
anyInt(),
Matchers.<Object> anyObject(),
Matchers.<Guid> any(Guid.class),
Matchers.<Guid> any(Guid.class),
anyBoolean(),
anyBoolean(),
anyInt()
)).thenReturn(Boolean.TRUE);
}
private void mockConfig() {
when(Config.<Object> GetValue(ConfigValues.PredefinedVMProperties, "3.0")).thenReturn("");
when(Config.<Object> GetValue(ConfigValues.UserDefinedVMProperties, "3.0")).thenReturn("");
when(Config.<Object> GetValue(ConfigValues.InitStorageSparseSizeInGB)).thenReturn(new Integer("1"));
}
private void mockConfigSizeRequirements(int requiredSpaceBufferInGB, int requiredSpacePercent) {
when(Config.<Object> GetValue(ConfigValues.FreeSpaceCriticalLowInGB)).thenReturn(requiredSpaceBufferInGB);
when(Config.<Object> GetValue(ConfigValues.FreeSpaceLow)).thenReturn(requiredSpacePercent);
}
private void mockConfigSizeDefaults() {
int requiredSpaceBufferInGB = 5;
int requiredSpacePercent = 0;
mockConfigSizeRequirements(requiredSpaceBufferInGB, requiredSpacePercent);
}
private VM createVm(int diskSize) {
VM vm = new VM();
vm.setDiskSize(diskSize);
VmDynamic dynamic = new VmDynamic();
VmStatic stat = new VmStatic();
stat.setvmt_guid(Guid.NewGuid());
stat.setvm_name("testVm");
stat.setpriority(1);
vm.setStaticData(stat);
vm.setDynamicData(dynamic);
return vm;
}
private AddVmCommand<VmManagementParametersBase> createCommand(VM vm) {
VmManagementParametersBase param = new VmManagementParametersBase(vm);
AddVmCommand<VmManagementParametersBase> concrete = new AddVmCommand<VmManagementParametersBase>(param);
return spy(concrete);
}
private <T extends VmManagementParametersBase> void mockUninterestingMethods(AddVmCommand<T> spy) {
doReturn(true).when(spy).isVmNameValidLength(Matchers.<VM> any(VM.class));
doReturn(STORAGE_POOL_ID).when(spy).getStoragePoolId();
doReturn(createVmTemplate()).when(spy).getVmTemplate();
doReturn(true).when(spy).areParametersLegal(Matchers.<ArrayList> any(ArrayList.class));
doReturn(Collections.<VmNetworkInterface> emptyList()).when(spy).getVmInterfaces();
doReturn(Collections.<DiskImageBase> emptyList()).when(spy).getVmDisks();
spy.setVmTemplateId(Guid.NewGuid());
}
private static LogCompat log = LogFactoryCompat.getLog(AddVmCommandTest.class);
}