package org.ovirt.engine.core.bll.network.macpool; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; import java.util.Arrays; import java.util.Collections; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import org.ovirt.engine.core.bll.DbDependentTestBase; import org.ovirt.engine.core.bll.context.CommandContext; import org.ovirt.engine.core.common.businessentities.Cluster; import org.ovirt.engine.core.common.businessentities.MacPool; import org.ovirt.engine.core.common.businessentities.MacRange; import org.ovirt.engine.core.common.businessentities.network.VmNic; import org.ovirt.engine.core.common.errors.EngineException; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.dal.dbbroker.DbFacade; import org.ovirt.engine.core.dao.AuditLogDao; import org.ovirt.engine.core.dao.ClusterDao; import org.ovirt.engine.core.dao.MacPoolDao; @RunWith(MockitoJUnitRunner.class) public class MacPoolPerClusterTest extends DbDependentTestBase { private static final String SESSION_ID = "session id"; @Rule public ExpectedException expectedException = ExpectedException.none(); @Mock private ClusterDao clusterDao; @Mock private MacPoolDao macPoolDao; @Mock private AuditLogDao auditLogDao; @Mock private DecoratedMacPoolFactory decoratedMacPoolFactory; private MacPool macPool; private Cluster cluster; private VmNic vmNic; private static final String MAC_FROM = "00:1a:4a:15:c0:00"; private static final String MAC_TO = "00:1a:4a:15:c0:ff"; private MacPoolPerCluster macPoolPerCluster; private CommandContext commandContext; @Before public void setUp() throws Exception { when(DbFacade.getInstance().getAuditLogDao()).thenReturn(auditLogDao); commandContext = CommandContext.createContext(SESSION_ID); macPool = createMacPool(MAC_FROM, MAC_TO); cluster = createCluster(macPool); vmNic = createVmNic(); when(decoratedMacPoolFactory.createDecoratedPool( any(org.ovirt.engine.core.bll.network.macpool.MacPool.class), anyList())) .thenAnswer(invocation -> invocation.getArguments()[0]); macPoolPerCluster = new MacPoolPerCluster(macPoolDao, clusterDao, new MacPoolFactory(), decoratedMacPoolFactory); } @Test public void testPoolDoesNotExistForGivenCluster() throws Exception { macPoolPerCluster.initialize(); expectedException.expect(IllegalStateException.class); expectedException.expectMessage(macPoolPerCluster.createExceptionMessageMacPoolHavingIdDoesNotExist(null)); getMacPool(cluster.getId()); } @Test public void testPoolOfGivenGuidExist() { mockCluster(cluster); mockGettingAllMacPools(macPool); macPoolPerCluster.initialize(); assertThat(getMacPool(cluster.getId()), is(notNullValue())); } @Test public void testNicIsCorrectlyAllocatedInScopedPool() throws Exception { mockCluster(cluster); mockGettingAllMacPools(macPool); mockAllMacsForCluster(cluster, vmNic.getMacAddress()); macPoolPerCluster.initialize(); assertThat("scoped pool for this nic should exist", getMacPool(cluster.getId()), is(notNullValue())); assertThat("provided mac should be used in returned pool", getMacPool(cluster.getId()).isMacInUse(vmNic.getMacAddress()), is(true)); } @Test public void testCreatePool() throws Exception { macPoolPerCluster.initialize(); mockCluster(cluster); macPoolPerCluster.createPool(macPool); assertThat("scoped pool for this data center should exist", getMacPool(cluster.getId()), is (notNullValue())); } @Test public void testCreatePoolWhichExists() throws Exception { mockGettingAllMacPools(macPool); macPoolPerCluster.initialize(); expectedException.expect(IllegalStateException.class); expectedException.expectMessage(MacPoolPerCluster.UNABLE_TO_CREATE_MAC_POOL_IT_ALREADY_EXIST); macPoolPerCluster.createPool(macPool); } @Test public void testModifyOfExistingMacPool() throws Exception { final String macAddress1 = "00:00:00:00:00:01"; final String macAddress2 = "00:00:00:00:00:02"; MacPool macPool = createMacPool(macAddress1, macAddress1); Cluster cluster = createCluster(macPool); mockCluster(cluster); mockGettingAllMacPools(macPool); macPoolPerCluster.initialize(); assertThat(getMacPool(cluster.getId()).addMac(MAC_FROM), is(true)); assertThat(getMacPool(cluster.getId()).addMac(MAC_FROM), is(false)); final String allocatedMac = allocateMac(cluster); /*needed due to implementation of modifyPool; modify assumes, that all allocated macs is used for vmNics. If allocatedMac succeeded it's expected that all vmNics were also successfully persisted to db or all allocated macs were returned to the pool. So after allocation we need to mock db, otherwise re-init in modifyPool would return improper results.*/ mockAllMacsForCluster(cluster, allocatedMac); assertThat(allocatedMac, is(macAddress1)); try { allocateMac(cluster); fail("this allocation should not succeed."); } catch (EngineException e) { //ok, this exception should occur. } macPool.setAllowDuplicateMacAddresses(true); final MacRange macRange = new MacRange(); macRange.setMacFrom(macAddress1); macRange.setMacTo(macAddress2); macPool.setRanges(Collections.singletonList(macRange)); macPoolPerCluster.modifyPool(macPool); assertThat(getMacPool(cluster.getId()).addMac(MAC_FROM), is(true)); assertThat(allocateMac(cluster), is(macAddress2)); } protected String allocateMac(Cluster cluster) { final Guid clusterId = cluster.getId(); return getMacPool(clusterId).allocateNewMac(); } private org.ovirt.engine.core.bll.network.macpool.MacPool getMacPool(Guid clusterId) { return macPoolPerCluster.getMacPoolForCluster(clusterId, commandContext); } @Test public void testModifyOfNotExistingMacPool() throws Exception { macPoolPerCluster.initialize(); expectedException.expect(IllegalStateException.class); MacPool macPool = createMacPool(null, null); Guid macPoolId = macPool.getId(); expectedException.expectMessage(macPoolPerCluster.createExceptionMessageMacPoolHavingIdDoesNotExist(macPoolId)); macPoolPerCluster.modifyPool(macPool); } @Test public void testRemoveOfMacPool() throws Exception { mockCluster(cluster); mockGettingAllMacPools(macPool); macPoolPerCluster.initialize(); assertThat(getMacPool(cluster.getId()), is(notNullValue())); Guid macPoolId = macPool.getId(); macPoolPerCluster.removePool(macPoolId); expectedException.expect(IllegalStateException.class); expectedException.expectMessage(macPoolPerCluster.createExceptionMessageMacPoolHavingIdDoesNotExist(macPoolId)); getMacPool(cluster.getId()); } @Test public void testRemoveOfInexistentMacPool() throws Exception { macPoolPerCluster.initialize(); try { getMacPool(cluster.getId()); fail("pool for given data center should not exist"); } catch (IllegalStateException e) { //ignore this exception. } macPoolPerCluster.removePool(macPool.getId()); //nothing to test, should not fail. } private Cluster createCluster(MacPool macPool) { //mock existing data centers. final Cluster cluster = new Cluster(); cluster.setId(Guid.newGuid()); cluster.setMacPoolId(macPool.getId()); return cluster; } private MacPool createMacPool(String macFrom, String macTo) { final MacRange macRange = new MacRange(); macRange.setMacFrom(macFrom); macRange.setMacTo(macTo); final MacPool macPool = new MacPool(); macPool.setId(Guid.newGuid()); macPool.setRanges(Collections.singletonList(macRange)); return macPool; } protected void mockAllMacsForCluster(Cluster cluster, String... macAddress) { when(macPoolDao.getAllMacsForMacPool(eq(cluster.getMacPoolId()))).thenReturn(Arrays.asList(macAddress)); } protected void mockGettingAllMacPools(MacPool... macPool) { when(macPoolDao.getAll()).thenReturn(Arrays.asList(macPool)); } protected VmNic createVmNic() { final VmNic vmNic = new VmNic(); vmNic.setMacAddress("00:1a:4a:15:c0:fe"); return vmNic; } protected void mockCluster(Cluster cluster) { when(clusterDao.get(eq(cluster.getId()))).thenReturn(cluster); } }