package org.ovirt.engine.core.bll.validator; import static org.junit.Assert.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; 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 java.util.Collections; import java.util.List; 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.bll.network.cluster.ManagementNetworkUtil; import org.ovirt.engine.core.common.businessentities.IscsiBond; import org.ovirt.engine.core.common.businessentities.StoragePool; import org.ovirt.engine.core.common.businessentities.VDS; import org.ovirt.engine.core.common.businessentities.VM; import org.ovirt.engine.core.common.businessentities.VmTemplate; import org.ovirt.engine.core.common.businessentities.network.Network; import org.ovirt.engine.core.common.errors.EngineMessage; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.dal.dbbroker.DbFacade; import org.ovirt.engine.core.dao.IscsiBondDao; import org.ovirt.engine.core.dao.StoragePoolDao; import org.ovirt.engine.core.dao.VdsDao; import org.ovirt.engine.core.dao.VmDao; import org.ovirt.engine.core.dao.VmTemplateDao; import org.ovirt.engine.core.dao.network.NetworkDao; import org.ovirt.engine.core.utils.RandomUtils; @RunWith(MockitoJUnitRunner.class) public class NetworkValidatorTest { private static final String NAMEABLE_NAME = "nameable"; private static final String DEFAULT_NETWORK_NAME = "mynetwork"; private static final String OTHER_NETWORK_NAME = "myothernetwork"; private static final Guid DEFAULT_GUID = Guid.newGuid(); private static final Guid OTHER_GUID = Guid.newGuid(); private static final int DEFAULT_VLAN_ID = 0; private static final int OTHER_VLAN_ID = 1; @Mock private DbFacade dbFacade; @Mock private StoragePoolDao dataCenterDao; @Mock private NetworkDao networkDao; @Mock private Network network; @Mock private StoragePool dataCenter; @Mock private ManagementNetworkUtil managementNetworkUtil; @Mock private VmDao vmDao; private List<Network> networks = new ArrayList<>(); private NetworkValidator validator; @Before public void setup() { // spy on attempts to access the database validator = spy(new NetworkValidator(vmDao, network)); doReturn(dbFacade).when(validator).getDbFacade(); doReturn(managementNetworkUtil).when(validator).getManagementNetworkUtil(); // mock some commonly used Daos when(dbFacade.getStoragePoolDao()).thenReturn(dataCenterDao); when(dbFacade.getNetworkDao()).thenReturn(networkDao); // mock their getters when(dataCenterDao.get(any())).thenReturn(dataCenter); when(networkDao.getAllForDataCenter(any())).thenReturn(networks); } @Test public void networkSet() throws Exception { assertThat(validator.networkIsSet(Guid.newGuid()), isValid()); } @Test public void networkNull() throws Exception { validator = new NetworkValidator(vmDao, null); assertThat(validator.networkIsSet(Guid.newGuid()), failsWith(EngineMessage.NETWORK_HAVING_ID_NOT_EXISTS)); } @Test public void dataCenterDoesntExist() throws Exception { when(dataCenterDao.get(any())).thenReturn(null); assertThat(validator.dataCenterExists(), failsWith(EngineMessage.ACTION_TYPE_FAILED_STORAGE_POOL_NOT_EXIST)); } @Test public void dataCenterExists() throws Exception { assertThat(validator.dataCenterExists(), isValid()); } private void stpTest(Matcher<ValidationResult> matcher, boolean vmNetwork, boolean stp) { when(network.isVmNetwork()).thenReturn(vmNetwork); when(network.getStp()).thenReturn(stp); assertThat(validator.stpForVmNetworkOnly(), matcher); } @Test public void stpWhenVmNetwork() throws Exception { stpTest(isValid(), true, true); } @Test public void noStpWhenVmNetwork() throws Exception { stpTest(isValid(), true, false); } @Test public void stpWhenNonVmNetwork() throws Exception { stpTest(failsWith(EngineMessage.NON_VM_NETWORK_CANNOT_SUPPORT_STP), false, true); } @Test public void noStpWhenNonVmNetwork() throws Exception { stpTest(isValid(), false, false); } @Test public void mtuValid() { assertThat(validator.mtuValid(), isValid()); } private void networkPrefixValidTest(Matcher<ValidationResult> matcher, String networkName) { when(network.getName()).thenReturn(networkName); assertThat(validator.networkPrefixValid(), matcher); } @Test public void networkPrefixBond() throws Exception { networkPrefixValidTest(failsWith(EngineMessage.NETWORK_CANNOT_CONTAIN_BOND_NAME), "bond0"); } @Test public void networkPrefixInnocent() throws Exception { networkPrefixValidTest(isValid(), DEFAULT_NETWORK_NAME); } private void vlanIdAvailableTest(Matcher<ValidationResult> matcher, List<Network> networks) { this.networks.addAll(networks); when(network.getVlanId()).thenReturn(DEFAULT_VLAN_ID); when(network.getId()).thenReturn(DEFAULT_GUID); assertThat(validator.vlanIdNotUsed(), matcher); } private static List<Network> getSingletonVlanNetworkList(int vlanId, Guid networkId) { Network network = new Network(); network.setVlanId(vlanId); network.setId(networkId); return Collections.singletonList(network); } @Test public void vlanIdNoNetworks() throws Exception { vlanIdAvailableTest(isValid(), Collections.emptyList()); } @Test public void vlanIdAvailable() throws Exception { vlanIdAvailableTest(isValid(), getSingletonVlanNetworkList(OTHER_VLAN_ID, OTHER_GUID)); } @Test public void vlanIdTakenByDifferentNetwork() throws Exception { vlanIdAvailableTest(failsWith(EngineMessage.NETWORK_VLAN_IN_USE), getSingletonVlanNetworkList(DEFAULT_VLAN_ID, OTHER_GUID)); } @Test public void vlanIdTakenBySameNetwork() throws Exception { vlanIdAvailableTest(isValid(), getSingletonVlanNetworkList(DEFAULT_VLAN_ID, DEFAULT_GUID)); } private void networkNameAvailableTest(Matcher<ValidationResult> matcher, List<Network> networks) { this.networks.addAll(networks); when(network.getName()).thenReturn(DEFAULT_NETWORK_NAME); when(network.getId()).thenReturn(DEFAULT_GUID); assertThat(validator.networkNameNotUsed(), matcher); } private void notIscsiBondNetworkTest(Matcher<ValidationResult> matcher, List<IscsiBond> iscsiBonds) { IscsiBondDao iscsiBondDao = mock(IscsiBondDao.class); when(iscsiBondDao.getIscsiBondsByNetworkId(any())).thenReturn(iscsiBonds); when(dbFacade.getIscsiBondDao()).thenReturn(iscsiBondDao); assertThat(validator.notIscsiBondNetwork(), matcher); } private static List<Network> getSingletonNamedNetworkList(String networkName, Guid networkId) { Network network = mock(Network.class); when(network.getName()).thenReturn(networkName); when(network.getId()).thenReturn(networkId); return Collections.singletonList(network); } private static List<IscsiBond> getIscsiBondList() { List<IscsiBond> iscsiBondList = new ArrayList<>(); IscsiBond iscsiBond = new IscsiBond(); iscsiBond.setId(Guid.newGuid()); iscsiBond.setName("IscsiBond name"); iscsiBondList.add(iscsiBond); return iscsiBondList; } @Test public void noIscsiBondsForNetowrkTest() throws Exception { notIscsiBondNetworkTest(isValid(), Collections.emptyList()); } @Test public void existingIscsiBondsForNetowrkTest() throws Exception { notIscsiBondNetworkTest(failsWith(EngineMessage.NETWORK_CANNOT_REMOVE_ISCSI_BOND_NETWORK), getIscsiBondList()); } @Test public void networkNameNoNetworks() throws Exception { networkNameAvailableTest(isValid(), Collections.emptyList()); } @Test public void networkNameAvailable() throws Exception { networkNameAvailableTest(isValid(), getSingletonNamedNetworkList(OTHER_NETWORK_NAME, OTHER_GUID)); } @Test public void networkNameTakenByDifferentNetwork() throws Exception { networkNameAvailableTest(failsWith(EngineMessage.ACTION_TYPE_FAILED_NETWORK_NAME_IN_USE), getSingletonNamedNetworkList(DEFAULT_NETWORK_NAME, OTHER_GUID)); } @Test public void networkNameTakenCaseSensitivelyByDifferentNetwork() throws Exception { networkNameAvailableTest(isValid(), getSingletonNamedNetworkList(DEFAULT_NETWORK_NAME.toUpperCase(), OTHER_GUID)); } @Test public void networkNameTakenBySameNetwork() throws Exception { networkNameAvailableTest(isValid(), getSingletonNamedNetworkList(DEFAULT_NETWORK_NAME, DEFAULT_GUID)); } private static Matcher<ValidationResult> failsWithOneNetworkInUse() { return failsWith(EngineMessage.ACTION_TYPE_FAILED_NETWORK_IN_ONE_USE); } private static Matcher<ValidationResult> failsWithManyNetworkInUse() { return failsWith(EngineMessage.ACTION_TYPE_FAILED_NETWORK_IN_MANY_USES); } private void networkNotUsedByVmsTest(Matcher<ValidationResult> matcher, List<VM> vms) { when(vmDao.getAllForNetwork(any())).thenReturn(vms); assertThat(validator.networkNotUsedByVms(), matcher); } @Test public void networkNotInUseByVms() throws Exception { networkNotUsedByVmsTest(isValid(), Collections.emptyList()); } @Test public void networkInUseByOneVm() throws Exception { VM vm = mock(VM.class); when(vm.getName()).thenReturn(NAMEABLE_NAME); networkNotUsedByVmsTest(failsWithOneNetworkInUse(), Collections.singletonList(vm)); } @Test public void networkInUseByManyVms() throws Exception { VM vm1 = mock(VM.class); when(vm1.getName()).thenReturn(NAMEABLE_NAME+1); VM vm2 = mock(VM.class); when(vm2.getName()).thenReturn(NAMEABLE_NAME+2); networkNotUsedByVmsTest(failsWithManyNetworkInUse(), Arrays.asList(vm1, vm2)); } private void networkNotUsedByHostsTest(Matcher<ValidationResult> matcher, List<VDS> hosts) { VdsDao hostDao = mock(VdsDao.class); when(hostDao.getAllForNetwork(any())).thenReturn(hosts); when(dbFacade.getVdsDao()).thenReturn(hostDao); assertThat(validator.networkNotUsedByHosts(), matcher); } @Test public void networkNotInUseByHosts() throws Exception { networkNotUsedByHostsTest(isValid(), Collections.emptyList()); } @Test public void networkInUseByOneHost() throws Exception { VDS host = mock(VDS.class); when(host.getName()).thenReturn(NAMEABLE_NAME); networkNotUsedByHostsTest(failsWithOneNetworkInUse(), Collections.singletonList(host)); } @Test public void networkInUseByManyHosts() throws Exception { VDS host1 = mock(VDS.class); when(host1.getName()).thenReturn(NAMEABLE_NAME+1); VDS host2 = mock(VDS.class); when(host2.getName()).thenReturn(NAMEABLE_NAME+2); networkNotUsedByHostsTest(failsWithManyNetworkInUse(), Arrays.asList(host1, host2)); } private void networkNotUsedByTemplatesTest(Matcher<ValidationResult> matcher, List<VmTemplate> templates) { VmTemplateDao templateDao = mock(VmTemplateDao.class); when(templateDao.getAllForNetwork(any())).thenReturn(templates); when(dbFacade.getVmTemplateDao()).thenReturn(templateDao); assertThat(validator.networkNotUsedByTemplates(), matcher); } @Test public void networkNotInUseByTemplates() throws Exception { networkNotUsedByTemplatesTest(isValid(), Collections.emptyList()); } @Test public void networkInUseByOneTemplate() throws Exception { VmTemplate template = mock(VmTemplate.class); when(template.getName()).thenReturn(NAMEABLE_NAME); networkNotUsedByTemplatesTest(failsWithOneNetworkInUse(), Collections.singletonList(template)); } @Test public void networkInUseByManyTemplates() throws Exception { VmTemplate template1 = mock(VmTemplate.class); when(template1.getName()).thenReturn(NAMEABLE_NAME+1); VmTemplate template2 = mock(VmTemplate.class); when(template2.getName()).thenReturn(NAMEABLE_NAME+2); networkNotUsedByTemplatesTest(failsWithManyNetworkInUse(), Arrays.asList(template1, template2)); } @Test public void networkNotLabeled() throws Exception { assertThat(validator.notLabeled(), isValid()); } @Test public void networkLabeled() throws Exception { when(network.getLabel()).thenReturn(RandomUtils.instance().nextPropertyString(10)); assertThat(validator.notLabeled(), failsWith(EngineMessage.ACTION_TYPE_FAILED_NETWORK_ALREADY_LABELED)); } @Test public void testNotExternalNetworkFailsForExternalNetwork() throws Exception { when(network.isExternal()).thenReturn(true); assertThat(validator.notExternalNetwork(), failsWith(EngineMessage.ACTION_TYPE_FAILED_NOT_SUPPORTED_FOR_EXTERNAL_NETWORK)); } @Test public void testNotExternalNetworkSucceedsForNonExternalNetwork() throws Exception { when(network.isExternal()).thenReturn(false); assertThat(validator.notExternalNetwork(), isValid()); } @Test public void testNotManagementNetworkPositive() { when(network.getId()).thenReturn(DEFAULT_GUID); when(managementNetworkUtil.isManagementNetwork(DEFAULT_GUID)).thenReturn(true); assertThat(validator.notManagementNetwork(), failsWith(EngineMessage.NETWORK_CANNOT_REMOVE_MANAGEMENT_NETWORK)); } @Test public void testNotManagementNetworkNegative() { when(network.getId()).thenReturn(DEFAULT_GUID); when(managementNetworkUtil.isManagementNetwork(DEFAULT_GUID)).thenReturn(false); assertThat(validator.notManagementNetwork(), isValid()); } }