Package net.floodlightcontroller.core.internal

Source Code of net.floodlightcontroller.core.internal.OFChannelHandlerTest

package net.floodlightcontroller.core.internal;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import net.floodlightcontroller.core.FloodlightContext;
import net.floodlightcontroller.core.IOFSwitch;
import net.floodlightcontroller.core.IFloodlightProviderService.Role;
import net.floodlightcontroller.core.IOFSwitch.PortChangeEvent;
import net.floodlightcontroller.core.IOFSwitch.PortChangeType;
import net.floodlightcontroller.core.ImmutablePort;
import net.floodlightcontroller.debugcounter.DebugCounter;
import net.floodlightcontroller.debugcounter.IDebugCounterService;
import net.floodlightcontroller.debugcounter.IDebugCounterService.CounterException;
import net.floodlightcontroller.storage.IResultSet;
import net.floodlightcontroller.storage.IStorageSourceService;
import net.floodlightcontroller.threadpool.IThreadPoolService;
import net.floodlightcontroller.util.OrderedCollection;
import net.floodlightcontroller.util.LinkedHashSetWrapper;

import org.easymock.Capture;
import org.easymock.CaptureType;
import org.easymock.EasyMock;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.openflow.protocol.OFError;
import org.openflow.protocol.OFError.OFBadRequestCode;
import org.openflow.protocol.OFError.OFErrorType;
import org.openflow.protocol.OFFeaturesReply;
import org.openflow.protocol.OFGetConfigReply;
import org.openflow.protocol.OFMessage;
import org.openflow.protocol.OFPacketIn;
import org.openflow.protocol.OFPhysicalPort;
import org.openflow.protocol.OFPortStatus;
import org.openflow.protocol.OFPortStatus.OFPortReason;
import org.openflow.protocol.OFSetConfig;
import org.openflow.protocol.OFStatisticsReply;
import org.openflow.protocol.OFStatisticsRequest;
import org.openflow.protocol.OFType;
import org.openflow.protocol.OFVendor;
import org.openflow.protocol.factory.BasicFactory;
import org.openflow.protocol.statistics.OFDescriptionStatistics;
import org.openflow.protocol.statistics.OFStatisticsType;
import org.openflow.util.HexString;
import org.openflow.vendor.nicira.OFNiciraVendorData;
import org.openflow.vendor.nicira.OFRoleReplyVendorData;
import org.openflow.vendor.nicira.OFRoleRequestVendorData;

import static org.easymock.EasyMock.*;

import static org.junit.Assert.*;


public class OFChannelHandlerTest {
    private static final short CORE_PRIORITY = 4242;
    private static final short ACCESS_PRIORITY = 42;
    private Controller controller;
    private IThreadPoolService threadPool;
    private IDebugCounterService debugCounterService;
    private OFChannelHandler handler;
    private Channel channel;
    private ChannelHandlerContext ctx;
    private MessageEvent messageEvent;
    private ChannelStateEvent channelStateEvent;
    private ChannelPipeline pipeline;


    private Capture<ExceptionEvent> exceptionEventCapture;
    private Capture<List<OFMessage>> writeCapture;

    private OFFeaturesReply featuresReply;

    private Set<Integer> seenXids = null;
    private IStorageSourceService storageSource;
    private IResultSet storageResultSet;
    private IOFSwitch sw;



    @Before
    public void setUpFeaturesReply() {
        featuresReply = (OFFeaturesReply)BasicFactory.getInstance()
                .getMessage(OFType.FEATURES_REPLY);
        featuresReply.setDatapathId(0x42L);
        featuresReply.setBuffers(1);
        featuresReply.setTables((byte)1);
        featuresReply.setCapabilities(3);
        featuresReply.setActions(4);
        List<OFPhysicalPort> ports = new ArrayList<OFPhysicalPort>();
        // A dummy port.
        OFPhysicalPort p = new OFPhysicalPort();
        p.setName("Eth1");
        p.setPortNumber((short)1);
        ports.add(p);
        featuresReply.setPorts(ports);
    }


    @Before
    public void setUp() throws Exception {
        controller = createMock(Controller.class);
        threadPool = createMock(IThreadPoolService.class);
        ctx = createMock(ChannelHandlerContext.class);
        channelStateEvent = createMock(ChannelStateEvent.class);
        channel = createMock(Channel.class);
        messageEvent = createMock(MessageEvent.class);
        exceptionEventCapture = new Capture<ExceptionEvent>(CaptureType.ALL);
        pipeline = createMock(ChannelPipeline.class);
        writeCapture = new Capture<List<OFMessage>>(CaptureType.ALL);
        sw = createMock(IOFSwitch.class);
        seenXids = null;

        // TODO: should mock IDebugCounterService and make sure
        // the expected counters are updated.
        debugCounterService = new DebugCounter();
        Controller.Counters counters =
                new Controller.Counters();
        counters.createCounters(debugCounterService);
        expect(controller.getCounters()).andReturn(counters).anyTimes();
        replay(controller);
        handler = new OFChannelHandler(controller);
        verify(controller);
        reset(controller);

        resetChannel();

        // thread pool is usually not called, so start empty replay
        replay(threadPool);

        // replay controller. Reset it if you need more specific behavior
        replay(controller);

        // replay switch. Reset it if you need more specific behavior
        replay(sw);

        // Mock ctx and channelStateEvent
        expect(ctx.getChannel()).andReturn(channel).anyTimes();
        expect(channelStateEvent.getChannel()).andReturn(channel).anyTimes();
        replay(ctx, channelStateEvent);

        /* Setup an exception event capture on the channel. Right now
         * we only expect exception events to be send up the channel.
         * However, it's easy to extend to other events if we need it
         */
        pipeline.sendUpstream(capture(exceptionEventCapture));
        expectLastCall().anyTimes();
        replay(pipeline);
    }

    @After
    public void tearDown() {
        /* ensure no exception was thrown */
        if (exceptionEventCapture.hasCaptured()) {
            Throwable ex = exceptionEventCapture.getValue().getCause();
            throw new AssertionError("Unexpected exception: " +
                       ex.getClass().getName() + "(" + ex + ")");
        }
        assertFalse("Unexpected messages have been captured",
                    writeCapture.hasCaptured());
        // verify all mocks.
        verify(channel);
        verify(messageEvent);
        verify(controller);
        verify(threadPool);
        verify(ctx);
        verify(channelStateEvent);
        verify(pipeline);
        verify(sw);
    }

