/* * Copyright (c) 2013 Big Switch Networks, Inc. * * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/legal/epl-v10.html * * 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 org.sdnplatform.devicemanager.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.HashSet; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.openflow.protocol.OFPhysicalPort; import org.sdnplatform.core.IOFSwitch; import org.sdnplatform.core.test.MockControllerProvider; import org.sdnplatform.devicemanager.SwitchPort; import org.sdnplatform.devicemanager.internal.SwitchInterfaceRegexMatcher; public class SwitchInterfaceRegexMatcherTest { MockControllerProvider controllerProvider; SwitchInterfaceRegexMatcher matcher; ConcurrentHashMap<Long, IOFSwitch> switches; IOFSwitch sw1; IOFSwitch sw2; ArrayList<OFPhysicalPort> sw1ports; ArrayList<OFPhysicalPort> sw2ports; SwitchPort s1p1; SwitchPort s1p2; SwitchPort s1p3; SwitchPort s2p1; SwitchPort s2p2; @Before public void setUp() { controllerProvider = new MockControllerProvider(); switches = new ConcurrentHashMap<Long, IOFSwitch>(); controllerProvider.setSwitches(switches); matcher = new SwitchInterfaceRegexMatcher(controllerProvider); sw1 = createMock(IOFSwitch.class); sw1ports = new ArrayList<OFPhysicalPort>(); OFPhysicalPort pp = new OFPhysicalPort(); pp.setName("eth1"); pp.setPortNumber((short)1); sw1ports.add(pp); pp = new OFPhysicalPort(); pp.setName("eth2"); pp.setPortNumber((short)2); sw1ports.add(pp); pp = new OFPhysicalPort(); pp.setName("port1"); pp.setPortNumber((short)3); sw1ports.add(pp); expect(sw1.getId()).andReturn(1L).anyTimes(); expect(sw1.getEnabledPorts()).andReturn(sw1ports).anyTimes(); switches.put(1L, sw1); sw2 = createMock(IOFSwitch.class); sw2ports = new ArrayList<OFPhysicalPort>(); pp = new OFPhysicalPort(); pp.setName("eTh1"); pp.setPortNumber((short)11); sw2ports.add(pp); pp = new OFPhysicalPort(); pp.setName("EtH2"); pp.setPortNumber((short)12); sw2ports.add(pp); expect(sw2.getId()).andReturn(2L).anyTimes(); expect(sw2.getEnabledPorts()).andReturn(sw2ports).anyTimes(); switches.put(2L, sw2); s1p1 = new SwitchPort(1L, 1); s1p2 = new SwitchPort(1L, 2); s1p3 = new SwitchPort(1L, 3); s2p1 = new SwitchPort(2L, 11); s2p2 = new SwitchPort(2L, 12); replay(sw1, sw2); } protected void verifyExpectedSwitchPorts(SwitchPort[] exptected, Collection<SwitchPort> actual) { Set<SwitchPort> expectedSet = new HashSet<SwitchPort>(Arrays.asList(exptected)); Set<SwitchPort> actualSet = new HashSet<SwitchPort>(); if (actual != null) actualSet.addAll(actual); assertEquals(expectedSet, actualSet); } @After public void tearDown() { verify(sw1, sw2); } @Test public void testCornerCases() { // make sure these are handled internally and don't generate // exception. // switch doesn't exist. matcher.addOrUpdate("foo", 44L, "pattern"); matcher.switchPortChanged(44L); // invald regex -- should be ignored matcher.addOrUpdate("bar", 1L, "patt["); matcher.addOrUpdate("bar", 1L, "pat{]"); matcher.addOrUpdate("bar", 1L, "pat]df"); matcher.addOrUpdate("bar", 1L, "pat}df"); // remove non-existent, update existent matcher.addOrUpdate("key1", 1L, "eth.*"); matcher.remove("doesnotexist"); matcher.addOrUpdate("key1", 2L, "Eth.*"); } /* Test add, remove, and update */ @Test public void testAddRemoveUpdate() { Collection<SwitchPort> ifaces; matcher.addOrUpdate("key1", 1L, "eth1"); ifaces = matcher.getInterfacesByKey("key1"); verifyExpectedSwitchPorts(new SwitchPort[] { s1p1 }, ifaces); matcher.remove("key1"); ifaces = matcher.getInterfacesByKey("key1"); verifyExpectedSwitchPorts(new SwitchPort[] {}, ifaces); // add again matcher.addOrUpdate("key1", 1L, "eth1"); ifaces = matcher.getInterfacesByKey("key1"); verifyExpectedSwitchPorts(new SwitchPort[] { s1p1 }, ifaces); // update matcher.addOrUpdate("key1", 1L, "eth.*"); ifaces = matcher.getInterfacesByKey("key1"); verifyExpectedSwitchPorts(new SwitchPort[] { s1p1, s1p2 }, ifaces); // update matcher.addOrUpdate("key1", 1L, "eth1"); ifaces = matcher.getInterfacesByKey("key1"); verifyExpectedSwitchPorts(new SwitchPort[] { s1p1 }, ifaces); // different key matcher.addOrUpdate("key2", 2L, "eth1"); ifaces = matcher.getInterfacesByKey("key2"); verifyExpectedSwitchPorts(new SwitchPort[] { s2p1 }, ifaces); ifaces = matcher.getInterfacesByKey("key1"); verifyExpectedSwitchPorts(new SwitchPort[] { s1p1 }, ifaces); } /* Do some general test to see the regex matching is sane */ @Test public void testRegexMatching() { Collection<SwitchPort> ifaces; matcher.addOrUpdate("key1", 1L, "eth1"); ifaces = matcher.getInterfacesByKey("key1"); verifyExpectedSwitchPorts(new SwitchPort[] { s1p1 }, ifaces); matcher.remove("key1"); // basic matching. matcher.addOrUpdate("key1", 1L, "eth.*"); ifaces = matcher.getInterfacesByKey("key1"); verifyExpectedSwitchPorts(new SwitchPort[] { s1p1, s1p2 }, ifaces); matcher.remove("key1"); // different matches matcher.addOrUpdate("key1", 1L, "eth[0-9]"); ifaces = matcher.getInterfacesByKey("key1"); verifyExpectedSwitchPorts(new SwitchPort[] { s1p1, s1p2 }, ifaces); matcher.remove("key1"); // another flavor of matching matcher.addOrUpdate("key1", 1L, "eth[0-9]+"); ifaces = matcher.getInterfacesByKey("key1"); verifyExpectedSwitchPorts(new SwitchPort[] { s1p1, s1p2 }, ifaces); matcher.remove("key1"); // check that regex matching is anchored at start of string matcher.addOrUpdate("key1", 1L, "th[0-9]+"); ifaces = matcher.getInterfacesByKey("key1"); verifyExpectedSwitchPorts(new SwitchPort[] {}, ifaces); matcher.remove("key1"); // check that regex matching is anchored at end matcher.addOrUpdate("key1", 1L, "eth"); ifaces = matcher.getInterfacesByKey("key1"); verifyExpectedSwitchPorts(new SwitchPort[] {}, ifaces); matcher.remove("key1"); // check that regex matching is case insensitive matcher.addOrUpdate("key1", 1L, "eTh.*"); ifaces = matcher.getInterfacesByKey("key1"); verifyExpectedSwitchPorts(new SwitchPort[] { s1p1, s1p2 }, ifaces); matcher.remove("key1"); // check that regex matching is case insensitive matcher.addOrUpdate("key1", 2L, "eth.*"); ifaces = matcher.getInterfacesByKey("key1"); verifyExpectedSwitchPorts(new SwitchPort[] { s2p1, s2p2 }, ifaces); matcher.remove("key1"); } /* Test switch wildcards */ @Test public void testSwitchWildcards() { Collection<SwitchPort> ifaces; matcher.addOrUpdate("key1", 1L, "eth.*"); ifaces = matcher.getInterfacesByKey("key1"); verifyExpectedSwitchPorts(new SwitchPort[] { s1p1, s1p2 }, ifaces); matcher.addOrUpdate("key1", null, "eth.*"); ifaces = matcher.getInterfacesByKey("key1"); verifyExpectedSwitchPorts(new SwitchPort[] { s1p1, s1p2, s2p1, s2p2 }, ifaces); // note new key matcher.addOrUpdate("key2", null, ".*1"); ifaces = matcher.getInterfacesByKey("key2"); verifyExpectedSwitchPorts(new SwitchPort[] { s1p1, s1p3, s2p1 }, ifaces); // just to cross-check: key1 should be unaffected ifaces = matcher.getInterfacesByKey("key1"); verifyExpectedSwitchPorts(new SwitchPort[] { s1p1, s1p2, s2p1, s2p2 }, ifaces); } /* Test adding. removing switches */ @Test public void testSwitchChanges() { Collection<SwitchPort> ifaces; // remove sw2 for the time being switches.remove(2L); // populate our regexes matcher.addOrUpdate("allEth", null, "eth.*"); matcher.addOrUpdate("sw1Eth", 1L, "eth[0-9]"); matcher.addOrUpdate("sw2Eth", 2L, "eth.*"); // verify ifaces = matcher.getInterfacesByKey("allEth"); verifyExpectedSwitchPorts(new SwitchPort[] { s1p1, s1p2 }, ifaces); ifaces = matcher.getInterfacesByKey("sw1Eth"); verifyExpectedSwitchPorts(new SwitchPort[] { s1p1, s1p2 }, ifaces); ifaces = matcher.getInterfacesByKey("sw2Eth"); verifyExpectedSwitchPorts(new SwitchPort[] {}, ifaces); // add switch 2 switches.put(2L, sw2); matcher.addedSwitch(sw2); ifaces = matcher.getInterfacesByKey("allEth"); verifyExpectedSwitchPorts(new SwitchPort[] { s1p1, s1p2, s2p1, s2p2 }, ifaces); ifaces = matcher.getInterfacesByKey("sw1Eth"); verifyExpectedSwitchPorts(new SwitchPort[] { s1p1, s1p2 }, ifaces); ifaces = matcher.getInterfacesByKey("sw2Eth"); verifyExpectedSwitchPorts(new SwitchPort[] { s2p1, s2p2 }, ifaces); // remove switch 1 switches.remove(1L); matcher.removedSwitch(sw1); ifaces = matcher.getInterfacesByKey("allEth"); verifyExpectedSwitchPorts(new SwitchPort[] { s2p1, s2p2 }, ifaces); ifaces = matcher.getInterfacesByKey("sw1Eth"); verifyExpectedSwitchPorts(new SwitchPort[] {}, ifaces); ifaces = matcher.getInterfacesByKey("sw2Eth"); verifyExpectedSwitchPorts(new SwitchPort[] { s2p1, s2p2 }, ifaces); // add switch 1 back switches.put(1L, sw1); matcher.addedSwitch(sw1); ifaces = matcher.getInterfacesByKey("allEth"); verifyExpectedSwitchPorts(new SwitchPort[] { s1p1, s1p2, s2p1, s2p2 }, ifaces); ifaces = matcher.getInterfacesByKey("sw1Eth"); verifyExpectedSwitchPorts(new SwitchPort[] { s1p1, s1p2 }, ifaces); ifaces = matcher.getInterfacesByKey("sw2Eth"); verifyExpectedSwitchPorts(new SwitchPort[] { s2p1, s2p2 }, ifaces); // modify ports on sw1. Since we just fiddle around in the list of // ports we don't need to reset the mock sw1ports.remove(0); // remove port 1 OFPhysicalPort p = new OFPhysicalPort(); p.setPortNumber((short)4); p.setName("eth4"); sw1ports.add(p); SwitchPort s1p4 = new SwitchPort(1L, 4); matcher.switchPortChanged(1L); ifaces = matcher.getInterfacesByKey("allEth"); verifyExpectedSwitchPorts(new SwitchPort[] { s1p2, s1p4, s2p1, s2p2 }, ifaces); ifaces = matcher.getInterfacesByKey("sw1Eth"); verifyExpectedSwitchPorts(new SwitchPort[] { s1p2, s1p4 }, ifaces); ifaces = matcher.getInterfacesByKey("sw2Eth"); verifyExpectedSwitchPorts(new SwitchPort[] { s2p1, s2p2 }, ifaces); } }