package org.ovirt.engine.core.bll;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.ArgumentMatchers.anyMap;
import static org.mockito.ArgumentMatchers.anySet;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
import org.ovirt.engine.core.bll.storage.disk.DiskHandler;
import org.ovirt.engine.core.bll.utils.PermissionSubject;
import org.ovirt.engine.core.bll.utils.VmDeviceUtils;
import org.ovirt.engine.core.bll.validator.ValidationResultMatchers;
import org.ovirt.engine.core.bll.validator.storage.DiskImagesValidator;
import org.ovirt.engine.core.bll.validator.storage.MultipleDiskVmElementValidator;
import org.ovirt.engine.core.bll.validator.storage.MultipleStorageDomainsValidator;
import org.ovirt.engine.core.common.VdcObjectType;
import org.ovirt.engine.core.common.action.AddVmTemplateParameters;
import org.ovirt.engine.core.common.businessentities.ActionGroup;
import org.ovirt.engine.core.common.businessentities.ArchitectureType;
import org.ovirt.engine.core.common.businessentities.Cluster;
import org.ovirt.engine.core.common.businessentities.StoragePool;
import org.ovirt.engine.core.common.businessentities.StoragePoolStatus;
import org.ovirt.engine.core.common.businessentities.VM;
import org.ovirt.engine.core.common.businessentities.VMStatus;
import org.ovirt.engine.core.common.businessentities.VmEntityType;
import org.ovirt.engine.core.common.businessentities.VmStatic;
import org.ovirt.engine.core.common.businessentities.storage.DiskImage;
import org.ovirt.engine.core.common.errors.EngineMessage;
import org.ovirt.engine.core.common.osinfo.OsRepository;
import org.ovirt.engine.core.common.utils.SimpleDependencyInjector;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.core.compat.Version;
import org.ovirt.engine.core.dao.ClusterDao;
import org.ovirt.engine.core.dao.DiskVmElementDao;
import org.ovirt.engine.core.dao.StoragePoolDao;
import org.ovirt.engine.core.dao.VmDao;
import org.ovirt.engine.core.dao.VmDeviceDao;
import org.ovirt.engine.core.utils.MockConfigRule;
/**
* A test case for {@link AddVmTemplateCommand}
*/
public class AddVmTemplateCommandTest extends BaseCommandTest {
@ClassRule
public static MockConfigRule mcr = new MockConfigRule();
private VM vm = createVM();
@Spy
@InjectMocks
private AddVmTemplateCommand<AddVmTemplateParameters> cmd =
new AddVmTemplateCommand<>(new AddVmTemplateParameters(vm, "templateName", "Template for testing"), null);
@Mock
private VmDao vmDao;
@Mock
private ClusterDao clusterDao;
@Mock
private StoragePoolDao storagePoolDao;
@Mock
private CpuFlagsManagerHandler cpuFlagsManagerHandler;
@Mock
private OsRepository osRepository;
@Mock
private MultipleStorageDomainsValidator multipleSdValidator;
@Mock
private DiskImagesValidator diskImagesValidator;
@Mock
private VmDeviceDao deviceDao;
@Mock
private DiskVmElementDao diskVmElementDao;
@Mock
private DiskHandler diskHandler;
@Spy
@InjectMocks
private VmHandler vmHandler;
@Spy
@InjectMocks
private VmDeviceUtils vmDeviceUtils;
private VM createVM() {
Guid vmId = Guid.newGuid();
Guid clusterId = Guid.newGuid();
Guid spId = Guid.newGuid();
VM vm = new VM();
vm.setId(vmId);
vm.setClusterId(clusterId);
vm.setStoragePoolId(spId);
vm.setVmOs(14);
return vm;
}
@Before
public void setUp() {
when(vmDao.get(vm.getId())).thenReturn(vm);
// The cluster to use
Cluster cluster = new Cluster();
cluster.setCpuName("Intel Conroe Family");
cluster.setArchitecture(ArchitectureType.x86_64);
cluster.setId(vm.getClusterId());
cluster.setStoragePoolId(vm.getStoragePoolId());
cluster.setCompatibilityVersion(Version.getLast());
when(clusterDao.get(vm.getClusterId())).thenReturn(cluster);
mockOsRepository();
doNothing().when(cmd).separateCustomProperties(any(VmStatic.class));
doReturn(getDisksList(vm.getStoragePoolId())).when(cmd).getVmDisksFromDB();
doReturn(vmDeviceUtils).when(cmd).getVmDeviceUtils();
cmd.init();
}
protected void mockOsRepository() {
SimpleDependencyInjector.getInstance().bind(OsRepository.class, osRepository);
vmDeviceUtils.init();
injectorRule.bind(VmDeviceUtils.class, vmDeviceUtils);
injectorRule.bind(CpuFlagsManagerHandler.class, cpuFlagsManagerHandler);
vmHandler.init();
when(osRepository.isWindows(0)).thenReturn(true);
when(osRepository.getMinimumRam(vm.getVmOsId(), Version.getLast())).thenReturn(0);
when(osRepository.getMaximumRam(vm.getVmOsId(), Version.getLast())).thenReturn(100);
when(osRepository.getArchitectureFromOS(14)).thenReturn(ArchitectureType.x86_64);
}
@Test
public void testValidate() {
doReturn(true).when(cmd).validateVmNotDuringSnapshot();
vm.setStatus(VMStatus.Up);
ValidateTestUtils.runAndAssertValidateFailure(cmd, EngineMessage.VMT_CANNOT_CREATE_TEMPLATE_FROM_DOWN_VM);
}
@Test
// When Template by the same name already exists in the datacenter - fail.
public void testValidateDuplicateTemplateName() {
doReturn(true).when(cmd).isVmTemplateWithSameNameExist("templateName", vm.getStoragePoolId());
ValidateTestUtils.runAndAssertValidateFailure(cmd, EngineMessage.ACTION_TYPE_FAILED_NAME_ALREADY_USED);
}
@Test
// When Instance by same name exists - fail (regardless of datacenter).
public void testValidateInstanceNameDuplicate() {
cmd.getParameters().setTemplateType(VmEntityType.INSTANCE_TYPE);
doReturn(true).when(cmd).isInstanceWithSameNameExists("templateName");
ValidateTestUtils.runAndAssertValidateFailure(cmd, EngineMessage.ACTION_TYPE_FAILED_NAME_ALREADY_USED);
}
@Test
public void sufficientStorageSpace() {
setupForStorageTests();
assertTrue(cmd.validateImages());
}
@Test
public void storageSpaceNotWithinThreshold() {
setupForStorageTests();
doReturn(new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_DISK_SPACE_LOW_ON_STORAGE_DOMAIN)).
when(multipleSdValidator).allDomainsWithinThresholds();
assertFalse(cmd.validateImages());
}
@Test
public void insufficientStorageSpace() {
setupForStorageTests();
doReturn(new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_DISK_SPACE_LOW_ON_STORAGE_DOMAIN)).
when(multipleSdValidator).allDomainsHaveSpaceForClonedDisks(anyList());
assertFalse(cmd.validateImages());
}
@Test
public void imagesRelatedChecksFailPassDiscardNotSupported() {
setupForStorageTests();
doReturn(new ValidationResult(EngineMessage.ACTION_TYPE_FAILED_PASS_DISCARD_NOT_SUPPORTED_BY_DISK_INTERFACE))
.when(cmd).isPassDiscardSupportedForImagesDestSds();
assertFalse(cmd.validateImages());
}
@Test
public void passDiscardSupportedForDestSds() {
assertThat(cmd.isPassDiscardSupportedForImagesDestSds(), ValidationResultMatchers.isValid());
}
@Test
public void passDiscardNotSupportedForDestSds() {
mockPassDiscardSupportedForDestSds(new ValidationResult(
EngineMessage.ACTION_TYPE_FAILED_PASS_DISCARD_NOT_SUPPORTED_BY_DISK_INTERFACE));
assertThat(cmd.isPassDiscardSupportedForImagesDestSds(), ValidationResultMatchers.failsWith(
EngineMessage.ACTION_TYPE_FAILED_PASS_DISCARD_NOT_SUPPORTED_BY_DISK_INTERFACE
));
}
@Test
public void testBeanValidations() {
assertTrue(cmd.validateInputs());
}
@Test
public void testPatternBasedNameFails() {
cmd.getParameters().setName("aa-??bb");
assertFalse("Pattern-based name should not be supported for Template", cmd.validateInputs());
}
@Test
public void testOneEmptyDiskAlias() {
Map<Guid, DiskImage> diskInfoDestinationMap = new HashMap<>();
DiskImage disk1 = new DiskImage();
disk1.setDiskAlias("");
diskInfoDestinationMap.put(Guid.newGuid(), disk1);
cmd.diskInfoDestinationMap = diskInfoDestinationMap;
assertFalse(cmd.isDisksAliasNotEmpty());
}
@Test
public void testOneOfManyEmptyDiskAlias() {
Map<Guid, DiskImage> diskInfoDestinationMap = new HashMap<>();
DiskImage disk1 = new DiskImage();
DiskImage disk2 = new DiskImage();
disk1.setDiskAlias("");
disk2.setDiskAlias("disk");
diskInfoDestinationMap.put(Guid.newGuid(), disk1);
diskInfoDestinationMap.put(Guid.newGuid(), disk2);
cmd.diskInfoDestinationMap = diskInfoDestinationMap;
assertFalse(cmd.isDisksAliasNotEmpty());
}
@Test
public void testDiskAliasNotEmpty() {
Map<Guid, DiskImage> diskInfoDestinationMap = new HashMap<>();
DiskImage disk1 = new DiskImage();
DiskImage disk2 = new DiskImage();
disk1.setDiskAlias("disk");
disk2.setDiskAlias("disk");
diskInfoDestinationMap.put(Guid.newGuid(), disk1);
diskInfoDestinationMap.put(Guid.newGuid(), disk2);
cmd.diskInfoDestinationMap = diskInfoDestinationMap;
assertTrue(cmd.isDisksAliasNotEmpty());
}
@Test
public void testPermissionsForAddingTemplateDedicatedHostNotChanged(){
setupDedicatedHostForVmAndTemplate(true);
List<PermissionSubject> permissionCheckSubjects = cmd.getPermissionCheckSubjects();
for(PermissionSubject permissionSubject : permissionCheckSubjects){
assertFalse(ActionGroup.EDIT_ADMIN_TEMPLATE_PROPERTIES.equals(permissionSubject.getActionGroup()));
}
}
@Test
public void testPermissionsForAddingTemplateDedicatedHostChanged(){
setupDedicatedHostForVmAndTemplate(false);
PermissionSubject editDefaultHostPermission = new PermissionSubject(vm.getStoragePoolId(),
VdcObjectType.StoragePool,
ActionGroup.EDIT_ADMIN_TEMPLATE_PROPERTIES);
List<PermissionSubject> permissionCheckSubjects = cmd.getPermissionCheckSubjects();
permissionCheckSubjects.stream()
.filter(permissionSubject ->
ActionGroup.EDIT_ADMIN_TEMPLATE_PROPERTIES == permissionSubject.getActionGroup())
.forEach(permissionSubject -> verifyPermissions(editDefaultHostPermission, permissionSubject));
}
private void verifyPermissions(PermissionSubject editDefaultHostPermission, PermissionSubject permissionSubject) {
assertEquals(permissionSubject.getMessage(), editDefaultHostPermission.getMessage());
assertEquals(permissionSubject.getActionGroup(), editDefaultHostPermission.getActionGroup());
assertEquals(permissionSubject.getObjectId(), editDefaultHostPermission.getObjectId());
assertEquals(permissionSubject.getObjectType(), editDefaultHostPermission.getObjectType());
}
private void setupDedicatedHostForVmAndTemplate(boolean setDefaultHostForTemplate){
Guid hostId = Guid.newGuid();
vm.setDedicatedVmForVdsList(Collections.singletonList(hostId));
AddVmTemplateParameters parameters = new AddVmTemplateParameters();
VmStatic vmStatic = new VmStatic();
vmStatic.setDedicatedVmForVdsList(setDefaultHostForTemplate ? Collections.singletonList(hostId) : Collections.emptyList());
parameters.setMasterVm(vmStatic);
parameters.setTemplateType(VmEntityType.TEMPLATE);
doReturn(parameters).when(cmd).getParameters();
}
private void setupForStorageTests() {
doReturn(true).when(cmd).validateVmNotDuringSnapshot();
vm.setStatus(VMStatus.Down);
doReturn(multipleSdValidator).when(cmd).getStorageDomainsValidator(any(Guid.class), anySet());
setupStoragePool();
}
private void setupStoragePool() {
StoragePool storagePool = new StoragePool();
storagePool.setId(vm.getStoragePoolId());
storagePool.setStatus(StoragePoolStatus.Up);
when(storagePoolDao.get(vm.getStoragePoolId())).thenReturn(storagePool);
}
private List<DiskImage> getDisksList(Guid spId) {
DiskImage disk = new DiskImage();
disk.setStorageIds(new ArrayList<>(Collections.singletonList(spId)));
return Collections.singletonList(disk);
}
private void mockPassDiscardSupportedForDestSds(ValidationResult validationResult) {
cmd.diskInfoDestinationMap = Collections.emptyMap();
MultipleDiskVmElementValidator multipleDiskVmElementValidator = mock(MultipleDiskVmElementValidator.class);
doReturn(multipleDiskVmElementValidator).when(cmd).createMultipleDiskVmElementValidator(anyMap());
when(multipleDiskVmElementValidator.isPassDiscardSupportedForDestSds(anyMap())).thenReturn(validationResult);
}
}