    /** Reset the channel mock and set basic method call expectations */
    void resetChannel() {
        reset(channel);
        expect(channel.getPipeline()).andReturn(pipeline).anyTimes();
        expect(channel.getRemoteAddress()).andReturn(null).anyTimes();
    }


    /** reset, setup, and replay the messageEvent mock for the given
     * messages
     */
    void setupMessageEvent(List<OFMessage> messages) {
        reset(messageEvent);
        expect(messageEvent.getMessage()).andReturn(messages).atLeastOnce();
        replay(messageEvent);
    }


    /** reset, setup, and replay the messageEvent mock for the given
     * messages, mock controller  send message to channel handler
     *
     * This method will reset, start replay on controller, and then verify
     */
    void sendMessageToHandlerWithControllerReset(List<OFMessage> messages)
            throws Exception {
        verify(controller);
        reset(controller);

        sendMessageToHandlerNoControllerReset(messages);
    }

    /** reset, setup, and replay the messageEvent mock for the given
     * messages, mock controller  send message to channel handler
     *
     * This method will start replay on controller, and then verify
     */
    void sendMessageToHandlerNoControllerReset(List<OFMessage> messages)
            throws Exception {
        setupMessageEvent(messages);

        // mock controller
        controller.flushAll();
        expectLastCall().atLeastOnce();
        replay(controller);
        handler.messageReceived(ctx, messageEvent);
        verify(controller);
    }

    /**
     * Extract the list of OFMessages that was captured by the Channel.write()
     * capture. Will check that something was actually captured first. We'll
     * collapse the messages from multiple writes into a single list of
     * OFMessages.
     * Resets the channelWriteCapture.
     */
    List<OFMessage> getMessagesFromCapture() {
        List<OFMessage> msgs = new ArrayList<OFMessage>();

        assertTrue("No write on channel was captured",
                   writeCapture.hasCaptured());
        List<List<OFMessage>> capturedVals = writeCapture.getValues();

        for (List<OFMessage> oneWriteList: capturedVals)
            msgs.addAll(oneWriteList);
        writeCapture.reset();
        return msgs;
    }


    /**
     * Verify that the given exception event capture (as returned by
     * getAndInitExceptionCapture) has thrown an exception of the given
     * expectedExceptionClass.
     * Resets the capture
     */
    void verifyExceptionCaptured(
            Class<? extends Throwable> expectedExceptionClass) {
        assertTrue("Excpected exception not thrown",
                   exceptionEventCapture.hasCaptured());
        Throwable caughtEx = exceptionEventCapture.getValue().getCause();
        assertEquals(expectedExceptionClass, caughtEx.getClass());
        exceptionEventCapture.reset();
    }

    /** make sure that the transaction ids in the given messages are
     * not 0 and differ between each other.
     * While it's not a defect per se if the xids are we want to ensure
     * we use different ones for each message we send.
     */
    void verifyUniqueXids(List<OFMessage> msgs) {
        if (seenXids == null)
            seenXids = new HashSet<Integer>();
        for (OFMessage m: msgs)  {
            int xid = m.getXid();
            assertTrue("Xid in messags is 0", xid != 0);
            assertFalse("Xid " + xid + " has already been used",
                        seenXids.contains(xid));
            seenXids.add(xid);
        }
    }


    @Test
    public void testInitState() throws Exception {
        // Message event needs to be list
        expect(messageEvent.getMessage()).andReturn(null);
        replay(channel, messageEvent);
        handler.messageReceived(ctx, messageEvent);
        verify(channel, messageEvent);
        verifyExceptionCaptured(AssertionError.class);

        // Message event needs to be list *of OFMessages*
        // TODO: messageReceived can throw exceptions that don't get send
        // back into the channel (e.g., the ClassCastException below).
        // Do we need to care?
        /*
        reset(channel, messageEvent);
        List<String> listOfWrongType = Collections.singletonList("FooBar");
        expect(messageEvent.getMessage()).andReturn(listOfWrongType)
                .atLeastOnce();
        replay(channel, messageEvent);
        handler.messageReceived(ctx, messageEvent);
        verify(channel, messageEvent);
        verifyExceptionCaptured(ClassCastException.class);
        */

        // We don't expect to receive /any/ messages in init state since
        // channelConnected moves us to a different state
        OFMessage m = BasicFactory.getInstance().getMessage(OFType.HELLO);
        sendMessageToHandlerWithControllerReset(Collections.singletonList(m));

        verifyExceptionCaptured(SwitchStateException.class);
        assertEquals(OFChannelHandler.ChannelState.INIT,
                     handler.getStateForTesting());
    }

    /* Move the channel from scratch to WAIT_HELLO state */
    @Test
    public void moveToWaitHello() throws Exception {
        resetChannel();
        channel.write(capture(writeCapture));
        expectLastCall().andReturn(null).once();
        replay(channel);
        // replay unused mocks
        replay(messageEvent);

        handler.channelConnected(ctx, channelStateEvent);

        List<OFMessage> msgs = getMessagesFromCapture();
        assertEquals(1, msgs.size());
        assertEquals(OFType.HELLO, msgs.get(0).getType());
        assertEquals(OFChannelHandler.ChannelState.WAIT_HELLO,
                     handler.getStateForTesting());
        verifyUniqueXids(msgs);
    }

    /** Move the channel from scratch to WAIT_FEATURES_REPLY state
     * Builds on moveToWaitHello()
     * adds testing for WAIT_HELLO state
     */
    @Test
    public void moveToWaitFeaturesReply() throws Exception {
        moveToWaitHello();
        resetChannel();
        channel.write(capture(writeCapture));
        expectLastCall().andReturn(null).atLeastOnce();
        replay(channel);

        OFMessage hello = BasicFactory.getInstance().getMessage(OFType.HELLO);
        sendMessageToHandlerWithControllerReset(Collections.singletonList(hello));

        List<OFMessage> msgs = getMessagesFromCapture();
        assertEquals(1, msgs.size());
        assertEquals(OFType.FEATURES_REQUEST, msgs.get(0).getType());
        verifyUniqueXids(msgs);

        assertEquals(OFChannelHandler.ChannelState.WAIT_FEATURES_REPLY,
                     handler.getStateForTesting());
    }


