package org.ovirt.engine.core.bll.numa.vm;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.ovirt.engine.core.bll.utils.NumaTestUtils.createVdsNumaNode;
import static org.ovirt.engine.core.bll.utils.NumaTestUtils.createVmNumaNode;
import static org.ovirt.engine.core.bll.utils.NumaTestUtils.mockVdsNumaNodeDao;
import static org.ovirt.engine.core.bll.validator.ValidationResultMatchers.failsWith;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.ovirt.engine.core.bll.ValidationResult;
import org.ovirt.engine.core.common.businessentities.MigrationSupport;
import org.ovirt.engine.core.common.businessentities.NumaTuneMode;
import org.ovirt.engine.core.common.businessentities.VM;
import org.ovirt.engine.core.common.businessentities.VdsNumaNode;
import org.ovirt.engine.core.common.businessentities.VmNumaNode;
import org.ovirt.engine.core.common.errors.EngineMessage;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.core.dao.VdsNumaNodeDao;
import org.ovirt.engine.core.utils.MockConfigRule;
@RunWith(MockitoJUnitRunner.class)
public class NumaValidatorTest {
@Rule
public MockConfigRule mcr = new MockConfigRule();
@Mock
private VdsNumaNodeDao vdsNumaNodeDao;
@InjectMocks
private NumaValidator underTest;
private ArrayList<VdsNumaNode> vdsNumaNodes;
private VM vm;
private ArrayList<VmNumaNode> vmNumaNodes;
@Before
public void setUp() throws Exception {
vdsNumaNodes = new ArrayList<>(Arrays.asList(createVdsNumaNode(1), createVdsNumaNode(2), createVdsNumaNode(3)));
vmNumaNodes = new ArrayList<>(Arrays.asList(createVmNumaNode(0, vdsNumaNodes), createVmNumaNode(1)));
mockVdsNumaNodeDao(vdsNumaNodeDao, vdsNumaNodes);
vm = new VM();
vm.setId(Guid.newGuid());
vm.setDedicatedVmForVdsList(Collections.singletonList(Guid.newGuid()));
vm.setNumOfSockets(1);
vm.setCpuPerSocket(2);
vm.setVmMemSizeMb(4000);
vm.setMigrationSupport(MigrationSupport.PINNED_TO_HOST);
vm.setNumaTuneMode(NumaTuneMode.INTERLEAVE);
vm.setvNumaNodeList(vmNumaNodes);
}
@Test
public void shouldSetNumaPinning() {
assertTrue(underTest.checkVmNumaNodesIntegrity(vm, vm.getvNumaNodeList()).isValid());
}
@Test
public void shouldHandleNoNumaNodes() {
vm.setvNumaNodeList(null);
assertTrue(underTest.checkVmNumaNodesIntegrity(vm, vm.getvNumaNodeList()).isValid());
}
@Test
public void shouldDetectHostWihtoutNumaSupport() {
vdsNumaNodes = new ArrayList(Collections.singletonList(createVdsNumaNode(1)));
assertValidationFailure(underTest.validateNumaCompatibility(vm, vm.getvNumaNodeList(), vdsNumaNodes),
EngineMessage.HOST_NUMA_NOT_SUPPORTED);
}
@Test
public void shouldDetectZeroHostNodes() {
vdsNumaNodes.clear();
assertValidationFailure(underTest.checkVmNumaNodesIntegrity(vm, vm.getvNumaNodeList()),
EngineMessage.VM_NUMA_PINNED_VDS_NODE_EMPTY);
}
@Test
public void shouldDetectInsufficientMemory() {
vm.setNumaTuneMode(NumaTuneMode.STRICT);
vmNumaNodes.get(0).setMemTotal(1000);
vdsNumaNodes.get(0).setMemTotal(500);
assertValidationFailure(underTest.checkVmNumaNodesIntegrity(vm, vm.getvNumaNodeList()),
EngineMessage.VM_NUMA_NODE_MEMORY_ERROR);
}
@Test
public void shouldDetectTooMuchVmNumaNodes() {
vm.setNumaTuneMode(NumaTuneMode.PREFERRED);
assertValidationFailure(underTest.checkVmNumaNodesIntegrity(vm, vm.getvNumaNodeList()),
EngineMessage.VM_NUMA_NODE_PREFERRED_NOT_PINNED_TO_SINGLE_NODE);
}
@Test
public void shouldDetectTooMuchHostNodes() {
vm.setvNumaNodeList(Collections.singletonList(createVmNumaNode(1, vdsNumaNodes)));
vm.setNumaTuneMode(NumaTuneMode.PREFERRED);
assertValidationFailure(underTest.checkVmNumaNodesIntegrity(vm, vm.getvNumaNodeList()),
EngineMessage.VM_NUMA_NODE_PREFERRED_NOT_PINNED_TO_SINGLE_NODE);
}
@Test
public void shouldDetectDuplicateNodeIndex() {
vmNumaNodes.get(0).setIndex(1);
vmNumaNodes.get(1).setIndex(1);
assertValidationFailure(underTest.checkVmNumaNodesIntegrity(vm, vm.getvNumaNodeList()),
EngineMessage.VM_NUMA_NODE_INDEX_DUPLICATE);
}
@Test
public void shouldDetectNonContinuousNodeIndices() {
vmNumaNodes.get(0).setIndex(0);
vmNumaNodes.get(1).setIndex(2);
assertValidationFailure(underTest.checkVmNumaNodesIntegrity(vm, vm.getvNumaNodeList()),
EngineMessage.VM_NUMA_NODE_NON_CONTINUOUS_INDEX);
}
@Test
public void shouldDetectIndicesNotStartingWithZero() {
vmNumaNodes.get(0).setIndex(2);
vmNumaNodes.get(1).setIndex(3);
assertValidationFailure(underTest.checkVmNumaNodesIntegrity(vm, vm.getvNumaNodeList()),
EngineMessage.VM_NUMA_NODE_NON_CONTINUOUS_INDEX);
}
@Test
public void shouldValidateSingleNodePinning() {
vm.setvNumaNodeList(Collections.singletonList(createVmNumaNode(0, Collections.singletonList(createVdsNumaNode(1)))));
vm.setNumaTuneMode(NumaTuneMode.PREFERRED);
assertTrue(underTest.checkVmNumaNodesIntegrity(vm, vm.getvNumaNodeList()).isValid());
}
@Test
public void shouldDetectMissingPinningEntry() {
vm.getvNumaNodeList().get(0).getVdsNumaNodeList().set(0, null);
assertValidationFailure(underTest.checkVmNumaNodesIntegrity(vm, vm.getvNumaNodeList()),
EngineMessage.VM_NUMA_NODE_PINNED_INDEX_ERROR);
}
@Test
public void shouldDetectSufficientMemory() {
vm.setNumaTuneMode(NumaTuneMode.STRICT);
vmNumaNodes.get(0).setMemTotal(1000);
vdsNumaNodes.get(0).setMemTotal(2000);
assertTrue(underTest.checkVmNumaNodesIntegrity(vm, vm.getvNumaNodeList()).isValid());
}
@Test
public void shouldDetectMissingRequiredHostNumaNodes() {
vdsNumaNodes.remove(0);
assertValidationFailure(underTest.checkVmNumaNodesIntegrity(vm, vm.getvNumaNodeList()),
EngineMessage.VM_NUMA_NODE_HOST_NODE_INVALID_INDEX);
}
@Test
public void shouldOnlyDoWithPinnedToHostMigrationSupport() {
vm.setMigrationSupport(MigrationSupport.MIGRATABLE);
assertValidationFailure(underTest.checkVmNumaNodesIntegrity(vm, vm.getvNumaNodeList()),
EngineMessage.ACTION_TYPE_FAILED_VM_NOT_PINNED_TO_HOST);
}
@Test
public void shouldNotDoWithoutPinnedHost() {
vm.setMigrationSupport(MigrationSupport.MIGRATABLE);
vm.setDedicatedVmForVdsList(new ArrayList<>());
assertValidationFailure(underTest.checkVmNumaNodesIntegrity(vm, vm.getvNumaNodeList()), EngineMessage
.ACTION_TYPE_FAILED_VM_NOT_PINNED_TO_HOST);
}
@Test
public void shouldNotDoWithTwoPinnedHost() {
vm.setDedicatedVmForVdsList(Arrays.asList(Guid.newGuid(), Guid.newGuid()));
assertValidationFailure(underTest.checkVmNumaNodesIntegrity(vm, vm.getvNumaNodeList()),
EngineMessage.ACTION_TYPE_FAILED_VM_PINNED_TO_MULTIPLE_HOSTS);
}
@Test
public void shouldCreateAsMuchNumaNodesAsVirtualCores() {
vm.setNumOfSockets(1);
vm.setCpuPerSocket(2);
assertTrue(underTest.checkVmNumaNodesIntegrity(vm, vm.getvNumaNodeList()).isValid());
}
@Test
public void shouldCreateLessNumaNodesAsVirtualCores() {
vm.setNumOfSockets(1);
vm.setCpuPerSocket(3);
assertTrue(underTest.checkVmNumaNodesIntegrity(vm, vm.getvNumaNodeList()).isValid());
}
@Test
public void failCreateMoreNumaNodesThanVirtualCores() {
vm.setNumOfSockets(1);
vm.setCpuPerSocket(1);
assertValidationFailure(underTest.checkVmNumaNodesIntegrity(vm, vm.getvNumaNodeList()),
EngineMessage.VM_NUMA_NODE_MORE_NODES_THAN_CPUS);
}
@Test
public void shouldDetectDuplicateCpuAssignment() {
vmNumaNodes.get(0).setCpuIds(Collections.singletonList(0));
vmNumaNodes.get(1).setCpuIds(Collections.singletonList(0));
assertValidationFailure(underTest.checkVmNumaNodesIntegrity(vm, vm.getvNumaNodeList()),
EngineMessage.VM_NUMA_NODE_DUPLICATE_CPU_IDS);
}
@Test
public void shouldDetectInvalidCpuIndex() {
vmNumaNodes.get(0).setCpuIds(Collections.singletonList(vm.getNumOfCpus() + 1));
assertValidationFailure(underTest.checkVmNumaNodesIntegrity(vm, vm.getvNumaNodeList()),
EngineMessage.VM_NUMA_NODE_INVALID_CPU_ID);
}
@Test
public void shouldDetectNegativeCpuIndex() {
vmNumaNodes.get(0).setCpuIds(Collections.singletonList(-1));
assertValidationFailure(underTest.checkVmNumaNodesIntegrity(vm, vm.getvNumaNodeList()),
EngineMessage.VM_NUMA_NODE_INVALID_CPU_ID);
}
@Test
public void shouldDetectMoreNumaMemoryThanVmMemory() {
vm.setVmMemSizeMb(1000);
assertValidationFailure(underTest.checkVmNumaNodesIntegrity(vm, vm.getvNumaNodeList()),
EngineMessage.VM_NUMA_NODE_MEMORY_ERROR);
}
private void assertValidationFailure(ValidationResult validationResult, EngineMessage engineMessage) {
assertThat(validationResult, failsWith(engineMessage));
}
}