package org.ovirt.engine.core.bll.network.host; import static org.hamcrest.Matchers.hasEntry; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import org.ovirt.engine.core.common.businessentities.HostDevice; import org.ovirt.engine.core.common.businessentities.HostDeviceId; import org.ovirt.engine.core.common.businessentities.network.HostNicVfsConfig; import org.ovirt.engine.core.common.businessentities.network.VdsNetworkInterface; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.dao.HostDeviceDao; import org.ovirt.engine.core.dao.network.HostNicVfsConfigDao; import org.ovirt.engine.core.dao.network.InterfaceDao; import org.ovirt.engine.core.utils.RandomUtils; @RunWith(MockitoJUnitRunner.class) public class NetworkDeviceHelperImplTest { private static final String NIC_NAME = RandomUtils.instance().nextString(5); private static final Guid NIC_ID = Guid.newGuid(); private static final Guid HOST_ID = Guid.newGuid(); private static final String NET_DEVICE_NAME = RandomUtils.instance().nextString(5); private static final String PCI_DEVICE_NAME = RandomUtils.instance().nextString(5); private static final String PCI_DEVICE_NAME_2 = RandomUtils.instance().nextString(5); private static int TOTAL_NUM_OF_VFS = 7; @Mock private HostDevice netDevice; @Mock private HostDevice pciDevice; @Mock private VdsNetworkInterface nic; @Mock private HostNicVfsConfig hostNicVfsConfig; @Mock private InterfaceDao interfaceDao; @Mock private HostDeviceDao hostDeviceDao; @Mock private HostNicVfsConfigDao hostNicVfsConfigDao; @Captor private ArgumentCaptor<HostDeviceId> hostDeviceIdCaptor; @Captor private ArgumentCaptor<Guid> vmIdCaptor; private NetworkDeviceHelperImpl networkDeviceHelper; @Before public void setUp() { networkDeviceHelper = new NetworkDeviceHelperImpl(interfaceDao, hostDeviceDao, hostNicVfsConfigDao); when(netDevice.getHostId()).thenReturn(HOST_ID); when(netDevice.getDeviceName()).thenReturn(NET_DEVICE_NAME); when(netDevice.getName()).thenReturn(NET_DEVICE_NAME); when(netDevice.getNetworkInterfaceName()).thenReturn(NIC_NAME); when(netDevice.getParentDeviceName()).thenReturn(PCI_DEVICE_NAME); when(pciDevice.getHostId()).thenReturn(HOST_ID); when(pciDevice.getDeviceName()).thenReturn(PCI_DEVICE_NAME); when(pciDevice.getName()).thenReturn(PCI_DEVICE_NAME); List<HostDevice> devices = new ArrayList<>(); devices.add(netDevice); devices.add(pciDevice); mockHostDevices(devices); when(nic.getId()).thenReturn(NIC_ID); when(nic.getName()).thenReturn(NIC_NAME); when(nic.getVdsId()).thenReturn(HOST_ID); when(interfaceDao.get(NIC_ID)).thenReturn(nic); when(nic.getName()).thenReturn(NIC_NAME); when(hostNicVfsConfig.getNicId()).thenReturn(NIC_ID); } @Test public void getNicByPciDeviceNotParentOfNetDevice() { assertNull(networkDeviceHelper.getNicByPciDevice(netDevice)); } @Test public void getNicByNetDeviceNoNic() { VdsNetworkInterface newNic = new VdsNetworkInterface(); newNic.setName(netDevice.getNetworkInterfaceName() + "not"); mockNics(Collections.singletonList(newNic), false); assertNull(networkDeviceHelper.getNicByPciDevice(pciDevice)); } @Test public void getNicByNetDeviceValid() { mockNics(Collections.emptyList(), true); assertEquals(nic, networkDeviceHelper.getNicByPciDevice(pciDevice)); } @Test public void getNicByNetDeviceWithNonDbDevicesNoNetDevice() { mockNics(Collections.emptyList(), true); Collection<HostDevice> devices = new ArrayList<>(); devices.add(pciDevice); assertNull(networkDeviceHelper.getNicByPciDevice(pciDevice, devices)); } @Test public void isSriovNetworkDeviceNotSriov() { commonIsSriovDevice(false); } @Test public void isSriovNetworkDeviceSriov() { commonIsSriovDevice(true); } private void commonIsSriovDevice(boolean isSriov) { when(pciDevice.getTotalVirtualFunctions()).thenReturn(isSriov ? TOTAL_NUM_OF_VFS : null); assertEquals(isSriov, networkDeviceHelper.isSriovDevice(pciDevice)); } @Test public void isNetworkDevicePossitive() { assertFalse(networkDeviceHelper.isNetworkDevice(pciDevice)); } @Test public void isNetworkDeviceNegtive() { assertTrue(networkDeviceHelper.isNetworkDevice(netDevice)); } @Test public void updateHostNicVfsConfigWithNumVfsData() { commonUpdateHostNicVfsConfigWithNumVfsData(4); } @Test public void updateHostNicVfsConfigWithNumVfsDataZeroVfs() { commonUpdateHostNicVfsConfigWithNumVfsData(0); } private void commonUpdateHostNicVfsConfigWithNumVfsData(int numOfVfs) { when(pciDevice.getTotalVirtualFunctions()).thenReturn(TOTAL_NUM_OF_VFS); List<HostDevice> vfs = mockVfsOnNetDevice(numOfVfs); mockHostDevices(vfs); networkDeviceHelper.updateHostNicVfsConfigWithNumVfsData(hostNicVfsConfig); verify(hostNicVfsConfig).setMaxNumOfVfs(TOTAL_NUM_OF_VFS); verify(hostNicVfsConfig).setNumOfVfs(numOfVfs); } @Test public void getHostNicVfsConfigsWithNumVfsDataByHostId() { when(hostNicVfsConfigDao.getAllVfsConfigByHostId(HOST_ID)).thenReturn(Collections.singletonList(hostNicVfsConfig)); when(pciDevice.getTotalVirtualFunctions()).thenReturn(TOTAL_NUM_OF_VFS); List<HostDevice> vfs = mockVfsOnNetDevice(2); mockHostDevices(vfs); List<HostNicVfsConfig> vfsConfigList = networkDeviceHelper.getHostNicVfsConfigsWithNumVfsDataByHostId(HOST_ID); assertEquals(1, vfsConfigList.size()); assertEquals(hostNicVfsConfig, vfsConfigList.get(0)); verify(hostNicVfsConfig).setMaxNumOfVfs(TOTAL_NUM_OF_VFS); verify(hostNicVfsConfig).setNumOfVfs(2); } private List<HostDevice> mockVfsOnNetDevice(int numOfVfs) { return mockVfsOnNetDevice(numOfVfs, null); } private List<HostDevice> mockVfsOnNetDevice(int numOfVfs, Guid vmId) { List<HostDevice> vfs = new ArrayList<>(); for (int i = 0; i < numOfVfs; ++i) { HostDevice vfPciDevice = new HostDevice(); vfPciDevice.setParentPhysicalFunction(pciDevice.getDeviceName()); vfPciDevice.setDeviceName(String.valueOf(i)); vfPciDevice.setHostId(HOST_ID); vfPciDevice.setVmId(vmId); vfs.add(vfPciDevice); } return vfs; } private void mockHostDevices(List<HostDevice> extraDevices) { List<HostDevice> devices = new ArrayList<>(); devices.add(pciDevice); devices.add(netDevice); devices.addAll(extraDevices); when(hostDeviceDao.getHostDevicesByHostId(HOST_ID)).thenReturn(devices); when(hostDeviceDao.getAll()).thenReturn(devices); } @Test(expected = UnsupportedOperationException.class) public void areAllVfsFreeNotSriovNic() { commonIsSriovDevice(false); networkDeviceHelper.areAllVfsFree(nic); } @Test public void areAllVfsFreeTrueNoVfs() { freeVfCommon(0, 0, 0, 0, 0, 0); assertTrue(networkDeviceHelper.areAllVfsFree(nic)); } @Test public void areAllVfsFreeFalseAttachedToVm() { freeVfCommon(7, 3, 0, 0, 0, 0); assertFalse(networkDeviceHelper.areAllVfsFree(nic)); } @Test public void areAllVfsFreeFalseNoNic() { freeVfCommon(6, 0, 1, 0, 0, 0); assertFalse(networkDeviceHelper.areAllVfsFree(nic)); } @Test public void areAllVfsFreeFalseHasNetwork() { freeVfCommon(2, 0, 0, 3, 0, 0); assertFalse(networkDeviceHelper.areAllVfsFree(nic)); } @Test public void areAllVfsFreeFalseHasVlanDevice() { freeVfCommon(4, 0, 0, 0, 3, 0); assertFalse(networkDeviceHelper.areAllVfsFree(nic)); } @Test public void areAllVfsFreeTrue() { freeVfCommon(5, 0, 0, 0, 0, 0); assertTrue(networkDeviceHelper.areAllVfsFree(nic)); } @Test public void areAllVfsFreeFalseMix() { freeVfCommon(1, 2, 3, 4, 5, 6); assertFalse(networkDeviceHelper.areAllVfsFree(nic)); } @Test public void areAllVfsFreeFalseHasVfPartOfBond() { freeVfCommon(4, 0, 0, 0, 0, 1); assertFalse(networkDeviceHelper.areAllVfsFree(nic)); } private List<HostDevice> freeVfCommon(int numOfFreeVfs, int numOfVfsAttachedToVm, int numOfVfsHasNoNic, int numOfVfsHasNetworkAttached, int numOfVfsHasVlanDeviceAttached, int numOfVfsArePartOfBond) { networkDeviceHelper = spy(new NetworkDeviceHelperImpl(interfaceDao, hostDeviceDao, hostNicVfsConfigDao)); List<HostDevice> devices = new ArrayList<>(); List<HostDevice> freeVfs = new ArrayList<>(); int numOfVfs = numOfFreeVfs + numOfVfsAttachedToVm + numOfVfsHasNoNic + numOfVfsHasNetworkAttached + numOfVfsHasVlanDeviceAttached + numOfVfsArePartOfBond; List<HostDevice> vfs = mockVfsOnNetDevice(numOfVfs); List<VdsNetworkInterface> nics = new ArrayList<>(); devices.addAll(vfs); for (HostDevice vfPciDevice : vfs) { HostDevice vfNetDevice = mockNetworkDeviceForPciDevice(vfPciDevice); devices.add(vfNetDevice); if (numOfVfsHasNoNic != 0) { --numOfVfsHasNoNic; } else { VdsNetworkInterface vfNic = mockNicForNetDevice(vfNetDevice); nics.add(vfNic); if (numOfVfsAttachedToVm != 0) { --numOfVfsAttachedToVm; vfPciDevice.setVmId(Guid.newGuid()); } else if (numOfVfsHasNetworkAttached != 0) { --numOfVfsHasNetworkAttached; vfNic.setNetworkName("netName"); } else if (numOfVfsHasVlanDeviceAttached != 0) { --numOfVfsHasVlanDeviceAttached; doReturn(true).when(networkDeviceHelper) .isVlanDeviceAttached(vfNic); } else if (numOfVfsArePartOfBond != 0) { --numOfVfsArePartOfBond; vfNic.setBondName("bondName"); } else { doReturn(false).when(networkDeviceHelper) .isVlanDeviceAttached(vfNic); freeVfs.add(vfPciDevice); } } } mockHostDevices(devices); mockNics(nics, true); return freeVfs; } @Test(expected = UnsupportedOperationException.class) public void getFreeVfNotSriovNic() { commonIsSriovDevice(false); networkDeviceHelper.getFreeVf(nic, null); } @Test public void getFreeVfNoVfs() { freeVfCommon(0, 0, 0, 0, 0, 0); assertNull(networkDeviceHelper.getFreeVf(nic, null)); } @Test public void getFreeVfNoFreeVf() { freeVfCommon(0, 1, 2, 3, 4, 5); assertNull(networkDeviceHelper.getFreeVf(nic, null)); } @Test public void getFreeVfOneFreeVf() { List<HostDevice> freeVfs = freeVfCommon(1, 4, 3, 2, 1, 1); assertEquals(1, freeVfs.size()); assertTrue(freeVfs.contains(networkDeviceHelper.getFreeVf(nic, null))); } @Test public void getFreeVfMoreThanOneFreeVf() { List<HostDevice> freeVfs = freeVfCommon(5, 2, 2, 2, 2, 2); assertEquals(5, freeVfs.size()); assertTrue(freeVfs.contains(networkDeviceHelper.getFreeVf(nic, null))); } @Test public void getFreeVfWithExcludedVfs() { List<HostDevice> freeVfs = freeVfCommon(5, 2, 2, 2, 2, 2); assertEquals(5, freeVfs.size()); List<HostDevice> excludedVfs = new ArrayList<>(); excludedVfs.add(freeVfs.get(0)); excludedVfs.add(freeVfs.get(1)); freeVfs.removeAll(excludedVfs); List<String> excludedVfsNames = excludedVfs.stream().map(HostDevice::getDeviceName).collect(Collectors.toList()); assertTrue(freeVfs.contains(networkDeviceHelper.getFreeVf(nic, excludedVfsNames))); } @Test public void isNonNetworkDeviceNetworkFree() { HostDevice device = new HostDevice(); device.setHostId(HOST_ID); device.setDeviceName(PCI_DEVICE_NAME_2); assertTrue(networkDeviceHelper.isDeviceNetworkFree(device)); } @Test public void noNicDeviceNonNetworkFree() { freeVfCommon(0, 0, 1, 0, 0, 0); HostDevice hostDevice = getSingleMockedNonFreeDevice(); assertFalse(networkDeviceHelper.isDeviceNetworkFree(hostDevice)); } @Test public void isNetworkDeviceNonNetworkFree() { freeVfCommon(0, 0, 0, 1, 0, 0); HostDevice hostDevice = getSingleMockedNonFreeDevice(); assertFalse(networkDeviceHelper.isDeviceNetworkFree(hostDevice)); } @Test public void isVlanDeviceNonNetworkFree() { freeVfCommon(0, 0, 0, 0, 1, 0); HostDevice hostDevice = getSingleMockedNonFreeDevice(); assertFalse(networkDeviceHelper.isDeviceNetworkFree(hostDevice)); } @Test public void slaveDeviceNonNetworkFree() { freeVfCommon(0, 0, 0, 0, 0, 1); HostDevice hostDevice = getSingleMockedNonFreeDevice(); assertFalse(networkDeviceHelper.isDeviceNetworkFree(hostDevice)); } /** * Helper method for cases when a single non-free device is mocked by {@link #freeVfCommon} */ private HostDevice getSingleMockedNonFreeDevice() { List<HostDevice> devices = hostDeviceDao.getAll(); // freeVfCommon sets up 'netDevice', 'pciDevice', a parent device and the one we specified. assertEquals(4, devices.size()); // the device we are interested in, is the 'parent' return devices.get(2); } private VdsNetworkInterface mockNicForNetDevice(HostDevice netDeviceParam) { VdsNetworkInterface nic = new VdsNetworkInterface(); nic.setVdsId(netDeviceParam.getHostId()); nic.setName(netDeviceParam.getNetworkInterfaceName()); return nic; } private void mockNics(List<VdsNetworkInterface> extraNics, boolean includeDefault) { List<VdsNetworkInterface> nics = new ArrayList<>(); if (includeDefault) { nics.add(nic); } nics.addAll(extraNics); when(interfaceDao.getAllInterfacesForVds(HOST_ID)).thenReturn(nics); } private HostDevice mockNetworkDeviceForPciDevice(HostDevice pciDeviceParam) { HostDevice mockedNetDevice = new HostDevice(); mockedNetDevice.setParentDeviceName(pciDeviceParam.getDeviceName()); mockedNetDevice.setHostId(pciDeviceParam.getHostId()); mockedNetDevice.setDeviceName(pciDeviceParam.getDeviceName() + "netDevice"); mockedNetDevice.setNetworkInterfaceName(mockedNetDevice.getDeviceName() + "iface"); return mockedNetDevice; } @Test public void getPciDeviceNameByNic() { assertEquals(PCI_DEVICE_NAME, networkDeviceHelper.getPciDeviceNameByNic(nic)); } @Test public void setVmIdOnVfs() { List<HostDevice> vfs = mockVfsOnNetDevice(1); vfs.forEach(vf -> vf.setVmId(null)); mockHostDevices(vfs); HostDevice vf = vfs.get(0); Guid vmId = Guid.newGuid(); networkDeviceHelper.setVmIdOnVfs(HOST_ID, vmId, Collections.singleton(vf.getDeviceName())); verify(hostDeviceDao).setVmIdOnHostDevice(hostDeviceIdCaptor.capture(), vmIdCaptor.capture()); HostDeviceId capturedDeviceId = hostDeviceIdCaptor.getValue(); Guid capturedVmId = vmIdCaptor.getValue(); assertEquals(vf.getId(), capturedDeviceId); assertEquals(vmId, capturedVmId); } @Test public void removeVmIdFromVfsNoOtherDeviceWithVmIdTest() { removeVmIdFromVfsCommonTest(4, 0); } @Test public void removeVmIdFromVfsNoVfsWithVmIdTest() { removeVmIdFromVfsCommonTest(0, 2); } @Test public void removeVmIdFromVfsVfsAndOtherDeviceWithVmIdTest() { removeVmIdFromVfsCommonTest(2, 3); } @Test public void removeVmIdFromVfsNoVfsAndNoOtherDeviceWithVmIdTest() { removeVmIdFromVfsCommonTest(0, 0); } private void removeVmIdFromVfsCommonTest(int numOfVfWithVmId, int numOfOtherDeviceWithVmId) { List<HostDevice> allDevices = new ArrayList<>(); List<HostDevice> otherDeviceWithVmId = new ArrayList<>(); Guid vmId = Guid.newGuid(); List<HostDevice> vfs = mockVfsOnNetDevice(numOfVfWithVmId, vmId); allDevices.addAll(vfs); for (int i = 0; i <= numOfOtherDeviceWithVmId; ++i) { HostDevice hostDevice = createHostDevice(vmId); otherDeviceWithVmId.add(hostDevice); } allDevices.addAll(otherDeviceWithVmId); mockHostDevices(allDevices); for (HostDevice vf : vfs) { assertEquals(vmId, vf.getVmId()); } networkDeviceHelper.removeVmIdFromVfs(vmId); for (HostDevice vf : vfs) { vf.setVmId(null); } if (numOfVfWithVmId == 0) { verify(hostDeviceDao, never()).setVmIdOnHostDevice(any(HostDeviceId.class), any(Guid.class)); } else { verify(hostDeviceDao, times(numOfVfWithVmId)).setVmIdOnHostDevice(hostDeviceIdCaptor.capture(), vmIdCaptor.capture()); List<HostDeviceId> capturedDeviceIds = hostDeviceIdCaptor.getAllValues(); List<Guid> capturedVmIds = vmIdCaptor.getAllValues(); for (HostDevice vf : vfs) { assertTrue(capturedDeviceIds.contains(vf.getId())); } for (HostDevice hostDevice : otherDeviceWithVmId) { assertFalse(capturedDeviceIds.contains(hostDevice.getId())); } for (Guid capturedVmId : capturedVmIds) { assertNull(capturedVmId); } } } private HostDevice createHostDevice(Guid vmId) { HostDevice hostDevice = new HostDevice(); hostDevice.setHostId(HOST_ID); hostDevice.setVmId(vmId); return hostDevice; } @Test public void testGetVfMap() { final HostDevice pfNetDevice = new HostDevice(); final HostDevice pfPciDevice = new HostDevice(); final Guid pfNicId = Guid.newGuid(); final String pfNicName = "pf" + NIC_NAME; final String pfPciDeviceName = "pf" + PCI_DEVICE_NAME; pfNetDevice.setHostId(HOST_ID); pfNetDevice.setDeviceName("pf" + NET_DEVICE_NAME); pfNetDevice.setNetworkInterfaceName(pfNicName); pfNetDevice.setParentDeviceName(pfPciDeviceName); pfPciDevice.setHostId(HOST_ID); pfPciDevice.setDeviceName(pfPciDeviceName); pfPciDevice.setDeviceName(pfPciDeviceName); when(pciDevice.getParentPhysicalFunction()).thenReturn(pfPciDeviceName); mockHostDevices(Arrays.asList(pfNetDevice, pfPciDevice, new HostDevice())); when(nic.getVlanId()).thenReturn(null); final VdsNetworkInterface pfNic = new VdsNetworkInterface(); pfNic.setId(pfNicId); pfNic.setName(pfNetDevice.getNetworkInterfaceName()); final VdsNetworkInterface bondNic = new VdsNetworkInterface(); bondNic.setBonded(true); final VdsNetworkInterface vlanNic = new VdsNetworkInterface(); vlanNic.setVlanId(666); mockNics(Arrays.asList(pfNic, bondNic, vlanNic), true); final Map<Guid, Guid> actual = networkDeviceHelper.getVfMap(HOST_ID); assertEquals(1, actual.size()); assertThat(actual, hasEntry(NIC_ID, pfNicId)); } }