    /** Move the channel from scratch to WAIT_CONFIG_REPLY state
     * Builds on moveToWaitFeaturesReply
     * adds testing for WAIT_FEATURES_REPLY state
     */
    @Test
    public void moveToWaitConfigReply() throws Exception {
        moveToWaitFeaturesReply();
        resetChannel();
        channel.write(capture(writeCapture));
        expectLastCall().andReturn(null).atLeastOnce();
        replay(channel);

        sendMessageToHandlerWithControllerReset(Collections.<OFMessage>singletonList(featuresReply));

        List<OFMessage> msgs = getMessagesFromCapture();
        assertEquals(3, msgs.size());
        assertEquals(OFType.SET_CONFIG, msgs.get(0).getType());
        OFSetConfig sc = (OFSetConfig)msgs.get(0);
        assertEquals((short)0xffff, sc.getMissSendLength());
        assertEquals(OFType.BARRIER_REQUEST, msgs.get(1).getType());
        assertEquals(OFType.GET_CONFIG_REQUEST, msgs.get(2).getType());
        verifyUniqueXids(msgs);
        assertEquals(OFChannelHandler.ChannelState.WAIT_CONFIG_REPLY,
                     handler.getStateForTesting());
    }

    /** Move the channel from scratch to WAIT_DESCRIPTION_STAT_REPLY state
     * Builds on moveToWaitConfigReply()
     * adds testing for WAIT_CONFIG_REPLY state
     */
    @Test
    public void moveToWaitDescriptionStatReply() throws Exception {
        moveToWaitConfigReply();
        resetChannel();
        channel.write(capture(writeCapture));
        expectLastCall().andReturn(null).atLeastOnce();
        replay(channel);

        OFGetConfigReply cr = (OFGetConfigReply)BasicFactory.getInstance()
                .getMessage(OFType.GET_CONFIG_REPLY);
        cr.setMissSendLength((short)0xffff);

        sendMessageToHandlerWithControllerReset(Collections.<OFMessage>singletonList(cr));

        List<OFMessage> msgs = getMessagesFromCapture();
        assertEquals(1, msgs.size());
        assertEquals(OFType.STATS_REQUEST, msgs.get(0).getType());
        OFStatisticsRequest sr = (OFStatisticsRequest)msgs.get(0);
        assertEquals(OFStatisticsType.DESC, sr.getStatisticType());
        // no idea why an  OFStatisticsRequest even /has/ a getStatistics()
        // methods. It really shouldn't
        assertNull(sr.getStatistics());
        verifyUniqueXids(msgs);
        assertEquals(OFChannelHandler.ChannelState.WAIT_DESCRIPTION_STAT_REPLY,
                     handler.getStateForTesting());
    }


    /** A helper bean that represents the config for a particular switch in
     * the storage source.
     */
    private class MockStorageSourceConfig {
        // the dpid
        public String dpid;
        // true if the given dpid should be present in the storage source
        // if false the storage source will return an empty result
        public boolean isPresent;
        // the value of isCoreSwitch
        public boolean isCoreSwitch;
    }
    /** setup and replay a mock storage source and result set that
     * contains the IsCoreSwitch setting
     */
    private void setupMockStorageSource(MockStorageSourceConfig cfg) {

        storageSource = createMock(IStorageSourceService.class);
        storageResultSet = createMock(IResultSet.class);

        Iterator<IResultSet> it = null;

        if (cfg.isPresent) {
            storageResultSet.getBoolean(Controller.SWITCH_CONFIG_CORE_SWITCH);
            expectLastCall().andReturn(cfg.isCoreSwitch).atLeastOnce();
            it = Collections.singletonList(storageResultSet).iterator();
        } else {
            it = Collections.<IResultSet>emptyList().iterator();
        }

        storageResultSet.close();
        expectLastCall().atLeastOnce();
        expect(storageResultSet.iterator()).andReturn(it).atLeastOnce();
        storageSource.getRow(Controller.SWITCH_CONFIG_TABLE_NAME, cfg.dpid);
        expectLastCall().andReturn(storageResultSet).atLeastOnce();
        replay(storageResultSet, storageSource);
    }

    private void verifyStorageSource() {
        verify(storageSource);
        verify(storageResultSet);
    }

    private static OFStatisticsReply createDescriptionStatsReply() {
        OFStatisticsReply sr = (OFStatisticsReply)BasicFactory.getInstance()
                .getMessage(OFType.STATS_REPLY);
        sr.setStatisticType(OFStatisticsType.DESC);
        OFDescriptionStatistics desc = new OFDescriptionStatistics();
        desc.setDatapathDescription("Datapath Description");
        desc.setHardwareDescription("Hardware Description");
        desc.setManufacturerDescription("Manufacturer Description");
        desc.setSerialNumber("Serial Number");
        desc.setSoftwareDescription("Software Description");
        sr.setStatistics(Collections.singletonList(desc));
        return sr;
    }

    /**
     * setup the expectations for the mock switch that are needed
     * after the switch is instantiated in the WAIT_DESCRIPTION_STATS STATE
     * Will reset the switch
     * @throws CounterException
     */
    private void setupSwitchForInstantiationWithReset(String dpid)
            throws Exception {
        reset(sw);
        sw.setChannel(channel);
        expectLastCall().once();
        sw.setFloodlightProvider(controller);
        expectLastCall().once();
        sw.setThreadPoolService(threadPool);
        expectLastCall().once();
        sw.setDebugCounterService(debugCounterService);
        expectLastCall().once();
        sw.setFeaturesReply(featuresReply);
        expectLastCall().once();
        sw.setConnected(true);
        expectLastCall().once();
        sw.getStringId();
        expectLastCall().andReturn(dpid).atLeastOnce();
        sw.isWriteThrottleEnabled()// used for log message only
        expectLastCall().andReturn(false).anyTimes();
        sw.setAccessFlowPriority(ACCESS_PRIORITY);
        expectLastCall().once();
        sw.setCoreFlowPriority(CORE_PRIORITY);
        expectLastCall().once();
    }

