package org.ovirt.engine.core.bll.validator; import static org.junit.Assert.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.mockito.internal.verification.VerificationModeFactory.atLeastOnce; import static org.ovirt.engine.core.bll.validator.ValidationResultMatchers.failsWith; import static org.ovirt.engine.core.bll.validator.ValidationResultMatchers.isValid; import java.util.ArrayList; import java.util.Arrays; import org.hamcrest.Matcher; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import org.ovirt.engine.core.bll.ValidationResult; import org.ovirt.engine.core.common.businessentities.OriginType; import org.ovirt.engine.core.common.businessentities.VM; import org.ovirt.engine.core.common.businessentities.network.Network; import org.ovirt.engine.core.common.businessentities.network.VmInterfaceType; import org.ovirt.engine.core.common.businessentities.network.VmNic; import org.ovirt.engine.core.common.businessentities.network.VnicProfile; import org.ovirt.engine.core.common.errors.EngineMessage; import org.ovirt.engine.core.common.osinfo.OsRepository; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.compat.Version; import org.ovirt.engine.core.utils.RandomUtils; @RunWith(MockitoJUnitRunner.class) public class VmNicValidatorTest { private static final Guid VNIC_PROFILE_ID = Guid.newGuid(); private static final ArrayList<String> NETWORK_DEVICES = new ArrayList<>( Arrays.asList("rtl8139", "pv")); private final Guid OTHER_GUID = Guid.newGuid(); @Mock private VmNic nic; @Mock private Version version; private VmNicValidator validator; @Mock private VnicProfile vnicProfile; @Mock private Network network; private VM vm; @Before public void setup() { validator = spy(new VmNicValidator(nic, version)); vm = new VM(); } @Test public void e1000VmInterfaceTypeWhenNotIsCompatibleWithOs() throws Exception { isCompatibleWithOsTest(failsWith(EngineMessage.ACTION_TYPE_FAILED_VM_INTERFACE_TYPE_IS_NOT_SUPPORTED_BY_OS), VmInterfaceType.e1000.getValue()); } @Test public void pvVmInterfaceTypeWhenIsCompatibleWithOs() throws Exception { isCompatibleWithOsTest(isValid(), VmInterfaceType.pv.getValue()); } @Test public void rtl8139VmInterfaceTypeWhenIsCompatibleWithOs() throws Exception { isCompatibleWithOsTest(isValid(), VmInterfaceType.rtl8139.getValue()); } private void isCompatibleWithOsTest(Matcher<ValidationResult> matcher, int vmInterfaceType) { VmNicValidator validator = spy(new VmNicValidator(nic, version, 0)); OsRepository osRepository = mock(OsRepository.class); when(validator.getOsRepository()).thenReturn(osRepository); when(osRepository.getNetworkDevices(anyInt(), any(Version.class))).thenReturn(NETWORK_DEVICES); when(nic.getType()).thenReturn(vmInterfaceType); assertThat(validator.isCompatibleWithOs(), matcher); } @Test public void vnicProfileExist() throws Exception { vnicProfileValidationTest(isValid(), true, true); } @Test public void vnicProfileNotExist() throws Exception { vnicProfileValidationTest(failsWith(EngineMessage.ACTION_TYPE_FAILED_VNIC_PROFILE_NOT_EXISTS), false, false); } @Test public void networkInCluster() throws Exception { vnicProfileValidationTest(isValid(), true, true); } @Test public void networkNotInCluster() throws Exception { vnicProfileValidationTest(failsWith(EngineMessage.NETWORK_NOT_EXISTS_IN_CURRENT_CLUSTER), true, false); } private void vnicProfileValidationTest(Matcher<ValidationResult> matcher, boolean profileExists, boolean networkExists) { when(nic.getVnicProfileId()).thenReturn(VNIC_PROFILE_ID); doReturn(profileExists ? vnicProfile : null).when(validator).loadVnicProfile(VNIC_PROFILE_ID); doReturn(networkExists ? network : null).when(validator).getNetworkByVnicProfile(vnicProfile); doReturn(networkExists).when(validator).isNetworkInCluster(network, OTHER_GUID); assertThat(validator.profileValid(OTHER_GUID), matcher); verify(nic, atLeastOnce()).getVnicProfileId(); verify(validator).loadVnicProfile(VNIC_PROFILE_ID); if (networkExists) { verify(validator).getNetworkByVnicProfile(vnicProfile); verify(validator).isNetworkInCluster(network, OTHER_GUID); } } @Test public void typeMatchesProfileBothNotPassthrough() { typeMatchesProfileCommon(false, false); assertThat(validator.typeMatchesProfile(), isValid()); } @Test public void typeMatchesProfilePassthrough() { typeMatchesProfileCommon(true, true); assertThat(validator.typeMatchesProfile(), isValid()); } @Test public void typeMatchesProfileOnlyTypePassthrough() { typeMatchesProfileCommon(true, false); assertThat(validator.typeMatchesProfile(), failsWith(EngineMessage.ACTION_TYPE_FAILED_VM_INTERFACE_TYPE_NOT_MATCH_PROFILE)); } @Test public void typeMatchesProfileOnlyProfilePassthrough() { typeMatchesProfileCommon(false, true); assertThat(validator.typeMatchesProfile(), failsWith(EngineMessage.ACTION_TYPE_FAILED_VM_INTERFACE_TYPE_NOT_MATCH_PROFILE)); } @Test public void typeMatchesProfileTypePassthroughProfileIsNull() { typeMatchesProfileCommon(true, null); assertThat(validator.typeMatchesProfile(), failsWith(EngineMessage.ACTION_TYPE_FAILED_VM_INTERFACE_TYPE_NOT_MATCH_PROFILE)); } @Test public void typeMatchesProfileTypeNotPassthroughProfileIsNull() { typeMatchesProfileCommon(false, null); assertThat(validator.typeMatchesProfile(), isValid()); } private void typeMatchesProfileCommon(boolean typePassthorugh, Boolean profilePassthorugh) { when(nic.getVnicProfileId()).thenReturn(VNIC_PROFILE_ID); doReturn(profilePassthorugh == null ? null : vnicProfile).when(validator).loadVnicProfile(VNIC_PROFILE_ID); if (profilePassthorugh != null) { when(vnicProfile.isPassthrough()).thenReturn(profilePassthorugh); } when(nic.getType()).thenReturn(typePassthorugh ? VmInterfaceType.pciPassthrough.getValue() : ((VmInterfaceType) anyEnumBut(VmInterfaceType.pciPassthrough)).getValue()); } private <T extends Enum<?>> Enum<?> anyEnumBut(T excludeEnum) { Enum<?> returnEnum = excludeEnum; while (returnEnum == excludeEnum) { returnEnum = RandomUtils.instance().nextEnum(excludeEnum.getClass()); } return returnEnum; } @Test public void passthroughVnicLinked() { passthroughIsLinkedCommon(true, true, isValid()); } @Test public void passthroughVnicUnlinked() { passthroughIsLinkedCommon(true, false, failsWith(EngineMessage.ACTION_TYPE_FAILED_UNLINKING_OF_PASSTHROUGH_VNIC_IS_NOT_SUPPORTED)); } @Test public void nonPassthroughVnicLinked() { passthroughIsLinkedCommon(false, true, isValid()); } @Test public void nonPassthroughVnicUnLinked() { passthroughIsLinkedCommon(false, false, isValid()); } private void passthroughIsLinkedCommon(boolean isPassthrough, boolean isLinked, Matcher<ValidationResult> matcher) { when(nic.isPassthrough()).thenReturn(isPassthrough); when(nic.isLinked()).thenReturn(isLinked); assertThat(validator.passthroughIsLinked(), matcher); } @Test public void forbidEmptyProfileForHostedEngineVm(){ vm.setOrigin(OriginType.HOSTED_ENGINE); assertThat(validator.validateProfileNotEmptyForHostedEngineVm(vm), failsWith(EngineMessage.HOSTED_ENGINE_VM_CANNOT_HAVE_NIC_WITH_EMPTY_PROFILE)); } @Test public void allowEmptyProfileForNonHostedEngineVm(){ vm.setOrigin(OriginType.RHEV); assertThat(validator.validateProfileNotEmptyForHostedEngineVm(vm), isValid()); } }