Package net.floodlightcontroller.core.internal

Source Code of net.floodlightcontroller.core.internal.OFSwitchBaseTest$OFSwitchTest

/**
*    Copyright 2013, Big Switch Networks, Inc.
*
*    Licensed under the Apache License, Version 2.0 (the "License"); you may
*    not use this file except in compliance with the License. You may obtain
*    a copy of the License at
*
*         http://www.apache.org/licenses/LICENSE-2.0
*
*    Unless required by applicable law or agreed to in writing, software
*    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
*    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
*    License for the specific language governing permissions and limitations
*    under the License.
**/

package net.floodlightcontroller.core.internal;

import static org.easymock.EasyMock.*;
import static org.junit.Assert.*;

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.concurrent.ConcurrentHashMap;

import net.floodlightcontroller.core.FloodlightContext;
import net.floodlightcontroller.core.IFloodlightProviderService;
import net.floodlightcontroller.core.IOFSwitch;
import net.floodlightcontroller.core.SwitchDriverSubHandshakeAlreadyStarted;
import net.floodlightcontroller.core.SwitchDriverSubHandshakeCompleted;
import net.floodlightcontroller.core.SwitchDriverSubHandshakeNotStarted;
import net.floodlightcontroller.core.IOFSwitch.PortChangeEvent;
import net.floodlightcontroller.core.IOFSwitch.PortChangeType;
import net.floodlightcontroller.core.ImmutablePort;
import net.floodlightcontroller.core.OFSwitchBase;
import net.floodlightcontroller.debugcounter.DebugCounter;
import net.floodlightcontroller.debugcounter.IDebugCounterService;
import net.floodlightcontroller.packet.ARP;
import net.floodlightcontroller.packet.Ethernet;
import net.floodlightcontroller.packet.IPacket;
import net.floodlightcontroller.packet.IPv4;

import org.junit.Before;
import org.junit.Test;
import org.openflow.protocol.OFFlowMod;
import org.openflow.protocol.OFMatch;
import org.openflow.protocol.OFMessage;
import org.openflow.protocol.OFPacketIn;
import org.openflow.protocol.OFPortStatus;
import org.openflow.protocol.OFType;
import org.openflow.protocol.OFPacketIn.OFPacketInReason;
import org.openflow.protocol.OFPhysicalPort.OFPortConfig;
import org.openflow.protocol.OFPhysicalPort.OFPortFeatures;
import org.openflow.protocol.OFPortStatus.OFPortReason;
import org.openflow.protocol.factory.BasicFactory;
import org.openflow.protocol.statistics.OFDescriptionStatistics;
import org.openflow.util.HexString;

public class OFSwitchBaseTest {
    private static final String srcMac = "00:44:33:22:11:00";
    IFloodlightProviderService floodlightProvider;
    Map<Long, IOFSwitch> switches;
    private OFMessage blockMessage;
    private OFPacketIn pi;
    private IPacket testPacket;
    private byte[] testPacketSerialized;

    private class OFSwitchTest extends OFSwitchBase {
        public OFSwitchTest(IFloodlightProviderService fp) {
            super();
            stringId = "whatever";
            datapathId = 1L;
            floodlightProvider = fp;
        }

        @Override
        public void setSwitchProperties(OFDescriptionStatistics description) {
            // TODO Auto-generated method stub
        }

        @Override
        public OFPortType getPortType(short port_num) {
            // TODO Auto-generated method stub
            return null;
        }

        @Override
        public boolean isFastPort(short port_num) {
            // TODO Auto-generated method stub
            return false;
        }

        @Override
        public void write(OFMessage msg, FloodlightContext cntx) {
            blockMessage = msg;
        }

        public void setThresholds(int high, int low, int host, int port) {
            sw.setInputThrottleThresholds(high, low, host, port);
        }

        public boolean inputThrottleEnabled() {
            return packetInThrottleEnabled;
        }

        @Override
        public String toString() {
            return "OFSwitchTest";
        }
    }
    private OFSwitchTest sw;
    private ImmutablePort p1a;
    private ImmutablePort p1b;
    private ImmutablePort p2a;
    private ImmutablePort p2b;
    private ImmutablePort p3;
    private final ImmutablePort portFoo1 = ImmutablePort.create("foo", (short)11);
    private final ImmutablePort portFoo2 = ImmutablePort.create("foo", (short)12);
    private final ImmutablePort portBar1 = ImmutablePort.create("bar", (short)11);
    private final ImmutablePort portBar2 = ImmutablePort.create("bar", (short)12);
    private final PortChangeEvent portFoo1Add =
            new PortChangeEvent(portFoo1, PortChangeType.ADD);
    private final PortChangeEvent portFoo2Add =
            new PortChangeEvent(portFoo2, PortChangeType.ADD);
    private final PortChangeEvent portBar1Add =
            new PortChangeEvent(portBar1, PortChangeType.ADD);
    private final PortChangeEvent portBar2Add =
            new PortChangeEvent(portBar2, PortChangeType.ADD);
    private final PortChangeEvent portFoo1Del =
            new PortChangeEvent(portFoo1, PortChangeType.DELETE);
    private final PortChangeEvent portFoo2Del =
            new PortChangeEvent(portFoo2, PortChangeType.DELETE);
    private final PortChangeEvent portBar1Del =
            new PortChangeEvent(portBar1, PortChangeType.DELETE);
    private final PortChangeEvent portBar2Del =
            new PortChangeEvent(portBar2, PortChangeType.DELETE);

