package net.floodlightcontroller.core.internal; import static org.easymock.EasyMock.createMock; import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.replay; import static org.easymock.EasyMock.verify; import static org.junit.Assert.*; import java.io.IOException; import java.util.Collection; import java.util.LinkedList; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.IFloodlightProviderService.Role; import net.floodlightcontroller.core.internal.RoleChanger.RoleChangeTask; import org.easymock.EasyMock; import org.jboss.netty.channel.Channel; import org.junit.Before; import org.junit.Test; public class RoleChangerTest { public RoleChanger roleChanger; @Before public void setUp() throws Exception { roleChanger = new RoleChanger(); } /** * Send a role request for SLAVE to a switch that doesn't support it. * The connection should be closed. */ @Test public void testSendRoleRequestSlaveNotSupported() { LinkedList<OFSwitchImpl> switches = new LinkedList<OFSwitchImpl>(); // a switch that doesn't support role requests OFSwitchImpl sw1 = EasyMock.createMock(OFSwitchImpl.class); Channel channel1 = createMock(Channel.class); expect(sw1.getChannel()).andReturn(channel1); // No support for NX_ROLE expect(sw1.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE)) .andReturn(false); expect(channel1.close()).andReturn(null); switches.add(sw1); replay(sw1, channel1); roleChanger.sendRoleRequest(switches, Role.SLAVE, 123456); verify(sw1, channel1); // sendRoleRequest needs to remove the switch from the list since // it closed its connection assertTrue(switches.isEmpty()); } /** * Send a role request for MASTER to a switch that doesn't support it. * The connection should be closed. */ @Test public void testSendRoleRequestMasterNotSupported() { LinkedList<OFSwitchImpl> switches = new LinkedList<OFSwitchImpl>(); // a switch that doesn't support role requests OFSwitchImpl sw1 = EasyMock.createMock(OFSwitchImpl.class); // No support for NX_ROLE expect(sw1.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE)) .andReturn(false); switches.add(sw1); replay(sw1); roleChanger.sendRoleRequest(switches, Role.MASTER, 123456); verify(sw1); assertEquals(1, switches.size()); } /** * Send a role request a switch that supports it and one that * hasn't had a role request send to it yet */ @Test public void testSendRoleRequestErrorHandling () throws Exception { LinkedList<OFSwitchImpl> switches = new LinkedList<OFSwitchImpl>(); // a switch that supports role requests OFSwitchImpl sw1 = EasyMock.createMock(OFSwitchImpl.class); // No support for NX_ROLE expect(sw1.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE)) .andReturn(true); expect(sw1.sendNxRoleRequest(Role.MASTER, 123456)) .andThrow(new IOException()).once(); Channel channel1 = createMock(Channel.class); expect(sw1.getChannel()).andReturn(channel1); expect(channel1.close()).andReturn(null); switches.add(sw1); replay(sw1); roleChanger.sendRoleRequest(switches, Role.MASTER, 123456); verify(sw1); assertTrue(switches.isEmpty()); } /** * Check error handling * hasn't had a role request send to it yet */ @Test public void testSendRoleRequestSupported() throws Exception { LinkedList<OFSwitchImpl> switches = new LinkedList<OFSwitchImpl>(); // a switch that supports role requests OFSwitchImpl sw1 = EasyMock.createMock(OFSwitchImpl.class); // No support for NX_ROLE expect(sw1.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE)) .andReturn(true); expect(sw1.sendNxRoleRequest(Role.MASTER, 123456)).andReturn(1).once(); switches.add(sw1); // a switch for which we don't have SUPPORTS_NX_ROLE yet OFSwitchImpl sw2 = EasyMock.createMock(OFSwitchImpl.class); // No support for NX_ROLE expect(sw2.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE)) .andReturn(null); expect(sw2.sendNxRoleRequest(Role.MASTER, 123456)).andReturn(1).once(); switches.add(sw2); replay(sw1, sw2); roleChanger.sendRoleRequest(switches, Role.MASTER, 123456); verify(sw1, sw2); assertEquals(2, switches.size()); } @Test public void testVerifyRoleReplyReceived() { LinkedList<OFSwitchImpl> switches = new LinkedList<OFSwitchImpl>(); // Add a switch that has received a role reply OFSwitchImpl sw1 = EasyMock.createMock(OFSwitchImpl.class); expect(sw1.checkFirstPendingRoleRequestCookie(123456)) .andReturn(false).once(); switches.add(sw1); // Add a switch that has not yet received a role reply OFSwitchImpl sw2 = EasyMock.createMock(OFSwitchImpl.class); expect(sw2.checkFirstPendingRoleRequestCookie(123456)) .andReturn(true).once(); Channel channel2 = createMock(Channel.class); expect(sw2.getChannel()).andReturn(channel2); expect(channel2.close()).andReturn(null); switches.add(sw2); replay(sw1, sw2); roleChanger.verifyRoleReplyReceived(switches, 123456); verify(sw1, sw2); assertEquals(2, switches.size()); } @Test public void testRoleChangeTask() { @SuppressWarnings("unchecked") Collection<OFSwitchImpl> switches = EasyMock.createMock(Collection.class); long now = System.nanoTime(); long dt1 = 10 * 1000*1000*1000L; long dt2 = 20 * 1000*1000*1000L; long dt3 = 15 * 1000*1000*1000L; RoleChangeTask t1 = new RoleChangeTask(switches, null, now+dt1); RoleChangeTask t2 = new RoleChangeTask(switches, null, now+dt2); RoleChangeTask t3 = new RoleChangeTask(switches, null, now+dt3); // FIXME: cannot test comparison against self. grrr //assertTrue( t1.compareTo(t1) <= 0 ); assertTrue( t1.compareTo(t2) < 0 ); assertTrue( t1.compareTo(t3) < 0 ); assertTrue( t2.compareTo(t1) > 0 ); //assertTrue( t2.compareTo(t2) <= 0 ); assertTrue( t2.compareTo(t3) > 0 ); } @Test public void testSubmitRequest() throws Exception { LinkedList<OFSwitchImpl> switches = new LinkedList<OFSwitchImpl>(); roleChanger.timeout = 500*1000*1000; // 500 ms // a switch that supports role requests OFSwitchImpl sw1 = EasyMock.createStrictMock(OFSwitchImpl.class); // No support for NX_ROLE expect(sw1.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE)) .andReturn(true); expect(sw1.sendNxRoleRequest(EasyMock.same(Role.MASTER), EasyMock.anyLong())) .andReturn(1); expect(sw1.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE)) .andReturn(true); expect(sw1.sendNxRoleRequest(EasyMock.same(Role.SLAVE), EasyMock.anyLong())) .andReturn(1); // The following calls happen for timeout handling: expect(sw1.checkFirstPendingRoleRequestCookie(EasyMock.anyLong())) .andReturn(false); expect(sw1.checkFirstPendingRoleRequestCookie(EasyMock.anyLong())) .andReturn(false); switches.add(sw1); replay(sw1); roleChanger.submitRequest(switches, Role.MASTER); roleChanger.submitRequest(switches, Role.SLAVE); // Wait until role request has been sent. // TODO: need to get rid of this sleep somehow Thread.sleep(100); // Now there should be exactly one timeout task pending assertEquals(2, roleChanger.pendingTasks.size()); // Make sure it's indeed a timeout task assertSame(RoleChanger.RoleChangeTask.Type.TIMEOUT, roleChanger.pendingTasks.peek().type); // Check that RoleChanger indeed made a copy of switches collection assertNotSame(switches, roleChanger.pendingTasks.peek().switches); // Wait until the timeout triggers // TODO: get rid of this sleep too. Thread.sleep(500); assertEquals(0, roleChanger.pendingTasks.size()); verify(sw1); } }