    /** Move the channel from scratch to WAIT_INITIAL_ROLE state
     * for a switch that does not have a sub-handshake
     * Builds on moveToWaitDescriptionStatReply()
     * adds testing for WAIT_DESCRIPTION_STAT_REPLY state
     * @param storageSourceConfig paramterizes the contents of the storage
     * source (for IS_CORE_SWITCH)
     */
    public void doMoveToWaitInitialRole(MockStorageSourceConfig cfg)
            throws Exception {
        moveToWaitDescriptionStatReply();

        // We do not expect a write to the channel for the role request. We add
        // the channel to the controller and the controller would in turn
        // call handler.sendRoleRequest(). Since we mock the controller so
        // we won't see the handler.sendRoleRequest() call and therefore we
        // won't see any calls on the channel.
        resetChannel();
        replay(channel);

        // build the stats reply
        OFStatisticsReply sr = createDescriptionStatsReply();
        OFDescriptionStatistics desc =
                (OFDescriptionStatistics) sr.getFirstStatistics();

        setupMessageEvent(Collections.<OFMessage>singletonList(sr));
        setupMockStorageSource(cfg);

        setupSwitchForInstantiationWithReset(cfg.dpid);
        sw.startDriverHandshake();
        expectLastCall().once();
        sw.isDriverHandshakeComplete();
        expectLastCall().andReturn(true).once();

        if (cfg.isPresent)
            sw.setAttribute(IOFSwitch.SWITCH_IS_CORE_SWITCH, cfg.isCoreSwitch);
        replay(sw);

        // mock controller
        reset(controller);
        expect(controller.getDebugCounter()).andReturn(debugCounterService)
                .once();
        controller.flushAll();
        expectLastCall().once();
        expect(controller.getThreadPoolService())
                .andReturn(threadPool).once();
        expect(controller.getOFSwitchInstance(eq(desc)))
                .andReturn(sw).once();
        expect(controller.getCoreFlowPriority())
                .andReturn(CORE_PRIORITY).once();
        expect(controller.getAccessFlowPriority())
                .andReturn(ACCESS_PRIORITY).once();
        controller.addSwitchChannelAndSendInitialRole(handler);
        expectLastCall().once();
        expect(controller.getStorageSourceService())
                .andReturn(storageSource).atLeastOnce();
        replay(controller);

        // send the description stats reply
        handler.messageReceived(ctx, messageEvent);

        assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
                     handler.getStateForTesting());
        verifyStorageSource();
    }

    /**
     * Move the channel from scratch to WAIT_INITIAL_ROLE state via
     * WAIT_SWITCH_DRIVER_SUB_HANDSHAKE
     * Does extensive testing for the WAIT_SWITCH_DRIVER_SUB_HANDSHAKE state
     *
     */
    @Test
    public void testSwitchDriverSubHandshake()
            throws Exception {
        MockStorageSourceConfig cfg = new MockStorageSourceConfig();
        cfg.dpid = HexString.toHexString(featuresReply.getDatapathId());
        cfg.isPresent = false;

        moveToWaitDescriptionStatReply();

        resetChannel();
        channel.write(capture(writeCapture));
        expectLastCall().andReturn(null).atLeastOnce();
        replay(channel);

        // build the stats reply
        OFStatisticsReply sr = createDescriptionStatsReply();
        OFDescriptionStatistics desc =
                (OFDescriptionStatistics) sr.getFirstStatistics();

        setupMessageEvent(Collections.<OFMessage>singletonList(sr));
        setupMockStorageSource(cfg);

        // Start the sub-handshake. Switch will indicate that it's not
        // complete yet
        setupSwitchForInstantiationWithReset(cfg.dpid);
        sw.startDriverHandshake();
        expectLastCall().once();
        sw.isDriverHandshakeComplete();
        expectLastCall().andReturn(false).once();

        if (cfg.isPresent)
            sw.setAttribute(IOFSwitch.SWITCH_IS_CORE_SWITCH, cfg.isCoreSwitch);
        replay(sw);

        // mock controller
        reset(controller);
        expect(controller.getDebugCounter()).andReturn(debugCounterService)
                .once();
        controller.flushAll();
        expectLastCall().once();
        expect(controller.getThreadPoolService())
                .andReturn(threadPool).once();
        expect(controller.getOFSwitchInstance(eq(desc)))
                .andReturn(sw).once();
        expect(controller.getCoreFlowPriority())
                .andReturn(CORE_PRIORITY).once();
        expect(controller.getAccessFlowPriority())
                .andReturn(ACCESS_PRIORITY).once();
        expect(controller.getStorageSourceService())
                .andReturn(storageSource).atLeastOnce();
        replay(controller);

        // send the description stats reply
        handler.messageReceived(ctx, messageEvent);

        assertEquals(OFChannelHandler.ChannelState.WAIT_SWITCH_DRIVER_SUB_HANDSHAKE,
                     handler.getStateForTesting());
        assertFalse("Unexpected message captured", writeCapture.hasCaptured());
        verifyStorageSource();
        verify(sw);


        //-------------------------------------------------
        // Send a message to the handler, it should be passed to the
        // switch's sub-handshake handling.
        OFMessage m = BasicFactory.getInstance().getMessage(OFType.HELLO);
        resetToStrict(sw);
        expect(sw.inputThrottled(anyObject(OFMessage.class)))
                .andReturn(false).anyTimes();
        sw.processDriverHandshakeMessage(m);
        expectLastCall().once();
        expect(sw.isDriverHandshakeComplete()).andReturn(false).once();
        replay(sw);

        sendMessageToHandlerWithControllerReset(Collections.singletonList(m));
        assertEquals(OFChannelHandler.ChannelState.WAIT_SWITCH_DRIVER_SUB_HANDSHAKE,
                     handler.getStateForTesting());
        assertFalse("Unexpected message captured", writeCapture.hasCaptured());
        verify(sw);

        //-------------------------------------------------
        // Send a ECHO_REQUEST. This should be handled by the OFChannelHandler
        // and *not* passed to switch sub-handshake
        // TODO: should this be also passed to the switch handshake instead?
        m = BasicFactory.getInstance().getMessage(OFType.ECHO_REQUEST);
        m.setXid(0x042042);

        reset(sw);
        expect(sw.inputThrottled(anyObject(OFMessage.class)))
                .andReturn(false).anyTimes();
        replay(sw);
        sendMessageToHandlerWithControllerReset(Collections.singletonList(m));
        assertEquals(OFChannelHandler.ChannelState.WAIT_SWITCH_DRIVER_SUB_HANDSHAKE,
                     handler.getStateForTesting());
        List<OFMessage> msgs = getMessagesFromCapture();
        assertEquals(1, msgs.size());
        assertEquals(OFType.ECHO_REPLY, msgs.get(0).getType());
        assertEquals(0x42042, msgs.get(0).getXid());
        verify(sw);


        //-------------------------------------------------
        //-------------------------------------------------
        // Send a message to the handler, it should be passed to the
        // switch's sub-handshake handling. After this message the
        // sub-handshake will be complete
        m = BasicFactory.getInstance().getMessage(OFType.FLOW_REMOVED);
        resetToStrict(sw);
        expect(sw.inputThrottled(anyObject(OFMessage.class)))
                .andReturn(false).anyTimes();
        sw.processDriverHandshakeMessage(m);
        expectLastCall().once();
        expect(sw.isDriverHandshakeComplete()).andReturn(true).once();
        replay(sw);

        verify(controller);
        reset(controller);
        controller.addSwitchChannelAndSendInitialRole(handler);
        expectLastCall().once();
        sendMessageToHandlerNoControllerReset(Collections.singletonList(m));
        assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
                     handler.getStateForTesting());
        assertFalse("Unexpected message captured", writeCapture.hasCaptured());
        verify(sw);

        //-------------------------------------------------

        //-------------------------------------------------
    }

    @Test
    /** Test WaitDescriptionReplyState. No config for switch in storage */
    public void testWaitDescriptionReplyState1() throws Exception {
        MockStorageSourceConfig cfg = new MockStorageSourceConfig();
        cfg.dpid = HexString.toHexString(featuresReply.getDatapathId());
        cfg.isPresent = false;
        doMoveToWaitInitialRole(cfg);
    }

    @Test
    /** Test WaitDescriptionReplyState. switch is core switch */
    public void testWaitDescriptionReplyState2() throws Exception {
        MockStorageSourceConfig cfg = new MockStorageSourceConfig();
        cfg.dpid = HexString.toHexString(featuresReply.getDatapathId());
        cfg.isPresent = true;
        cfg.isCoreSwitch = true;
        doMoveToWaitInitialRole(cfg);
    }

    @Test
    /** Test WaitDescriptionReplyState. switch is NOT core switch */
    public void testWaitDescriptionReplyState3() throws Exception {
        MockStorageSourceConfig cfg = new MockStorageSourceConfig();
        cfg.dpid = HexString.toHexString(featuresReply.getDatapathId());
        cfg.isPresent = true;
        cfg.isCoreSwitch = true;
        doMoveToWaitInitialRole(cfg);
    }

    /**
     * Helper
     * Verify that the given OFMessage is a correct Nicira RoleRequest message
     * for the given role using the given xid.
     */
    private void verifyRoleRequest(OFMessage m,
                                   int expectedXid,
                                   Role expectedRole) {
        assertEquals(OFType.VENDOR, m.getType());
        OFVendor vendorMsg = (OFVendor)m;
        assertEquals(expectedXid, vendorMsg.getXid());
        assertEquals(OFNiciraVendorData.NX_VENDOR_ID, vendorMsg.getVendor());
        assertTrue("Vendor data is not an instance of OFRoleRequestVendorData"
                   + " its class is: " + vendorMsg.getVendorData().getClass().getName(),
                   vendorMsg.getVendorData() instanceof OFRoleRequestVendorData);
        OFRoleRequestVendorData requestData =
                (OFRoleRequestVendorData)vendorMsg.getVendorData();
        assertEquals(expectedRole.toNxRole(), requestData.getRole());
    }

    /**
     * Setup the mock switch and write capture for a role request, set the
     * role and verify mocks.
     * @param supportsNxRole whether the switch supports role request messages
     * to setup the attribute. This must be null (don't yet know if roles
     * supported: send to check) or true.
     * @param xid The xid to use in the role request
     * @param role The role to send
     * @throws IOException
     */
    private void setupSwitchSendRoleRequestAndVerify(Boolean supportsNxRole,
                                           int xid,
                                           Role role) throws IOException {
        assertTrue("This internal test helper method most not be called " +
                   "with supportsNxRole==false. Test setup broken",
                   supportsNxRole == null || supportsNxRole == true);
        reset(sw);
        expect(sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE))
                .andReturn(supportsNxRole).atLeastOnce();
        expect(sw.getNextTransactionId()).andReturn(xid).once();
        sw.write(capture(writeCapture), EasyMock.<FloodlightContext>anyObject());
        expectLastCall().anyTimes();
        replay(sw);

        handler.sendRoleRequest(role);

        List<OFMessage> msgs = getMessagesFromCapture();
        assertEquals(1, msgs.size());
        verifyRoleRequest(msgs.get(0), xid, role);
        verify(sw);
    }

    /**
     * Setup the mock switch for a role change request where the switch
     * does not support roles.
     *
     * Needs to verify and reset the controller since we need to set
     * an expectation
     */
    private void setupSwitchRoleChangeUnsupported(int xid,
                                                  Role role) {
        boolean supportsNxRole = false;
        reset(sw);
        expect(sw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE))
                .andReturn(supportsNxRole).atLeastOnce();
        // TODO: hmmm. While it's not incorrect that we set the attribute
        // again it looks odd. Maybe change
        sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, supportsNxRole);
        expectLastCall().anyTimes();
        sw.setHARole(role);
        expectLastCall().once();
        if (role == Role.SLAVE) {
            sw.disconnectOutputStream();
            expectLastCall().once();
        } else {
            verify(controller);
            reset(controller);
            controller.switchActivated(sw);
            replay(controller);
        }
        replay(sw);

        handler.sendRoleRequest(role);

        verify(sw);
    }

    /** Return a Nicira RoleReply message for the given role */
    private OFMessage getRoleReply(int xid, Role role) {
        OFVendor vm = (OFVendor)BasicFactory.getInstance()
                .getMessage(OFType.VENDOR);
        vm.setXid(xid);
        vm.setVendor(OFNiciraVendorData.NX_VENDOR_ID);
        OFRoleReplyVendorData replyData = new OFRoleReplyVendorData();
        replyData.setRole(role.toNxRole());
        vm.setVendorData(replyData);
        return vm;
    }

    /** Return an OFError of the given type with the given xid */
    private OFMessage getErrorMessage(OFErrorType type,
                                      int i,
                                      int xid) {
        OFError e = (OFError) BasicFactory.getInstance()
                .getMessage(OFType.ERROR);
        e.setErrorType(type);
        e.setErrorCode((short)i);
        e.setXid(xid);
        return e;
    }


    /** Move the channel from scratch to MASTER state
     * Builds on doMoveToWaitInitialRole()
     * adds testing for WAIT_INITAL_ROLE state
     *
     * This method tests only the simple case that the switch supports roles
     * and transitions to MASTER
     */
    @Test
    public void testInitialMoveToMasterWithRole() throws Exception {
        int xid = 42;
        // first, move us to WAIT_INITIAL_ROLE_STATE
        MockStorageSourceConfig cfg = new MockStorageSourceConfig();
        cfg.dpid = HexString.toHexString(featuresReply.getDatapathId());
        cfg.isPresent = false;
        doMoveToWaitInitialRole(cfg);
        assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
                     handler.getStateForTesting());

        // Set the role
        setupSwitchSendRoleRequestAndVerify(null, xid, Role.MASTER);
        assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
                     handler.getStateForTesting());

        // prepare mocks and inject the role reply message
        reset(sw);
        expect(sw.inputThrottled(anyObject(OFMessage.class)))
               .andReturn(false).anyTimes();
        sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, true);
        expectLastCall().once();
        sw.setHARole(Role.MASTER);
        expectLastCall().once();
        replay(sw);

        verify(controller);
        reset(controller);
        controller.switchActivated(sw);
        expectLastCall().once();
        OFMessage reply = getRoleReply(xid, Role.MASTER);
        // sendMessageToHandler will verify and rest controller mock
        sendMessageToHandlerNoControllerReset(Collections.singletonList(reply));

        assertEquals(OFChannelHandler.ChannelState.MASTER,
                     handler.getStateForTesting());
    }

    /** Move the channel from scratch to SLAVE state
     * Builds on doMoveToWaitInitialRole()
     * adds testing for WAIT_INITAL_ROLE state
     *
     * This method tests only the simple case that the switch supports roles
     * and transitions to SLAVE
     */
    @Test
    public void testInitialMoveToSlaveWithRole() throws Exception {
        int xid = 42;
        // first, move us to WAIT_INITIAL_ROLE_STATE
        MockStorageSourceConfig cfg = new MockStorageSourceConfig();
        cfg.dpid = HexString.toHexString(featuresReply.getDatapathId());
        cfg.isPresent = false;
        doMoveToWaitInitialRole(cfg);
        assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
                     handler.getStateForTesting());

        // Set the role
        setupSwitchSendRoleRequestAndVerify(null, xid, Role.SLAVE);
        assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
                     handler.getStateForTesting());

        // prepare mocks and inject the role reply message
        reset(sw);
        expect(sw.inputThrottled(anyObject(OFMessage.class)))
                .andReturn(false).anyTimes();
        sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, true);
        expectLastCall().once();
        sw.setHARole(Role.SLAVE);
        expectLastCall().once();
        replay(sw);

        verify(controller);
        reset(controller);
        controller.switchDeactivated(sw);
        expectLastCall().once();
        OFMessage reply = getRoleReply(xid, Role.SLAVE);
        // sendMessageToHandler will verify and rest controller mock
        sendMessageToHandlerNoControllerReset(Collections.singletonList(reply));

        assertEquals(OFChannelHandler.ChannelState.SLAVE,
                     handler.getStateForTesting());
    }

    /** Move the channel from scratch to MASTER state
     * Builds on doMoveToWaitInitialRole()
     * adds testing for WAIT_INITAL_ROLE state
     *
     * This method tests the case that the switch does NOT support roles.
     * The channel handler still needs to send the initial request to find
     * out that whether the switch supports roles.
     */
    @Test
    public void testInitialMoveToMasterNoRole() throws Exception {
        int xid = 43;
        // first, move us to WAIT_INITIAL_ROLE_STATE
        MockStorageSourceConfig cfg = new MockStorageSourceConfig();
        cfg.dpid = HexString.toHexString(featuresReply.getDatapathId());
        cfg.isPresent = false;
        doMoveToWaitInitialRole(cfg);
        assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
                     handler.getStateForTesting());

        // Set the role
        setupSwitchSendRoleRequestAndVerify(null, xid, Role.MASTER);
        assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
                     handler.getStateForTesting());

        // prepare mocks and inject the role reply message
        reset(sw);
        expect(sw.inputThrottled(anyObject(OFMessage.class)))
                .andReturn(false).anyTimes();
        sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, false);
        expectLastCall().once();
        sw.setHARole(Role.MASTER);
        expectLastCall().once();
        replay(sw);

        // FIXME: shouldn't use ordinal(), but OFError is broken

        // Error with incorrect xid and type. Should be ignored.
        OFMessage err = getErrorMessage(OFErrorType.OFPET_BAD_ACTION,
                                        0,
                                        xid+1);
        // sendMessageToHandler will verify and rest controller mock
        sendMessageToHandlerWithControllerReset(Collections.singletonList(err));
        assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
                     handler.getStateForTesting());

        // Error with correct xid. Should trigger state transition
        err = getErrorMessage(OFErrorType.OFPET_BAD_REQUEST,
                              OFError.OFBadRequestCode.OFPBRC_BAD_VENDOR.ordinal(),
                              xid);
        verify(controller);
        reset(controller);
        controller.switchActivated(sw);
        expectLastCall().once();
        // sendMessageToHandler will verify and rest controller mock
        sendMessageToHandlerNoControllerReset(Collections.singletonList(err));

        assertEquals(OFChannelHandler.ChannelState.MASTER,
                     handler.getStateForTesting());

    }

    /** Move the channel from scratch to MASTER state
     * Builds on doMoveToWaitInitialRole()
     * adds testing for WAIT_INITAL_ROLE state
     *
     * We let the initial role request time out. Role support should be
     * disabled but the switch should be activated.
     */
    @Test
    public void testInitialMoveToMasterTimeout() throws Exception {
        int timeout = 50;
        handler.useRoleChangerWithOtherTimeoutForTesting(timeout);
        int xid = 4343;

        // first, move us to WAIT_INITIAL_ROLE_STATE
        MockStorageSourceConfig cfg = new MockStorageSourceConfig();
        cfg.dpid = HexString.toHexString(featuresReply.getDatapathId());
        cfg.isPresent = false;
        doMoveToWaitInitialRole(cfg);
        assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
                     handler.getStateForTesting());

        // Set the role
        setupSwitchSendRoleRequestAndVerify(null, xid, Role.MASTER);
        assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
                     handler.getStateForTesting());

        // prepare mocks and inject the role reply message
        reset(sw);
        expect(sw.inputThrottled(anyObject(OFMessage.class)))
                .andReturn(false).anyTimes();
        sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, false);
        expectLastCall().once();
        sw.setHARole(Role.MASTER);
        expectLastCall().once();
        replay(sw);

        OFMessage m = BasicFactory.getInstance().getMessage(OFType.ECHO_REPLY);

        Thread.sleep(timeout+5);

        verify(controller);
        reset(controller);
        controller.switchActivated(sw);
        expectLastCall().once();
        sendMessageToHandlerNoControllerReset(Collections.singletonList(m));

        assertEquals(OFChannelHandler.ChannelState.MASTER,
                     handler.getStateForTesting());

    }


    /** Move the channel from scratch to SLAVE state
     * Builds on doMoveToWaitInitialRole()
     * adds testing for WAIT_INITAL_ROLE state
     *
     * This method tests the case that the switch does NOT support roles.
     * The channel handler still needs to send the initial request to find
     * out that whether the switch supports roles.
     *
     */
    @Test
    public void testInitialMoveToSlaveNoRole() throws Exception {
        int xid = 44;
        // first, move us to WAIT_INITIAL_ROLE_STATE
        MockStorageSourceConfig cfg = new MockStorageSourceConfig();
        cfg.dpid = HexString.toHexString(featuresReply.getDatapathId());
        cfg.isPresent = false;
        doMoveToWaitInitialRole(cfg);
        assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
                     handler.getStateForTesting());

        // Set the role
        setupSwitchSendRoleRequestAndVerify(null, xid, Role.SLAVE);
        assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
                     handler.getStateForTesting());

        // prepare mocks and inject the role reply message
        reset(sw);
        expect(sw.inputThrottled(anyObject(OFMessage.class)))
                .andReturn(false).anyTimes();
        sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, false);
        expectLastCall().once();
        sw.setHARole(Role.SLAVE);
        expectLastCall().once();
        sw.disconnectOutputStream(); // Make sure we disconnect
        expectLastCall().once();
        replay(sw);


        // FIXME: shouldn't use ordinal(), but OFError is broken

        // Error with incorrect xid and type. Should be ignored.
        OFMessage err = getErrorMessage(OFErrorType.OFPET_BAD_ACTION,
                                        0,
                                        xid+1);
        // sendMessageToHandler will verify and rest controller mock
        sendMessageToHandlerWithControllerReset(Collections.singletonList(err));
        assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
                     handler.getStateForTesting());

        // Error with correct xid. Should trigger state transition
        err = getErrorMessage(OFErrorType.OFPET_BAD_REQUEST,
                              OFError.OFBadRequestCode.OFPBRC_BAD_VENDOR.ordinal(),
                              xid);
        // sendMessageToHandler will verify and rest controller mock
        sendMessageToHandlerWithControllerReset(Collections.singletonList(err));
    }


    /** Move the channel from scratch to SLAVE state
     * Builds on doMoveToWaitInitialRole()
     * adds testing for WAIT_INITAL_ROLE state
     *
     * We let the initial role request time out. The switch should be
     * disconnected
     */
    @Test
    public void testInitialMoveToSlaveTimeout() throws Exception {
        int timeout = 50;
        handler.useRoleChangerWithOtherTimeoutForTesting(timeout);
        int xid = 4444;

        // first, move us to WAIT_INITIAL_ROLE_STATE
        MockStorageSourceConfig cfg = new MockStorageSourceConfig();
        cfg.dpid = HexString.toHexString(featuresReply.getDatapathId());
        cfg.isPresent = false;
        doMoveToWaitInitialRole(cfg);
        assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
                     handler.getStateForTesting());

        // Set the role
        setupSwitchSendRoleRequestAndVerify(null, xid, Role.SLAVE);
        assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
                     handler.getStateForTesting());

        // prepare mocks and inject the role reply message
        reset(sw);
        expect(sw.inputThrottled(anyObject(OFMessage.class)))
                .andReturn(false).anyTimes();
        sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, false);
        expectLastCall().once();
        sw.setHARole(Role.SLAVE);
        expectLastCall().once();
        sw.disconnectOutputStream(); // Make sure we disconnect
        expectLastCall().once();
        replay(sw);

        OFMessage m = BasicFactory.getInstance().getMessage(OFType.ECHO_REPLY);

        Thread.sleep(timeout+5);

        sendMessageToHandlerWithControllerReset(Collections.singletonList(m));
    }


    /** Move channel from scratch to WAIT_INITIAL_STATE, then MASTER,
     * then SLAVE for cases where the switch does not support roles.
     * I.e., the final SLAVE transition should disconnect the switch.
     */
    @Test
    public void testNoRoleInitialToMasterToSlave() throws Exception {
        int xid = 46;
        // First, lets move the state to MASTER without role support
        testInitialMoveToMasterNoRole();
        assertEquals(OFChannelHandler.ChannelState.MASTER,
                     handler.getStateForTesting());

        // try to set master role again. should be a no-op
        setupSwitchRoleChangeUnsupported(xid, Role.MASTER);
        assertEquals(OFChannelHandler.ChannelState.MASTER,
                     handler.getStateForTesting());


        setupSwitchRoleChangeUnsupported(xid, Role.SLAVE);
        assertEquals(OFChannelHandler.ChannelState.SLAVE,
                     handler.getStateForTesting());

    }

    /** Move the channel to MASTER state
     * Expects that the channel is in MASTER or SLAVE state.
     *
     */
    public void changeRoleToMasterWithRequest() throws Exception {
        int xid = 4242;

        assertTrue("This method can only be called when handler is in " +
                   "MASTER or SLAVE role", handler.isHandshakeComplete());

        // Set the role
        setupSwitchSendRoleRequestAndVerify(true, xid, Role.MASTER);

        // prepare mocks and inject the role reply message
        reset(sw);
        expect(sw.inputThrottled(anyObject(OFMessage.class)))
                .andReturn(false).anyTimes();
        sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, true);
        expectLastCall().once();
        sw.setHARole(Role.MASTER);
        expectLastCall().once();
        replay(sw);

        verify(controller);
        reset(controller);
        controller.switchActivated(sw);
        expectLastCall().once();
        OFMessage reply = getRoleReply(xid, Role.MASTER);
        // sendMessageToHandler will verify and rest controller mock
        sendMessageToHandlerNoControllerReset(Collections.singletonList(reply));

        assertEquals(OFChannelHandler.ChannelState.MASTER,
                     handler.getStateForTesting());
    }

    /** Move the channel to SLAVE state
     * Expects that the channel is in MASTER or SLAVE state.
     *
     */
    public void changeRoleToSlaveWithRequest() throws Exception {
        int xid = 2323;

        assertTrue("This method can only be called when handler is in " +
                   "MASTER or SLAVE role", handler.isHandshakeComplete());

        // Set the role
        setupSwitchSendRoleRequestAndVerify(true, xid, Role.SLAVE);

        // prepare mocks and inject the role reply message
        reset(sw);
        expect(sw.inputThrottled(anyObject(OFMessage.class)))
                .andReturn(false).anyTimes();
        sw.setAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE, true);
        expectLastCall().once();
        sw.setHARole(Role.SLAVE);
        expectLastCall().once();
        replay(sw);

        verify(controller);
        reset(controller);
        controller.switchDeactivated(sw);
        expectLastCall().once();
        OFMessage reply = getRoleReply(xid, Role.SLAVE);
        // sendMessageToHandler will verify and rest controller mock
        sendMessageToHandlerNoControllerReset(Collections.singletonList(reply));

        assertEquals(OFChannelHandler.ChannelState.SLAVE,
                     handler.getStateForTesting());
    }

    @Test
    public void testMultiRoleChange1() throws Exception {
        testInitialMoveToMasterWithRole();
        changeRoleToMasterWithRequest();
        changeRoleToSlaveWithRequest();
        changeRoleToSlaveWithRequest();
        changeRoleToMasterWithRequest();
        changeRoleToSlaveWithRequest();
    }

    @Test
    public void testMultiRoleChange2() throws Exception {
        testInitialMoveToSlaveWithRole();
        changeRoleToMasterWithRequest();
        changeRoleToSlaveWithRequest();
        changeRoleToSlaveWithRequest();
        changeRoleToMasterWithRequest();
        changeRoleToSlaveWithRequest();
    }

    /** Start from scratch and reply with an unexpected error to the role
     * change request
     * Builds on doMoveToWaitInitialRole()
     * adds testing for WAIT_INITAL_ROLE state
     */
    @Test
    public void testInitialRoleChangeOtherError() throws Exception {
        int xid = 4343;
        // first, move us to WAIT_INITIAL_ROLE_STATE
        MockStorageSourceConfig cfg = new MockStorageSourceConfig();
        cfg.dpid = HexString.toHexString(featuresReply.getDatapathId());
        cfg.isPresent = false;
        doMoveToWaitInitialRole(cfg);
        assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
                     handler.getStateForTesting());

        // Set the role
        setupSwitchSendRoleRequestAndVerify(null, xid, Role.MASTER);
        assertEquals(OFChannelHandler.ChannelState.WAIT_INITIAL_ROLE,
                     handler.getStateForTesting());


        // FIXME: shouldn't use ordinal(), but OFError is broken

        OFMessage err = getErrorMessage(OFErrorType.OFPET_BAD_ACTION,
                                        0,
                                        xid);
        verify(sw);
        reset(sw);
        expect(sw.inputThrottled(anyObject(OFMessage.class)))
                .andReturn(false).anyTimes();
        replay(sw);
        sendMessageToHandlerWithControllerReset(Collections.singletonList(err));

        verifyExceptionCaptured(SwitchStateException.class);
    }

    /**
     * Test dispatch of messages while in MASTER role
     */
    @Test
    public void testMessageDispatchMaster() throws Exception {
        testInitialMoveToMasterWithRole();

        // Send packet in. expect dispatch
        OFPacketIn pi = (OFPacketIn)
                BasicFactory.getInstance().getMessage(OFType.PACKET_IN);
        reset(controller);
        controller.handleMessage(sw, pi, null);
        expectLastCall().once();
        sendMessageToHandlerNoControllerReset(
               Collections.<OFMessage>singletonList(pi));
        verify(controller);
        // TODO: many more to go
    }

    /**
     * Test port status message handling while MASTER
     *
     */
    @Test
    public void testPortStatusMessageMaster() throws Exception {
        long dpid = featuresReply.getDatapathId();
        testInitialMoveToMasterWithRole();

        OFPhysicalPort p = new OFPhysicalPort();
        p.setName("Port1");
        p.setPortNumber((short)1);
        OFPortStatus ps = (OFPortStatus)
                BasicFactory.getInstance().getMessage(OFType.PORT_STATUS);
        ps.setDesc(p);

        // The events we expect sw.handlePortStatus to return
        // We'll just use the same list for all valid OFPortReasons and add
        // arbitrary events for arbitrary ports that are not necessarily
        // related to the port status message. Our goal
        // here is not to return the correct set of events but the make sure
        // that a) sw.handlePortStatus is called
        //      b) the list of events sw.handlePortStatus returns is sent
        //         as IOFSwitchListener notifications.
        OrderedCollection<PortChangeEvent> events =
                new LinkedHashSetWrapper<PortChangeEvent>();
        ImmutablePort p1 = ImmutablePort.create("eth1", (short)1);
        ImmutablePort p2 = ImmutablePort.create("eth2", (short)2);
        ImmutablePort p3 = ImmutablePort.create("eth3", (short)3);
        ImmutablePort p4 = ImmutablePort.create("eth4", (short)4);
        ImmutablePort p5 = ImmutablePort.create("eth5", (short)5);
        events.add(new PortChangeEvent(p1, PortChangeType.ADD));
        events.add(new PortChangeEvent(p2, PortChangeType.DELETE));
        events.add(new PortChangeEvent(p3, PortChangeType.UP));
        events.add(new PortChangeEvent(p4, PortChangeType.DOWN));
        events.add(new PortChangeEvent(p5, PortChangeType.OTHER_UPDATE));


        for (OFPortReason reason: OFPortReason.values()) {
            ps.setReason(reason.getReasonCode());

            reset(sw);
            expect(sw.inputThrottled(anyObject(OFMessage.class)))
                    .andReturn(false).anyTimes();
            expect(sw.getId()).andReturn(dpid).anyTimes();

            expect(sw.processOFPortStatus(ps)).andReturn(events).once();
            replay(sw);

            reset(controller);
            controller.notifyPortChanged(sw, p1, PortChangeType.ADD);
            controller.notifyPortChanged(sw, p2, PortChangeType.DELETE);
            controller.notifyPortChanged(sw, p3, PortChangeType.UP);
            controller.notifyPortChanged(sw, p4, PortChangeType.DOWN);
            controller.notifyPortChanged(sw, p5, PortChangeType.OTHER_UPDATE);
            sendMessageToHandlerNoControllerReset(
                   Collections.<OFMessage>singletonList(ps));
            verify(sw);
            verify(controller);
        }
    }

    /**
     * Test re-assert MASTER
     *
     */
    @Test
    public void testReassertMaster() throws Exception {
        testInitialMoveToMasterWithRole();

        OFError err = (OFError)
                BasicFactory.getInstance().getMessage(OFType.ERROR);
        err.setXid(42);
        err.setErrorType(OFErrorType.OFPET_BAD_REQUEST);
        err.setErrorCode(OFBadRequestCode.OFPBRC_EPERM);

        reset(controller);
        controller.reassertRole(handler, Role.MASTER);
        expectLastCall().once();
        controller.handleMessage(sw, err, null);
        expectLastCall().once();

        sendMessageToHandlerNoControllerReset(
                Collections.<OFMessage>singletonList(err));

        verify(sw);
        verify(controller);
    }


}
TOP

Related Classes of net.floodlightcontroller.core.internal.OFChannelHandlerTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.