    @Before
    public void setUp() throws Exception {
        blockMessage = null;
        // Build our test packet
        testPacket = new Ethernet()
        .setSourceMACAddress(srcMac)
        .setDestinationMACAddress("00:11:22:33:44:55")
        .setEtherType(Ethernet.TYPE_ARP)
        .setPayload(
                new ARP()
                .setHardwareType(ARP.HW_TYPE_ETHERNET)
                .setProtocolType(ARP.PROTO_TYPE_IP)
                .setHardwareAddressLength((byte) 6)
                .setProtocolAddressLength((byte) 4)
                .setOpCode(ARP.OP_REPLY)
                .setSenderHardwareAddress(Ethernet.toMACAddress("00:44:33:22:11:00"))
                .setSenderProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.1"))
                .setTargetHardwareAddress(Ethernet.toMACAddress("00:11:22:33:44:55"))
                .setTargetProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.2")));
        testPacketSerialized = testPacket.serialize();

        pi = ((OFPacketIn) BasicFactory.getInstance().getMessage(OFType.PACKET_IN))
                .setBufferId(-1)
                .setInPort((short) 1)
                .setPacketData(testPacketSerialized)
                .setReason(OFPacketInReason.NO_MATCH)
                .setTotalLength((short) testPacketSerialized.length);
        floodlightProvider = createMock(IFloodlightProviderService.class);
        sw = new OFSwitchTest(floodlightProvider);
        IDebugCounterService debugCounter = new DebugCounter();
        sw.setDebugCounterService(debugCounter);
        switches = new ConcurrentHashMap<Long, IOFSwitch>();
        switches.put(sw.getId(), sw);
        expect(floodlightProvider.getSwitch(sw.getId())).andReturn(sw).anyTimes();
        expect(floodlightProvider.getOFMessageFactory())
                .andReturn(BasicFactory.getInstance()).anyTimes();
    }

    @Before
    public void setUpPorts() {
        ImmutablePort.Builder bld = new ImmutablePort.Builder();
        // p1a is disabled
        p1a = bld.setName("port1")
                 .setPortNumber((short)1)
                 .setPortStateLinkDown(true)
                 .build();
        assertFalse("Sanity check portEnabled", p1a.isEnabled());

        // p1b is enabled
        // p1b has different feature from p1a
        p1b = bld.addCurrentFeature(OFPortFeatures.OFPPF_1GB_FD)
                 .setPortStateLinkDown(false)
                 .build();
        assertTrue("Sanity check portEnabled", p1b.isEnabled());

        // p2 is disabled
        // p2 has mixed case
        bld = new ImmutablePort.Builder();
        p2a = bld.setName("Port2")
                .setPortNumber((short)2)
                .setPortStateLinkDown(false)
                .addConfig(OFPortConfig.OFPPC_PORT_DOWN)
                .build();
        // p2b only differs in PortFeatures
        p2b = bld.addCurrentFeature(OFPortFeatures.OFPPF_100MB_HD)
                 .build();
        assertFalse("Sanity check portEnabled", p2a.isEnabled());
        // p3 is enabled
        // p3 has mixed case
        bld = new ImmutablePort.Builder();
        p3 = bld.setName("porT3")
                .setPortNumber((short)3)
                .setPortStateLinkDown(false)
                .build();
        assertTrue("Sanity check portEnabled", p3.isEnabled());

    }

    /**
     * By default, high threshold is infinite
     */
    @Test
    public void testNoPacketInThrottle() {
        replay(floodlightProvider);
        /* disable input throttle */
        sw.setThresholds(Integer.MAX_VALUE, 1, 0, 0);
        for (int i = 0; i < 200; i++) {
            assertFalse(sw.inputThrottled(pi));
        }
        assertTrue(blockMessage == null);
        assertFalse(sw.inputThrottleEnabled());
    }

    /**
     * The test sends packet in at infinite rate (< 1ms),
     * so throttling should be enabled on 100th packet, when the first
     * rate measurement is done.
     */
    @Test
    public void testPacketInStartThrottle() {
        floodlightProvider.addSwitchEvent(anyLong(),
                (String)anyObject(), anyBoolean());
        replay(floodlightProvider);

        int high = 500;
        sw.setThresholds(high, 10, 50, 200);
        // We measure time lapse every 1000 packets
        for (int i = 0; i < 1000; i++) {
            assertFalse(sw.inputThrottleEnabled());
            assertFalse(sw.inputThrottled(pi));
        }
        assertTrue(sw.inputThrottleEnabled());
        assertTrue(sw.inputThrottled(pi));
        assertTrue(sw.inputThrottled(pi));
        assertTrue(blockMessage == null);
    }

    /**
     * With throttling enabled, raise the low water mark threshold,
     * verify throttling stops.
     * @throws InterruptedException
     */
    @Test
    public void testPacketInStopThrottle() throws InterruptedException {
        floodlightProvider.addSwitchEvent(anyLong(),
                (String)anyObject(), anyBoolean());
        expectLastCall().times(2);
        replay(floodlightProvider);

        sw.setThresholds(100, 10, 50, 200);
        // First, enable throttling
        for (int i = 0; i < 1000; i++) {
            assertFalse(sw.inputThrottleEnabled());
            assertFalse(sw.inputThrottled(pi));
        }
        assertTrue(sw.inputThrottleEnabled());

        sw.setThresholds(Integer.MAX_VALUE, 100000, 50, 200);
        for (int i = 0; i < 999; i++) {
            assertTrue(sw.inputThrottled(pi));
            assertTrue(sw.inputThrottleEnabled());
        }
        // Sleep for 2 msec, next packet should disable throttling
        Thread.sleep(2);
        assertFalse(sw.inputThrottled(pi));
        assertFalse(sw.inputThrottleEnabled());
   }

    /**
     * With throttling enabled, if rate of unique flows from a host
     * exceeds set threshold, a flow mod should be emitted to block host
     */
    @Test
    public void testPacketInBlockHost() {
        floodlightProvider.addSwitchEvent(anyLong(),
                (String)anyObject(), anyBoolean());
        expectLastCall().times(2);
        replay(floodlightProvider);

        int high = 500;
        int perMac = 50;
        sw.setThresholds(high, 10, perMac, 200);
        // First, enable throttling
        for (int i = 0; i < 1000; i++) {
            assertFalse(sw.inputThrottleEnabled());
            assertFalse(sw.inputThrottled(pi));
        }
        assertTrue(sw.inputThrottleEnabled());
        assertTrue(blockMessage == null);

        // Build unique flows with the same source mac
        for (int j = 0; j < perMac - 1; j++) {
            testPacketSerialized[5]++;
            pi.setPacketData(testPacketSerialized);
            assertFalse(sw.inputThrottled(pi));
        }
        assertTrue(blockMessage == null);
        testPacketSerialized[5]++;
        pi.setPacketData(testPacketSerialized);
        assertFalse(sw.inputThrottled(pi));

        // Verify the message is a flowmod with a hard timeout and srcMac
        assertTrue(blockMessage != null);
        assertTrue(blockMessage instanceof OFFlowMod);
        OFFlowMod fm = (OFFlowMod) blockMessage;
        assertTrue(fm.getHardTimeout() == 5);
        OFMatch match = fm.getMatch();
        assertTrue((match.getWildcards() & OFMatch.OFPFW_DL_SRC) == 0);
        assertTrue(Arrays.equals(match.getDataLayerSource(),
                HexString.fromHexString(srcMac)));

        // Verify non-unique OFMatches are throttled
        assertTrue(sw.inputThrottled(pi));
    }

    /**
     * With throttling enabled, if rate of unique flows from a port
     * exceeds set threshold, a flow mod should be emitted to block port
     */
    @Test
    public void testPacketInBlockPort() {
        floodlightProvider.addSwitchEvent(anyLong(),
                (String)anyObject(), anyBoolean());
        expectLastCall().times(2);
        replay(floodlightProvider);

        int high = 500;
        int perPort = 200;
        sw.setThresholds(high, 10, 50, perPort);
        // First, enable throttling
        for (int i = 0; i < 1000; i++) {
            assertFalse(sw.inputThrottleEnabled());
            assertFalse(sw.inputThrottled(pi));
        }
        assertTrue(sw.inputThrottleEnabled());
        assertTrue(blockMessage == null);

        // Build unique flows with different source mac
        for (int j = 0; j < perPort - 1; j++) {
            testPacketSerialized[11]++;
            pi.setPacketData(testPacketSerialized);
            assertFalse(sw.inputThrottled(pi));
        }
        assertTrue(blockMessage == null);
        testPacketSerialized[11]++;
        pi.setPacketData(testPacketSerialized);
        assertFalse(sw.inputThrottled(pi));

        // Verify the message is a flowmod with a hard timeout and per port
        assertTrue(blockMessage != null);
        assertTrue(blockMessage instanceof OFFlowMod);
        OFFlowMod fm = (OFFlowMod) blockMessage;
        assertTrue(fm.getHardTimeout() == 5);
        OFMatch match = fm.getMatch();
        assertTrue((match.getWildcards() & OFMatch.OFPFW_DL_SRC) != 0);
        assertTrue((match.getWildcards() & OFMatch.OFPFW_IN_PORT) == 0);
        assertTrue(match.getInputPort() == 1);

        // Verify non-unique OFMatches are throttled
        assertTrue(sw.inputThrottled(pi));
    }

    /**
     * Test whether two collections contains the same elements, regardless
     * of the order in which the elements appear in the collections
     * @param expected
     * @param actual
     */
    private static <T> void assertCollectionEqualsNoOrder(Collection<T> expected,
                                         Collection<T> actual) {
        String msg = String.format("expected=%s, actual=%s",
                                   expected, actual);
        assertEquals(msg, expected.size(), actual.size());
        for(T e: expected) {
            if (!actual.contains(e)) {
                msg = String.format("Expected element %s not found in " +
                        "actual. expected=%s, actual=%s",
                    e, expected, actual);
                fail(msg);
            }
        }
    }


    /**
     * Test "normal" setPorts() and comparePorts() methods. No name<->number
     * conflicts or exception testing.
     */
    @Test
    public void testBasicSetPortOperations() {
        Collection<ImmutablePort> oldPorts = Collections.emptyList();
        Collection<ImmutablePort> oldEnabledPorts = Collections.emptyList();
        Collection<Short> oldEnabledPortNumbers = Collections.emptyList();
        List<ImmutablePort> ports = new ArrayList<ImmutablePort>();


        Collection<PortChangeEvent> expectedChanges =
                new ArrayList<IOFSwitch.PortChangeEvent>();

        Collection<PortChangeEvent> actualChanges = sw.comparePorts(ports);
        assertCollectionEqualsNoOrder(expectedChanges, actualChanges);
        assertEquals(0, sw.getPorts().size());
        assertEquals(0, sw.getEnabledPorts().size());
        assertEquals(0, sw.getEnabledPortNumbers().size());

        actualChanges = sw.setPorts(ports);
        assertCollectionEqualsNoOrder(expectedChanges, actualChanges);
        assertEquals(0, sw.getPorts().size());
        assertEquals(0, sw.getEnabledPorts().size());
        assertEquals(0, sw.getEnabledPortNumbers().size());

        //---------------------------------------------
        // Add port p1a and p2a
        ports.add(p1a);
        ports.add(p2a);

        PortChangeEvent evP1aAdded =
                new PortChangeEvent(p1a, PortChangeType.ADD);
        PortChangeEvent evP2aAdded =
                new PortChangeEvent(p2a, PortChangeType.ADD);

        expectedChanges.clear();
        expectedChanges.add(evP1aAdded);
        expectedChanges.add(evP2aAdded);

        actualChanges = sw.comparePorts(ports);
        assertEquals(0, sw.getPorts().size());
        assertEquals(0, sw.getEnabledPorts().size());
        assertEquals(0, sw.getEnabledPortNumbers().size());
        assertEquals(2, actualChanges.size());
        assertCollectionEqualsNoOrder(expectedChanges, actualChanges);

        actualChanges = sw.setPorts(ports);
        assertEquals(2, actualChanges.size());
        assertCollectionEqualsNoOrder(expectedChanges, actualChanges);

        assertCollectionEqualsNoOrder(ports, sw.getPorts());
        assertTrue("enabled ports should be empty",
                   sw.getEnabledPortNumbers().isEmpty());
        assertTrue("enabled ports should be empty",
                   sw.getEnabledPorts().isEmpty());
        assertEquals(p1a, sw.getPort((short)1));
        assertEquals(p1a, sw.getPort("port1"));
        assertEquals(p1a, sw.getPort("PoRt1")); // case insensitive get

        assertEquals(p2a, sw.getPort((short)2));
        assertEquals(p2a, sw.getPort("port2"));
        assertEquals(p2a, sw.getPort("PoRt2")); // case insensitive get

        assertEquals(null, sw.getPort((short)3));
        assertEquals(null, sw.getPort("port3"));
        assertEquals(null, sw.getPort("PoRt3")); // case insensitive get


        //----------------------------------------------------
        // Set the same ports again. No changes
        oldPorts = sw.getPorts();
        oldEnabledPorts = sw.getEnabledPorts();
        oldEnabledPortNumbers = sw.getEnabledPortNumbers();

        expectedChanges.clear();

        actualChanges = sw.comparePorts(ports);
        assertCollectionEqualsNoOrder(expectedChanges, actualChanges);
        assertEquals(oldPorts, sw.getPorts());
        assertEquals(oldEnabledPorts, sw.getEnabledPorts());
        assertEquals(oldEnabledPortNumbers, sw.getEnabledPortNumbers());

        actualChanges = sw.setPorts(ports);
        assertCollectionEqualsNoOrder(expectedChanges, actualChanges);
        assertEquals(oldPorts, sw.getPorts());
        assertEquals(oldEnabledPorts, sw.getEnabledPorts());
        assertEquals(oldEnabledPortNumbers, sw.getEnabledPortNumbers());
        assertCollectionEqualsNoOrder(ports, sw.getPorts());

        assertTrue("enabled ports should be empty",
                   sw.getEnabledPortNumbers().isEmpty());
        assertTrue("enabled ports should be empty",
                   sw.getEnabledPorts().isEmpty());
        assertEquals(p1a, sw.getPort((short)1));
        assertEquals(p1a, sw.getPort("port1"));
        assertEquals(p1a, sw.getPort("PoRt1")); // case insensitive get

        assertEquals(p2a, sw.getPort((short)2));
        assertEquals(p2a, sw.getPort("port2"));
        assertEquals(p2a, sw.getPort("PoRt2")); // case insensitive get

        assertEquals(null, sw.getPort((short)3));
        assertEquals(null, sw.getPort("port3"));
        assertEquals(null, sw.getPort("PoRt3")); // case insensitive get

        //----------------------------------------------------
        // Remove p1a, add p1b. Should receive a port up
        oldPorts = sw.getPorts();
        oldEnabledPorts = sw.getEnabledPorts();
        oldEnabledPortNumbers = sw.getEnabledPortNumbers();
        ports.clear();
        ports.add(p2a);
        ports.add(p1b);

        // comparePorts
        PortChangeEvent evP1bUp = new PortChangeEvent(p1b, PortChangeType.UP);
        actualChanges = sw.comparePorts(ports);
        assertEquals(oldPorts, sw.getPorts());
        assertEquals(oldEnabledPorts, sw.getEnabledPorts());
        assertEquals(oldEnabledPortNumbers, sw.getEnabledPortNumbers());
        assertEquals(1, actualChanges.size());
        assertTrue("No UP event for port1", actualChanges.contains(evP1bUp));

        // setPorts
        actualChanges = sw.setPorts(ports);
        assertEquals(1, actualChanges.size());
        assertTrue("No UP event for port1", actualChanges.contains(evP1bUp));
        assertCollectionEqualsNoOrder(ports, sw.getPorts());
        List<ImmutablePort> enabledPorts = new ArrayList<ImmutablePort>();
        enabledPorts.add(p1b);
        List<Short> enabledPortNumbers = new ArrayList<Short>();
        enabledPortNumbers.add((short)1);
        assertCollectionEqualsNoOrder(enabledPorts, sw.getEnabledPorts());
        assertCollectionEqualsNoOrder(enabledPortNumbers,
                                   sw.getEnabledPortNumbers());
        assertEquals(p1b, sw.getPort((short)1));
        assertEquals(p1b, sw.getPort("port1"));
        assertEquals(p1b, sw.getPort("PoRt1")); // case insensitive get

        assertEquals(p2a, sw.getPort((short)2));
        assertEquals(p2a, sw.getPort("port2"));
        assertEquals(p2a, sw.getPort("PoRt2")); // case insensitive get

        assertEquals(null, sw.getPort((short)3));
        assertEquals(null, sw.getPort("port3"));
        assertEquals(null, sw.getPort("PoRt3")); // case insensitive get

        //----------------------------------------------------
        // Remove p2a, add p2b. Should receive a port modify
        oldPorts = sw.getPorts();
        oldEnabledPorts = sw.getEnabledPorts();
        oldEnabledPortNumbers = sw.getEnabledPortNumbers();
        ports.clear();
        ports.add(p2b);
        ports.add(p1b);

        PortChangeEvent evP2bModified =
                new PortChangeEvent(p2b, PortChangeType.OTHER_UPDATE);

        // comparePorts
        actualChanges = sw.comparePorts(ports);
        assertEquals(oldPorts, sw.getPorts());
        assertEquals(oldEnabledPorts, sw.getEnabledPorts());
        assertEquals(oldEnabledPortNumbers, sw.getEnabledPortNumbers());
        assertEquals(1, actualChanges.size());
        assertTrue("No OTHER_CHANGE event for port2",
                   actualChanges.contains(evP2bModified));

        // setPorts
        actualChanges = sw.setPorts(ports);
        assertEquals(1, actualChanges.size());
        assertTrue("No OTHER_CHANGE event for port2",
                   actualChanges.contains(evP2bModified));
        assertCollectionEqualsNoOrder(ports, sw.getPorts());
        enabledPorts = new ArrayList<ImmutablePort>();
        enabledPorts.add(p1b);
        enabledPortNumbers = new ArrayList<Short>();
        enabledPortNumbers.add((short)1);
        assertCollectionEqualsNoOrder(enabledPorts, sw.getEnabledPorts());
        assertCollectionEqualsNoOrder(enabledPortNumbers,
                                   sw.getEnabledPortNumbers());
        assertEquals(p1b, sw.getPort((short)1));
        assertEquals(p1b, sw.getPort("port1"));
        assertEquals(p1b, sw.getPort("PoRt1")); // case insensitive get

        assertEquals(p2b, sw.getPort((short)2));
        assertEquals(p2b, sw.getPort("port2"));
        assertEquals(p2b, sw.getPort("PoRt2")); // case insensitive get

        assertEquals(null, sw.getPort((short)3));
        assertEquals(null, sw.getPort("port3"));
        assertEquals(null, sw.getPort("PoRt3")); // case insensitive get


        //----------------------------------------------------
        // Remove p1b, add p1a. Should receive a port DOWN
        // Remove p2b, add p2a. Should receive a port modify
        // Add p3, should receive an add
        oldPorts = sw.getPorts();
        oldEnabledPorts = sw.getEnabledPorts();
        oldEnabledPortNumbers = sw.getEnabledPortNumbers();
        ports.clear();
        ports.add(p2a);
        ports.add(p1a);
        ports.add(p3);

        PortChangeEvent evP1aDown =
                new PortChangeEvent(p1a, PortChangeType.DOWN);
        PortChangeEvent evP2aModified =
                new PortChangeEvent(p2a, PortChangeType.OTHER_UPDATE);
        PortChangeEvent evP3Add =
                new PortChangeEvent(p3, PortChangeType.ADD);
        expectedChanges.clear();
        expectedChanges.add(evP1aDown);
        expectedChanges.add(evP2aModified);
        expectedChanges.add(evP3Add);

        // comparePorts
        actualChanges = sw.comparePorts(ports);
        assertEquals(oldPorts, sw.getPorts());
        assertEquals(oldEnabledPorts, sw.getEnabledPorts());
        assertEquals(oldEnabledPortNumbers, sw.getEnabledPortNumbers());
        assertCollectionEqualsNoOrder(expectedChanges, actualChanges);

        // setPorts
        actualChanges = sw.setPorts(ports);
        assertCollectionEqualsNoOrder(expectedChanges, actualChanges);
        assertCollectionEqualsNoOrder(ports, sw.getPorts());
        enabledPorts.clear();
        enabledPorts.add(p3);
        enabledPortNumbers.clear();
        enabledPortNumbers.add((short)3);
        assertCollectionEqualsNoOrder(enabledPorts, sw.getEnabledPorts());
        assertCollectionEqualsNoOrder(enabledPortNumbers,
                                   sw.getEnabledPortNumbers());
        assertEquals(p1a, sw.getPort((short)1));
        assertEquals(p1a, sw.getPort("port1"));
        assertEquals(p1a, sw.getPort("PoRt1")); // case insensitive get

        assertEquals(p2a, sw.getPort((short)2));
        assertEquals(p2a, sw.getPort("port2"));
        assertEquals(p2a, sw.getPort("PoRt2")); // case insensitive get

        assertEquals(p3, sw.getPort((short)3));
        assertEquals(p3, sw.getPort("port3"));
        assertEquals(p3, sw.getPort("PoRt3")); // case insensitive get


        //----------------------------------------------------
        // Remove p1b Should receive a port DELETE
        // Remove p2b Should receive a port DELETE
        oldPorts = sw.getPorts();
        oldEnabledPorts = sw.getEnabledPorts();
        oldEnabledPortNumbers = sw.getEnabledPortNumbers();
        ports.clear();
        ports.add(p3);

        PortChangeEvent evP1aDel =
                new PortChangeEvent(p1a, PortChangeType.DELETE);
        PortChangeEvent evP2aDel =
                new PortChangeEvent(p2a, PortChangeType.DELETE);
        expectedChanges.clear();
        expectedChanges.add(evP1aDel);
        expectedChanges.add(evP2aDel);

        // comparePorts
        actualChanges = sw.comparePorts(ports);
        assertEquals(oldPorts, sw.getPorts());
        assertEquals(oldEnabledPorts, sw.getEnabledPorts());
        assertEquals(oldEnabledPortNumbers, sw.getEnabledPortNumbers());
        assertCollectionEqualsNoOrder(expectedChanges, actualChanges);

        // setPorts
        actualChanges = sw.setPorts(ports);
        assertCollectionEqualsNoOrder(expectedChanges, actualChanges);
        assertCollectionEqualsNoOrder(ports, sw.getPorts());
        enabledPorts.clear();
        enabledPorts.add(p3);
        enabledPortNumbers.clear();
        enabledPortNumbers.add((short)3);
        assertCollectionEqualsNoOrder(enabledPorts, sw.getEnabledPorts());
        assertCollectionEqualsNoOrder(enabledPortNumbers,
                                   sw.getEnabledPortNumbers());

        assertEquals(p3, sw.getPort((short)3));
        assertEquals(p3, sw.getPort("port3"));
        assertEquals(p3, sw.getPort("PoRt3")); // case insensitive get
    }


    /**
     * Test "normal" OFPortStatus handling. No name<->number
     * conflicts or exception testing.
     */
    @Test
    public void testBasicPortStatusOperation() {
        OFPortStatus ps = (OFPortStatus)
                BasicFactory.getInstance().getMessage(OFType.PORT_STATUS);
        List<ImmutablePort> ports = new ArrayList<ImmutablePort>();
        ports.add(p1a);
        ports.add(p2a);


        // Set p1a and p2a as baseline
        PortChangeEvent evP1aAdded =
                new PortChangeEvent(p1a, PortChangeType.ADD);
        PortChangeEvent evP2aAdded =
                new PortChangeEvent(p2a, PortChangeType.ADD);

        Collection<PortChangeEvent> expectedChanges =
                new ArrayList<IOFSwitch.PortChangeEvent>();
        expectedChanges.add(evP1aAdded);
        expectedChanges.add(evP2aAdded);

        Collection<PortChangeEvent> actualChanges = sw.comparePorts(ports);
        assertEquals(0, sw.getPorts().size());
        assertEquals(0, sw.getEnabledPorts().size());
        assertEquals(0, sw.getEnabledPortNumbers().size());
        assertEquals(2, actualChanges.size());
        assertCollectionEqualsNoOrder(expectedChanges, actualChanges);

        actualChanges = sw.setPorts(ports);
        assertEquals(2, actualChanges.size());
        assertCollectionEqualsNoOrder(expectedChanges, actualChanges);

        assertCollectionEqualsNoOrder(ports, sw.getPorts());
        assertTrue("enabled ports should be empty",
                   sw.getEnabledPortNumbers().isEmpty());
        assertTrue("enabled ports should be empty",
                   sw.getEnabledPorts().isEmpty());
        assertEquals(p1a, sw.getPort((short)1));
        assertEquals(p1a, sw.getPort("port1"));
        assertEquals(p1a, sw.getPort("PoRt1")); // case insensitive get

        assertEquals(p2a, sw.getPort((short)2));
        assertEquals(p2a, sw.getPort("port2"));
        assertEquals(p2a, sw.getPort("PoRt2")); // case insensitive get

        //----------------------------------------------------
        // P1a -> p1b. Should receive a port up
        ports.clear();
        ports.add(p2a);
        ports.add(p1b);

        ps.setReason(OFPortReason.OFPPR_MODIFY.getReasonCode());
        ps.setDesc(p1b.toOFPhysicalPort());

        PortChangeEvent evP1bUp = new PortChangeEvent(p1b, PortChangeType.UP);
        actualChanges = sw.processOFPortStatus(ps);
        expectedChanges.clear();
        expectedChanges.add(evP1bUp);
        assertCollectionEqualsNoOrder(expectedChanges, actualChanges);
        assertCollectionEqualsNoOrder(ports, sw.getPorts());
        List<ImmutablePort> enabledPorts = new ArrayList<ImmutablePort>();
        enabledPorts.add(p1b);
        List<Short> enabledPortNumbers = new ArrayList<Short>();
        enabledPortNumbers.add((short)1);
        assertCollectionEqualsNoOrder(enabledPorts, sw.getEnabledPorts());
        assertCollectionEqualsNoOrder(enabledPortNumbers,
                                   sw.getEnabledPortNumbers());
        assertEquals(p1b, sw.getPort((short)1));
        assertEquals(p1b, sw.getPort("port1"));
        assertEquals(p1b, sw.getPort("PoRt1")); // case insensitive get

        assertEquals(p2a, sw.getPort((short)2));
        assertEquals(p2a, sw.getPort("port2"));
        assertEquals(p2a, sw.getPort("PoRt2")); // case insensitive get

        //----------------------------------------------------
        // p2a -> p2b. Should receive a port modify
        ports.clear();
        ports.add(p2b);
        ports.add(p1b);

        PortChangeEvent evP2bModified =
                new PortChangeEvent(p2b, PortChangeType.OTHER_UPDATE);

        ps.setReason(OFPortReason.OFPPR_MODIFY.getReasonCode());
        ps.setDesc(p2b.toOFPhysicalPort());

        actualChanges = sw.processOFPortStatus(ps);
        expectedChanges.clear();
        expectedChanges.add(evP2bModified);
        assertCollectionEqualsNoOrder(expectedChanges, actualChanges);
        assertCollectionEqualsNoOrder(ports, sw.getPorts());
        enabledPorts = new ArrayList<ImmutablePort>();
        enabledPorts.add(p1b);
        enabledPortNumbers = new ArrayList<Short>();
        enabledPortNumbers.add((short)1);
        assertCollectionEqualsNoOrder(enabledPorts, sw.getEnabledPorts());
        assertCollectionEqualsNoOrder(enabledPortNumbers,
                                   sw.getEnabledPortNumbers());
        assertEquals(p1b, sw.getPort((short)1));
        assertEquals(p1b, sw.getPort("port1"));
        assertEquals(p1b, sw.getPort("PoRt1")); // case insensitive get

        assertEquals(p2b, sw.getPort((short)2));
        assertEquals(p2b, sw.getPort("port2"));
        assertEquals(p2b, sw.getPort("PoRt2")); // case insensitive get

        assertEquals(null, sw.getPort((short)3));
        assertEquals(null, sw.getPort("port3"));
        assertEquals(null, sw.getPort("PoRt3")); // case insensitive get


        //----------------------------------------------------
        // p1b -> p1a. Via an OFPPR_ADD, Should receive a port DOWN
        ports.clear();
        ports.add(p2b);
        ports.add(p1a);

        // we use an ADD here. We treat ADD and MODIFY the same way
        ps.setReason(OFPortReason.OFPPR_ADD.getReasonCode());
        ps.setDesc(p1a.toOFPhysicalPort());

        PortChangeEvent evP1aDown =
                new PortChangeEvent(p1a, PortChangeType.DOWN);
        actualChanges = sw.processOFPortStatus(ps);
        expectedChanges.clear();
        expectedChanges.add(evP1aDown);
        assertCollectionEqualsNoOrder(expectedChanges, actualChanges);
        assertCollectionEqualsNoOrder(ports, sw.getPorts());
        enabledPorts.clear();
        enabledPortNumbers.clear();
        assertCollectionEqualsNoOrder(enabledPorts, sw.getEnabledPorts());
        assertCollectionEqualsNoOrder(enabledPortNumbers,
                                   sw.getEnabledPortNumbers());
        assertEquals(p1a, sw.getPort((short)1));
        assertEquals(p1a, sw.getPort("port1"));
        assertEquals(p1a, sw.getPort("PoRt1")); // case insensitive get

        assertEquals(p2b, sw.getPort((short)2));
        assertEquals(p2b, sw.getPort("port2"));
        assertEquals(p2b, sw.getPort("PoRt2")); // case insensitive get


        //----------------------------------------------------
        // p2b -> p2a. Via an OFPPR_ADD, Should receive a port MODIFY
        ports.clear();
        ports.add(p2a);
        ports.add(p1a);

        // we use an ADD here. We treat ADD and MODIFY the same way
        ps.setReason(OFPortReason.OFPPR_ADD.getReasonCode());
        ps.setDesc(p2a.toOFPhysicalPort());

        PortChangeEvent evP2aModify =
                new PortChangeEvent(p2a, PortChangeType.OTHER_UPDATE);
        actualChanges = sw.processOFPortStatus(ps);
        expectedChanges.clear();
        expectedChanges.add(evP2aModify);
        assertCollectionEqualsNoOrder(expectedChanges, actualChanges);
        assertCollectionEqualsNoOrder(ports, sw.getPorts());
        enabledPorts.clear();
        enabledPortNumbers.clear();
        assertCollectionEqualsNoOrder(enabledPorts, sw.getEnabledPorts());
        assertCollectionEqualsNoOrder(enabledPortNumbers,
                                   sw.getEnabledPortNumbers());
        assertEquals(p1a, sw.getPort((short)1));
        assertEquals(p1a, sw.getPort("port1"));
        assertEquals(p1a, sw.getPort("PoRt1")); // case insensitive get

        assertEquals(p2a, sw.getPort((short)2));
        assertEquals(p2a, sw.getPort("port2"));
        assertEquals(p2a, sw.getPort("PoRt2")); // case insensitive get


        //----------------------------------------------------
        // Remove p2a
        ports.clear();
        ports.add(p1a);

        ps.setReason(OFPortReason.OFPPR_DELETE.getReasonCode());
        ps.setDesc(p2a.toOFPhysicalPort());

        PortChangeEvent evP2aDel =
                new PortChangeEvent(p2a, PortChangeType.DELETE);
        actualChanges = sw.processOFPortStatus(ps);
        expectedChanges.clear();
        expectedChanges.add(evP2aDel);
        assertCollectionEqualsNoOrder(expectedChanges, actualChanges);
        assertCollectionEqualsNoOrder(ports, sw.getPorts());
        enabledPorts.clear();
        enabledPortNumbers.clear();
        assertCollectionEqualsNoOrder(enabledPorts, sw.getEnabledPorts());
        assertCollectionEqualsNoOrder(enabledPortNumbers,
                                   sw.getEnabledPortNumbers());
        assertEquals(p1a, sw.getPort((short)1));
        assertEquals(p1a, sw.getPort("port1"));
        assertEquals(p1a, sw.getPort("PoRt1")); // case insensitive get

        assertEquals(null, sw.getPort((short)2));
        assertEquals(null, sw.getPort("port2"));
        assertEquals(null, sw.getPort("PoRt2")); // case insensitive get

        //----------------------------------------------------
        // Remove p2a again. Nothing should happen.
        ports.clear();
        ports.add(p1a);

        ps.setReason(OFPortReason.OFPPR_DELETE.getReasonCode());
        ps.setDesc(p2a.toOFPhysicalPort());

        actualChanges = sw.processOFPortStatus(ps);
        expectedChanges.clear();
        assertCollectionEqualsNoOrder(expectedChanges, actualChanges);
        assertCollectionEqualsNoOrder(ports, sw.getPorts());
        enabledPorts.clear();
        enabledPortNumbers.clear();
        assertCollectionEqualsNoOrder(enabledPorts, sw.getEnabledPorts());
        assertCollectionEqualsNoOrder(enabledPortNumbers,
                                   sw.getEnabledPortNumbers());
        assertEquals(p1a, sw.getPort((short)1));
        assertEquals(p1a, sw.getPort("port1"));
        assertEquals(p1a, sw.getPort("PoRt1")); // case insensitive get

        assertEquals(null, sw.getPort((short)2));
        assertEquals(null, sw.getPort("port2"));
        assertEquals(null, sw.getPort("PoRt2")); // case insensitive get


        //----------------------------------------------------
        // Remove p1a
        ports.clear();

        ps.setReason(OFPortReason.OFPPR_DELETE.getReasonCode());
        ps.setDesc(p1a.toOFPhysicalPort());

        PortChangeEvent evP1aDel =
                new PortChangeEvent(p1a, PortChangeType.DELETE);
        actualChanges = sw.processOFPortStatus(ps);
        expectedChanges.clear();
        expectedChanges.add(evP1aDel);
        assertCollectionEqualsNoOrder(expectedChanges, actualChanges);
        assertCollectionEqualsNoOrder(ports, sw.getPorts());
        enabledPorts.clear();
        enabledPortNumbers.clear();
        assertCollectionEqualsNoOrder(enabledPorts, sw.getEnabledPorts());
        assertCollectionEqualsNoOrder(enabledPortNumbers,
                                   sw.getEnabledPortNumbers());
        assertEquals(null, sw.getPort((short)1));
        assertEquals(null, sw.getPort("port1"));
        assertEquals(null, sw.getPort("PoRt1")); // case insensitive get

        assertEquals(null, sw.getPort((short)2));
        assertEquals(null, sw.getPort("port2"));
        assertEquals(null, sw.getPort("PoRt2")); // case insensitive get


        //----------------------------------------------------
        // Add p3, should receive an add
        ports.clear();
        ports.add(p3);

        PortChangeEvent evP3Add =
                new PortChangeEvent(p3, PortChangeType.ADD);
        expectedChanges.clear();
        expectedChanges.add(evP3Add);

        ps.setReason(OFPortReason.OFPPR_ADD.getReasonCode());
        ps.setDesc(p3.toOFPhysicalPort());

        actualChanges = sw.processOFPortStatus(ps);
        assertCollectionEqualsNoOrder(expectedChanges, actualChanges);
        assertCollectionEqualsNoOrder(ports, sw.getPorts());
        enabledPorts.clear();
        enabledPorts.add(p3);
        enabledPortNumbers.clear();
        enabledPortNumbers.add((short)3);
        assertCollectionEqualsNoOrder(enabledPorts, sw.getEnabledPorts());
        assertCollectionEqualsNoOrder(enabledPortNumbers,
                                   sw.getEnabledPortNumbers());
        assertEquals(null, sw.getPort((short)1));
        assertEquals(null, sw.getPort("port1"));
        assertEquals(null, sw.getPort("PoRt1")); // case insensitive get

        assertEquals(null, sw.getPort((short)2));
        assertEquals(null, sw.getPort("port2"));
        assertEquals(null, sw.getPort("PoRt2")); // case insensitive get

        assertEquals(p3, sw.getPort((short)3));
        assertEquals(p3, sw.getPort("port3"));
        assertEquals(p3, sw.getPort("PoRt3")); // case insensitive get

        //----------------------------------------------------
        // Add p1b, back should receive an add
        ports.clear();
        ports.add(p1b);
        ports.add(p3);

        PortChangeEvent evP1bAdd =
                new PortChangeEvent(p1b, PortChangeType.ADD);
        expectedChanges.clear();
        expectedChanges.add(evP1bAdd);

        // use a modify to add the port
        ps.setReason(OFPortReason.OFPPR_MODIFY.getReasonCode());
        ps.setDesc(p1b.toOFPhysicalPort());

        actualChanges = sw.processOFPortStatus(ps);
        assertCollectionEqualsNoOrder(expectedChanges, actualChanges);
        assertCollectionEqualsNoOrder(ports, sw.getPorts());
        enabledPorts.clear();
        enabledPorts.add(p3);
        enabledPorts.add(p1b);
        enabledPortNumbers.clear();
        enabledPortNumbers.add((short)3);
        enabledPortNumbers.add((short)1);
        assertCollectionEqualsNoOrder(enabledPorts, sw.getEnabledPorts());
        assertCollectionEqualsNoOrder(enabledPortNumbers,
                                   sw.getEnabledPortNumbers());
        assertEquals(p1b, sw.getPort((short)1));
        assertEquals(p1b, sw.getPort("port1"));
        assertEquals(p1b, sw.getPort("PoRt1")); // case insensitive get

        assertEquals(null, sw.getPort((short)2));
        assertEquals(null, sw.getPort("port2"));
        assertEquals(null, sw.getPort("PoRt2")); // case insensitive get

        assertEquals(p3, sw.getPort((short)3));
        assertEquals(p3, sw.getPort("port3"));
        assertEquals(p3, sw.getPort("PoRt3")); // case insensitive get

        //----------------------------------------------------
        // Modify, but nothing really changed
        ports.clear();
        ports.add(p1b);
        ports.add(p3);

        expectedChanges.clear();

        // use a modify to add the port
        ps.setReason(OFPortReason.OFPPR_MODIFY.getReasonCode());
        ps.setDesc(p1b.toOFPhysicalPort());

        actualChanges = sw.processOFPortStatus(ps);
        assertCollectionEqualsNoOrder(expectedChanges, actualChanges);
        assertCollectionEqualsNoOrder(ports, sw.getPorts());
        enabledPorts.clear();
        enabledPorts.add(p3);
        enabledPorts.add(p1b);
        enabledPortNumbers.clear();
        enabledPortNumbers.add((short)3);
        enabledPortNumbers.add((short)1);
        assertCollectionEqualsNoOrder(enabledPorts, sw.getEnabledPorts());
        assertCollectionEqualsNoOrder(enabledPortNumbers,
                                   sw.getEnabledPortNumbers());
        assertEquals(p1b, sw.getPort((short)1));
        assertEquals(p1b, sw.getPort("port1"));
        assertEquals(p1b, sw.getPort("PoRt1")); // case insensitive get

        assertEquals(null, sw.getPort((short)2));
        assertEquals(null, sw.getPort("port2"));
        assertEquals(null, sw.getPort("PoRt2")); // case insensitive get

        assertEquals(p3, sw.getPort((short)3));
        assertEquals(p3, sw.getPort("port3"));
        assertEquals(p3, sw.getPort("PoRt3")); // case insensitive get
    }


    /**
     * Test exception handling for setPorts() and comparePorts()
     */
    @Test
    public void testSetPortExceptions() {
        try {
            sw.setPorts(null);
            fail("Excpeted exception not thrown");
        } catch (NullPointerException e) { };

        // two ports with same name
        List<ImmutablePort> ports = new ArrayList<ImmutablePort>();
        ports.add(ImmutablePort.create("port1", (short)1));
        ports.add(ImmutablePort.create("port1", (short)2));
        try {
            sw.setPorts(ports);
            fail("Excpeted exception not thrown");
        } catch (IllegalArgumentException e) { };

        // two ports with same number
        ports.clear();
        ports.add(ImmutablePort.create("port1", (short)1));
        ports.add(ImmutablePort.create("port2", (short)1));
        try {
            sw.setPorts(ports);
            fail("Excpeted exception not thrown");
        } catch (IllegalArgumentException e) { };

        // null port in list
        ports.clear();
        ports.add(ImmutablePort.create("port1", (short)1));
        ports.add(null);
        try {
            sw.setPorts(ports);
            fail("Excpeted exception not thrown");
        } catch (NullPointerException e) { };

        // try getPort(null)
        try {
            sw.getPort(null);
            fail("Excpeted exception not thrown");
        } catch (NullPointerException e) { };

        //--------------------------
        // comparePorts()
        try {
            sw.comparePorts(null);
            fail("Excpeted exception not thrown");
        } catch (NullPointerException e) { };

        // two ports with same name
        ports = new ArrayList<ImmutablePort>();
        ports.add(ImmutablePort.create("port1", (short)1));
        ports.add(ImmutablePort.create("port1", (short)2));
        try {
            sw.comparePorts(ports);
            fail("Excpeted exception not thrown");
        } catch (IllegalArgumentException e) { };

        // two ports with same number
        ports.clear();
        ports.add(ImmutablePort.create("port1", (short)1));
        ports.add(ImmutablePort.create("port2", (short)1));
        try {
            sw.comparePorts(ports);
            fail("Excpeted exception not thrown");
        } catch (IllegalArgumentException e) { };

        // null port in list
        ports.clear();
        ports.add(ImmutablePort.create("port1", (short)1));
        ports.add(null);
        try {
            sw.comparePorts(ports);
            fail("Excpeted exception not thrown");
        } catch (NullPointerException e) { };

        // try getPort(null)
        try {
            sw.getPort(null);
            fail("Excpeted exception not thrown");
        } catch (NullPointerException e) { };

    }

    @Test
    public void testPortStatusExceptions() {
        OFPortStatus ps = (OFPortStatus)
                BasicFactory.getInstance().getMessage(OFType.PORT_STATUS);

        try {
            sw.processOFPortStatus(null);
            fail("Expected exception not thrown");
        } catch (NullPointerException e)  { }

        // illegal reason code
        ps.setReason((byte)0x42);
        ps.setDesc(ImmutablePort.create("p1", (short)1).toOFPhysicalPort());
        try {
            sw.processOFPortStatus(ps);
            fail("Expected exception not thrown");
        } catch (IllegalArgumentException e)  { }

        // null port
        ps.setReason(OFPortReason.OFPPR_ADD.getReasonCode());
        ps.setDesc(null);
        try {
            sw.processOFPortStatus(ps);
            fail("Expected exception not thrown");
        } catch (NullPointerException e)  { }
    }

    /**
     * Assert that the expected PortChangeEvents have been recevied, asserting
     * the expected ordering.
     *
     * All events in earlyEvents have to appear in actualEvents before any
     * event in lateEvent appears. Events in anytimeEvents can appear at any
     * given time. earlyEvents, lateEvents, and anytimeEvents must be mutually
     * exclusive (their intersection must be none) and their union must
     * contain all elements from actualEvents
     * @param earlyEvents
     * @param lateEvents
     * @param anytimeEvents
     * @param actualEvents
     */
    private static void assertChangeEvents(Collection<PortChangeEvent> earlyEvents,
                                      Collection<PortChangeEvent> lateEvents,
                                      Collection<PortChangeEvent> anytimeEvents,
                                      Collection<PortChangeEvent> actualEvents) {
        String inputDesc = String.format("earlyEvents=%s, lateEvents=%s, " +
                "anytimeEvents=%s, actualEvents=%s",
                earlyEvents, lateEvents, anytimeEvents, actualEvents);
        // Make copies of expected lists, so we can modify them
        Collection<PortChangeEvent> early =
                new ArrayList<PortChangeEvent>(earlyEvents);
        Collection<PortChangeEvent> late =
                new ArrayList<PortChangeEvent>(lateEvents);
        Collection<PortChangeEvent> any =
                new ArrayList<PortChangeEvent>(anytimeEvents);

        // Sanity check: no overlap between early, late, and anytime events
        for (PortChangeEvent ev: early) {
            assertFalse("Test setup error. Early and late overlap",
                        late.contains(ev));
            assertFalse("Test setup error. Early and anytime overlap",
                        any.contains(ev));
        }
        for (PortChangeEvent ev: late) {
            assertFalse("Test setup error. Late and early overlap",
                        early.contains(ev));
            assertFalse("Test setup error. Late and any overlap",
                        any.contains(ev));
        }
        for (PortChangeEvent ev: any) {
            assertFalse("Test setup error. Anytime and early overlap",
                        early.contains(ev));
            assertFalse("Test setup error. Anytime and late overlap",
                        late.contains(ev));
        }

        for (PortChangeEvent a: actualEvents) {
            if (early.remove(a)) {
                continue;
            }
            if (any.remove(a)) {
                continue;
            }
            if (late.remove(a)) {
                if (!early.isEmpty()) {
                    fail(a + " is in late list, but haven't seen all required " +
                         "early events. " + inputDesc);
                } else {
                    continue;
                }
            }
            fail(a + " was not expected. " + inputDesc);
        }
        if (!early.isEmpty())
            fail("Elements left in early: " + early + ". " + inputDesc);
        if (!late.isEmpty())
            fail("Elements left in late: " + late + ". " + inputDesc);
        if (!any.isEmpty())
            fail("Elements left in any: " + any + ". " + inputDesc);
    }

    /**
     * Test setPort() with changing name / number mappings
     * We don't test comparePorts() here. We assume setPorts() and
     * comparePorts() use the same underlying implementation
     */
    @Test
    public void testSetPortNameNumberMappingChange() {

        List<ImmutablePort> ports = new ArrayList<ImmutablePort>();
        Collection<PortChangeEvent> early = new ArrayList<PortChangeEvent>();
        Collection<PortChangeEvent> late = new ArrayList<PortChangeEvent>();
        Collection<PortChangeEvent> anytime = new ArrayList<PortChangeEvent>();
        Collection<PortChangeEvent> actualChanges = null;

        ports.add(portFoo1);
        ports.add(p1a);
        sw.setPorts(ports);
        assertCollectionEqualsNoOrder(ports, sw.getPorts());

        // Add portFoo2: name collision
        ports.clear();
        ports.add(portFoo2);
        ports.add(p1a);
        early.clear();
        late.clear();
        anytime.clear();
        actualChanges = sw.setPorts(ports);
        early.add(portFoo1Del);
        late.add(portFoo2Add);
        assertChangeEvents(early, late, anytime, actualChanges);
        assertCollectionEqualsNoOrder(ports, sw.getPorts());

        // Add portBar2: number collision
        ports.clear();
        ports.add(portBar2);
        ports.add(p1a);
        early.clear();
        late.clear();
        anytime.clear();
        actualChanges = sw.setPorts(ports);
        early.add(portFoo2Del);
        late.add(portBar2Add);
        assertChangeEvents(early, late, anytime, actualChanges);
        assertCollectionEqualsNoOrder(ports, sw.getPorts());

        // Set to portFoo1, portBar2. No collisions in this step
        ports.clear();
        ports.add(portFoo1);
        ports.add(portBar2);
        ports.add(p1a);
        early.clear();
        late.clear();
        anytime.clear();
        actualChanges = sw.setPorts(ports);
        anytime.add(portFoo1Add);
        assertChangeEvents(early, late, anytime, actualChanges);
        assertCollectionEqualsNoOrder(ports, sw.getPorts());

        // Add portFoo2: name and number collision
        ports.clear();
        ports.add(portFoo2);
        ports.add(p1a);
        early.clear();
        late.clear();
        anytime.clear();
        actualChanges = sw.setPorts(ports);
        early.add(portFoo1Del);
        early.add(portBar2Del);
        late.add(portFoo2Add);
        assertChangeEvents(early, late, anytime, actualChanges);
        assertCollectionEqualsNoOrder(ports, sw.getPorts());

        // Set to portFoo2, portBar1. No collisions in this step
        ports.clear();
        ports.add(portFoo2);
        ports.add(portBar1);
        ports.add(p1a);
        early.clear();
        late.clear();
        anytime.clear();
        actualChanges = sw.setPorts(ports);
        anytime.add(portBar1Add);
        assertChangeEvents(early, late, anytime, actualChanges);
        assertCollectionEqualsNoOrder(ports, sw.getPorts());

        // Add portFoo1, portBar2 name and number collision
        // Also change p1a -> p1b: expect modify for it
        // Also add p3: expect add for it
        PortChangeEvent p1bUp = new PortChangeEvent(p1b, PortChangeType.UP);
        PortChangeEvent p3Add = new PortChangeEvent(p3, PortChangeType.ADD);
        ports.clear();
        ports.add(portFoo1);
        ports.add(portBar2);
        ports.add(p1b);
        ports.add(p3);
        early.clear();
        late.clear();
        anytime.clear();
        actualChanges = sw.setPorts(ports);
        early.add(portFoo2Del);
        early.add(portBar1Del);
        late.add(portFoo1Add);
        late.add(portBar2Add);
        anytime.add(p1bUp);
        anytime.add(p3Add);
        assertChangeEvents(early, late, anytime, actualChanges);
        assertCollectionEqualsNoOrder(ports, sw.getPorts());
    }


    @Test
    public void testPortStatusNameNumberMappingChange() {
        List<ImmutablePort> ports = new ArrayList<ImmutablePort>();
        Collection<PortChangeEvent> early = new ArrayList<PortChangeEvent>();
        Collection<PortChangeEvent> late = new ArrayList<PortChangeEvent>();
        Collection<PortChangeEvent> anytime = new ArrayList<PortChangeEvent>();
        Collection<PortChangeEvent> actualChanges = null;

        // init: add portFoo1, p1a
        ports.add(portFoo1);
        ports.add(p1a);
        sw.setPorts(ports);
        assertCollectionEqualsNoOrder(ports, sw.getPorts());

        OFPortStatus ps = (OFPortStatus)
                BasicFactory.getInstance().getMessage(OFType.PORT_STATUS);

        // portFoo1 -> portFoo2 via MODIFY : name collision
        ps.setReason(OFPortReason.OFPPR_MODIFY.getReasonCode());
        ps.setDesc(portFoo2.toOFPhysicalPort());
        ports.clear();
        ports.add(portFoo2);
        ports.add(p1a);
        early.clear();
        late.clear();
        anytime.clear();
        actualChanges = sw.processOFPortStatus(ps);
        early.add(portFoo1Del);
        late.add(portFoo2Add);
        assertChangeEvents(early, late, anytime, actualChanges);
        assertCollectionEqualsNoOrder(ports, sw.getPorts());

        // portFoo2 -> portBar2 via ADD number collision
        ps.setReason(OFPortReason.OFPPR_ADD.getReasonCode());
        ps.setDesc(portBar2.toOFPhysicalPort());
        ports.clear();
        ports.add(portBar2);
        ports.add(p1a);
        early.clear();
        late.clear();
        anytime.clear();
        actualChanges = sw.processOFPortStatus(ps);
        early.add(portFoo2Del);
        late.add(portBar2Add);
        assertChangeEvents(early, late, anytime, actualChanges);
        assertCollectionEqualsNoOrder(ports, sw.getPorts());

        // Set to portFoo1, portBar2
        ports.clear();
        ports.add(portFoo1);
        ports.add(portBar2);
        sw.setPorts(ports);
        assertCollectionEqualsNoOrder(ports, sw.getPorts());

        // portFoo1 + portBar2 -> portFoo2: name and number collision
        ps.setReason(OFPortReason.OFPPR_MODIFY.getReasonCode());
        ps.setDesc(portFoo2.toOFPhysicalPort());
        ports.clear();
        ports.add(portFoo2);
        early.clear();
        late.clear();
        anytime.clear();
        actualChanges = sw.processOFPortStatus(ps);
        early.add(portFoo1Del);
        early.add(portBar2Del);
        late.add(portFoo2Add);
        assertChangeEvents(early, late, anytime, actualChanges);
        assertCollectionEqualsNoOrder(ports, sw.getPorts());

        //----------------------
        // Test DELETEs

        // del portFoo1: name exists (portFoo2), but number doesn't.
        ps.setReason(OFPortReason.OFPPR_DELETE.getReasonCode());
        ps.setDesc(portFoo1.toOFPhysicalPort());
        ports.clear();
        early.clear();
        late.clear();
        anytime.clear();
        actualChanges = sw.processOFPortStatus(ps);
        anytime.add(portFoo2Del);
        assertChangeEvents(early, late, anytime, actualChanges);
        assertCollectionEqualsNoOrder(ports, sw.getPorts());

        // Set to portFoo1
        ports.clear();
        ports.add(portFoo1);
        sw.setPorts(ports);
        assertCollectionEqualsNoOrder(ports, sw.getPorts());

        // del portBar1: number exists (portFoo1), but name doesn't.
        ps.setReason(OFPortReason.OFPPR_DELETE.getReasonCode());
        ps.setDesc(portBar1.toOFPhysicalPort());
        ports.clear();
        early.clear();
        late.clear();
        anytime.clear();
        actualChanges = sw.processOFPortStatus(ps);
        anytime.add(portFoo1Del);
        assertChangeEvents(early, late, anytime, actualChanges);
        assertCollectionEqualsNoOrder(ports, sw.getPorts());


        // Set to portFoo1, portBar2
        ports.clear();
        ports.add(portFoo1);
        ports.add(portBar2);
        sw.setPorts(ports);
        assertCollectionEqualsNoOrder(ports, sw.getPorts());

        // del portFoo2: name and number exists
        ps.setReason(OFPortReason.OFPPR_DELETE.getReasonCode());
        ps.setDesc(portFoo2.toOFPhysicalPort());
        ports.clear();
        early.clear();
        late.clear();
        anytime.clear();
        actualChanges = sw.processOFPortStatus(ps);
        anytime.add(portFoo1Del);
        anytime.add(portBar2Del);
        assertChangeEvents(early, late, anytime, actualChanges);
        assertCollectionEqualsNoOrder(ports, sw.getPorts());
    }

    @Test
    public void testSubHandshake() {
        OFMessage m = BasicFactory.getInstance().getMessage(OFType.VENDOR);
        // test execptions before handshake is started
        try {
            sw.processDriverHandshakeMessage(m);
            fail("expected exception not thrown");
        } catch (SwitchDriverSubHandshakeNotStarted e) { /* expected */ }
        try {
            sw.isDriverHandshakeComplete();
            fail("expected exception not thrown");
        } catch (SwitchDriverSubHandshakeNotStarted e) { /* expected */ }

        // start the handshake -- it should immediately complete
        sw.startDriverHandshake();
        assertTrue("Handshake should be complete",
                   sw.isDriverHandshakeComplete());

        // test exceptions after handshake is completed
        try {
            sw.processDriverHandshakeMessage(m);
            fail("expected exception not thrown");
        } catch (SwitchDriverSubHandshakeCompleted e) { /* expected */ }
        try {
            sw.startDriverHandshake();
            fail("Expected exception not thrown");
        } catch (SwitchDriverSubHandshakeAlreadyStarted e) { /* expected */ }
    }

}
TOP

Related Classes of net.floodlightcontroller.core.internal.OFSwitchBaseTest$OFSwitchTest

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.