From c3ed12c4c7aff2e62ab09f671daee9dd11b4e926 Mon Sep 17 00:00:00 2001 From: Shigeru Yasuda Date: Tue, 2 Jun 2015 01:21:59 +0900 Subject: [PATCH] Bug 3531: Remove unnecessary try-catch blocks in VTNRoutingManager. Other changes: * Refined unit tests. * VTNInventoryManagerTest * VTNRoutingManagerTest Change-Id: Id721d0e6ebe80e253c43681b7b44e1cfcc67d453 Signed-off-by: Shigeru Yasuda --- .../internal/routing/VTNRoutingManager.java | 16 +- .../vtn/manager/internal/TestBase.java | 88 + .../inventory/VTNInventoryManagerTest.java | 1222 ++++++++++++-- .../routing/VTNRoutingManagerTest.java | 1413 ++++++++++++++--- .../src/test/resources/logback.xml | 4 + 5 files changed, 2381 insertions(+), 362 deletions(-) diff --git a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/routing/VTNRoutingManager.java b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/routing/VTNRoutingManager.java index 7fcea1e3..df627dc8 100644 --- a/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/routing/VTNRoutingManager.java +++ b/manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/routing/VTNRoutingManager.java @@ -241,13 +241,7 @@ public final class VTNRoutingManager @Override protected void onCreated(TopologyEventContext ectx, IdentifiedData data) { - VtnLink vlink = data.getValue(); - try { - ectx.addCreated(vlink); - } catch (IllegalArgumentException e) { - LOG.debug("Ignore unsupported inter-switch link creation: " + - vlink, e); - } + ectx.addCreated(data.getValue()); } /** @@ -265,13 +259,7 @@ public final class VTNRoutingManager @Override protected void onRemoved(TopologyEventContext ectx, IdentifiedData data) { - VtnLink vlink = data.getValue(); - try { - ectx.addRemoved(vlink); - } catch (IllegalArgumentException e) { - LOG.debug("Ignore unsupported inter-switch link deletion: " + - vlink, e); - } + ectx.addRemoved(data.getValue()); } /** diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/TestBase.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/TestBase.java index a7a88b89..40252ee7 100644 --- a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/TestBase.java +++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/TestBase.java @@ -9,19 +9,24 @@ package org.opendaylight.vtn.manager.internal; +import static org.opendaylight.vtn.manager.internal.util.rpc.RpcErrorTag.MISSING_ELEMENT; + import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; +import java.lang.reflect.Field; import java.net.InetAddress; import java.util.ArrayList; +import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.TreeSet; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import javax.xml.bind.JAXBContext; @@ -67,6 +72,7 @@ import org.opendaylight.vtn.manager.internal.cluster.VTenantImpl; import org.opendaylight.vtn.manager.internal.cluster.VlanMapPath; import org.opendaylight.vtn.manager.internal.packet.PacketInEvent; import org.opendaylight.vtn.manager.internal.util.inventory.SalPort; +import org.opendaylight.vtn.manager.internal.util.rpc.RpcErrorTag; import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; @@ -86,6 +92,9 @@ import org.opendaylight.controller.sal.utils.GlobalConstants; import org.opendaylight.controller.sal.core.UpdateType; import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.common.RpcError.ErrorType; +import org.opendaylight.yangtools.yang.common.RpcError; +import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.inventory.rev150209.vtn.node.info.VtnPortBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.inventory.rev150209.vtn.port.info.PortLink; @@ -2320,6 +2329,85 @@ public abstract class TestBase extends Assert { } } + /** + * Return the value of the field configured in the given object. + * + * @param obj The target object. + * @param type A class which specifies the type of the field value. + * @param name The name of the field. + * @param The type of the field value. + * @return The value of the field configured in the given object. + * @throws Exception An error occurred. + */ + public static T getFieldValue(Object obj, Class type, String name) + throws Exception { + return getFieldValue(obj, obj.getClass(), type, name); + } + + /** + * Return the value of the field configured in the given object. + * + * @param obj The target object. + * @param objType A class which contains the declaration of the specified + * field. + * @param type A class which specifies the type of the field value. + * @param name The name of the field. + * @param The type of the field value. + * @return The value of the field configured in the given object. + * @throws Exception An error occurred. + */ + public static T getFieldValue(Object obj, Class objType, + Class type, String name) + throws Exception { + Field field = objType.getDeclaredField(name); + field.setAccessible(true); + Object value = field.get(obj); + + assertTrue(type.isInstance(value)); + return type.cast(value); + } + + /** + * Ensure that the given future associated with RPC contains an error state + * caused by a null RPC input. + * + * @param future A future associated with RPC. + * @param The type of RPC output. + * @throws Exception An error occurred. + */ + public static void verifyRpcInputNull(Future> future) + throws Exception { + verifyRpcFailure(future, MISSING_ELEMENT, "BADREQUEST", + "RPC input cannot be null"); + } + + /** + * Ensure that the given future associated with RPC contains an error + * state. + * + * @param future A future associated with RPC. + * @param tag The expected error tag. + * @param apTag The expected application error tag. + * @param msg The expected error message. + * @param The type of RPC output. + * @throws Exception An error occurred. + */ + public static void verifyRpcFailure(Future> future, + RpcErrorTag tag, String apTag, + String msg) throws Exception { + RpcResult result = future.get(1L, TimeUnit.SECONDS); + assertEquals(false, result.isSuccessful()); + + Collection errors = result.getErrors(); + assertEquals(1, errors.size()); + + RpcError error = errors.iterator().next(); + assertEquals(ErrorType.APPLICATION, error.getErrorType()); + assertEquals(tag.toString(), error.getTag()); + assertEquals(apTag, error.getApplicationTag()); + assertEquals(msg, error.getMessage()); + } + /** * check a Ethernet packet whether expected parameters are set. * (for IPv4 packet) diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/inventory/VTNInventoryManagerTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/inventory/VTNInventoryManagerTest.java index c7dd2831..3af47967 100644 --- a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/inventory/VTNInventoryManagerTest.java +++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/inventory/VTNInventoryManagerTest.java @@ -6,249 +6,1231 @@ * terms of the Eclipse Public License v1.0 which accompanies this * distribution, and is available at http://www.eclipse.org/legal/epl-v10.html */ + package org.opendaylight.vtn.manager.internal.inventory; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.isA; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + import org.slf4j.Logger; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; +import org.junit.Before; import org.junit.Test; -import org.mockito.Mockito; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; -import org.opendaylight.vtn.manager.internal.VTNManagerImpl; import org.opendaylight.vtn.manager.internal.VTNManagerProvider; import org.opendaylight.vtn.manager.internal.util.ChangedData; import org.opendaylight.vtn.manager.internal.util.IdentifiedData; import org.opendaylight.vtn.manager.internal.util.IdentifierTargetComparator; +import org.opendaylight.vtn.manager.internal.util.inventory.SalNode; +import org.opendaylight.vtn.manager.internal.util.inventory.SalPort; +import org.opendaylight.vtn.manager.internal.util.tx.TxEvent; + +import org.opendaylight.vtn.manager.internal.TestBase; import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.inventory.rev150209.VtnNodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.inventory.rev150209.VtnOpenflowVersion; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.inventory.rev150209.vtn.node.info.VtnPort; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.inventory.rev150209.vtn.node.info.VtnPortBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.inventory.rev150209.vtn.nodes.VtnNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.inventory.rev150209.vtn.nodes.VtnNodeBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.inventory.rev150209.vtn.port.info.PortLink; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.inventory.rev150209.vtn.port.info.PortLinkBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.types.rev150209.VtnUpdateType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; + +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.LinkId; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link; /** * JUnit test for {@link VTNInventoryManager}. */ -public class VTNInventoryManagerTest { +public class VTNInventoryManagerTest extends TestBase { /** - * Static instance of VTNInventoryManager to perform unit testing. + * Mock-up of {@link VTNManagerProvider}. */ - private static VTNInventoryManager vtnInventoryManager; + @Mock + private VTNManagerProvider vtnProvider; /** - * Static instance of VTNManagerProvider to perform unit testing. + * Mock-up of {@link DataBroker}. */ - private static VTNManagerProvider vtnManagerProvider; + @Mock + private DataBroker dataBroker; /** - * Static instance of VTNInventoryListener to perform unit testing. + * Registration to be associated with {@link NodeListener}. */ - private static VTNInventoryListener vtnInventoryListener; + @Mock + private ListenerRegistration nodeListenerReg; /** - * This method creates the requird objects to perform unit testing + * Registration to be associated with {@link NodeConnectorListener}. */ - @BeforeClass - public static void setUpBeforeClass() { - vtnManagerProvider = Mockito.mock(VTNManagerProvider.class); - Mockito.when(vtnManagerProvider.getDataBroker()).thenReturn(Mockito.mock(DataBroker.class)); - vtnInventoryManager = new VTNInventoryManager(vtnManagerProvider); - vtnInventoryListener = new VTNManagerImpl(); - try { - VTNManagerProvider vtnManagerProvider2 = Mockito.mock(VTNManagerProvider.class); - Mockito.when(vtnManagerProvider.getDataBroker()).thenThrow(new RuntimeException()); - VTNInventoryManager vtnInventoryManager2 = new VTNInventoryManager(vtnManagerProvider2); - VTNInventoryListener vtnInventoryListener2 = new VTNManagerImpl(); - } catch (Exception exception) { - Assert.assertNotNull(exception instanceof IllegalStateException); - } - } + @Mock + private ListenerRegistration ncListenerReg; + + /** + * Registration to be associated with {@link TopologyListener}. + */ + @Mock + private ListenerRegistration topoListenerReg; /** - * This method makes unnecessary objects eligible for garbage collection + * Registration to be associated with {@link VTNInventoryManager}. */ - @AfterClass - public static void tearDownAfterClass() { - vtnInventoryListener = null; - vtnInventoryManager = null; - vtnManagerProvider = null; + @Mock + private ListenerRegistration inventoryListenerReg; + + /** + * A {@link VTNInventoryManager} instance for test. + */ + private VTNInventoryManager inventoryManager; + + /** + * Set up test environment. + */ + @Before + public void setUp() { + initMocks(this); + when(vtnProvider.getDataBroker()).thenReturn(dataBroker); + + when(dataBroker.registerDataChangeListener( + any(LogicalDatastoreType.class), any(InstanceIdentifier.class), + isA(NodeListener.class), any(DataChangeScope.class))). + thenReturn(nodeListenerReg); + + when(dataBroker.registerDataChangeListener( + any(LogicalDatastoreType.class), any(InstanceIdentifier.class), + isA(NodeConnectorListener.class), any(DataChangeScope.class))). + thenReturn(ncListenerReg); + + when(dataBroker.registerDataChangeListener( + any(LogicalDatastoreType.class), any(InstanceIdentifier.class), + isA(TopologyListener.class), any(DataChangeScope.class))). + thenReturn(topoListenerReg); + + when(dataBroker.registerDataChangeListener( + any(LogicalDatastoreType.class), any(InstanceIdentifier.class), + isA(VTNInventoryManager.class), any(DataChangeScope.class))). + thenReturn(inventoryListenerReg); + + inventoryManager = new VTNInventoryManager(vtnProvider); } /** - * Test method for - * {@link VTNInventoryManager#addListener(VTNInventoryListener)}. + * Test case for + * {@link VTNInventoryManager#VTNInventoryManager(VTNManagerProvider)}. */ @Test - public void testAddListener() { - try { - vtnInventoryManager.addListener(vtnInventoryListener); - } catch (Exception exception) { - Assert.fail("VTNInventoryManager test case failed..................."); - } + public void testConstructor() { + LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL; + DataChangeScope scope = DataChangeScope.SUBTREE; + + // Ensure that NodeListner is registered as data change listener. + InstanceIdentifier path = InstanceIdentifier. + builder(Nodes.class). + child(Node.class). + augmentation(FlowCapableNode.class). + build(); + verify(dataBroker).registerDataChangeListener( + eq(oper), eq(path), isA(NodeListener.class), eq(scope)); + + // Ensure that NodeConnectorListner is registered as data change + // listener. + InstanceIdentifier cpath = InstanceIdentifier. + builder(Nodes.class). + child(Node.class). + child(NodeConnector.class). + augmentation(FlowCapableNodeConnector.class). + build(); + verify(dataBroker).registerDataChangeListener( + eq(oper), eq(cpath), isA(NodeConnectorListener.class), eq(scope)); + + // Ensure that TopologyListner is registered as data change listener. + TopologyKey topoKey = new TopologyKey(new TopologyId("flow:1")); + InstanceIdentifier tpath = InstanceIdentifier. + builder(NetworkTopology.class). + child(Topology.class, topoKey). + child(Link.class). + build(); + verify(dataBroker).registerDataChangeListener( + eq(oper), eq(tpath), isA(TopologyListener.class), eq(scope)); + + // Ensure that VTNInventoryManager is registered as data change + // listener. + InstanceIdentifier vpath = getPath(); + verify(dataBroker).registerDataChangeListener( + eq(oper), eq(vpath), eq(inventoryManager), eq(scope)); + + verifyZeroInteractions(nodeListenerReg); + verifyZeroInteractions(ncListenerReg); + verifyZeroInteractions(topoListenerReg); + verifyZeroInteractions(inventoryListenerReg); } /** - * Test method for - * {@link VTNInventoryManager#isAlive()}. + * Test case for + * {@link VTNInventoryManager#addListener(VTNInventoryListener)}. + * + * @throws Exception An error occurred. */ @Test - public void testIsAlive() { - Boolean result = vtnInventoryManager.isAlive(); - Assert.assertTrue(result instanceof Boolean); + public void testAddListener() throws Exception { + List expected = new ArrayList<>(); + for (int i = 0; i < 10; i++) { + VTNInventoryListener l = mock(VTNInventoryListener.class); + expected.add(l); + inventoryManager.addListener(l); + + List listeners = + getFieldValue(inventoryManager, List.class, "vtnListeners"); + assertEquals(expected, listeners); + } + + // Below calls should do nothing because listeners are already added. + for (VTNInventoryListener l: expected) { + inventoryManager.addListener(l); + List listeners = + getFieldValue(inventoryManager, List.class, "vtnListeners"); + assertEquals(expected, listeners); + } } /** - * Test method for - * {@link VTNInventoryManager#shutdown()}. + * Test case for {@link VTNInventoryManager#shutdown()} and + * {@link VTNInventoryManager#isAlive()}. */ @Test public void testShutdown() { - try { - vtnInventoryManager.shutdown(); - } catch (Exception exception) { - Assert.fail("VTNInventoryManager test case failed..................."); + ListenerRegistration[] regs = { + nodeListenerReg, + ncListenerReg, + topoListenerReg, + inventoryListenerReg, + }; + + for (ListenerRegistration reg: regs) { + verifyZeroInteractions(reg); + } + assertEquals(true, inventoryManager.isAlive()); + + inventoryManager.shutdown(); + assertEquals(false, inventoryManager.isAlive()); + + // Data change listeners should be still active. + for (ListenerRegistration reg: regs) { + verifyZeroInteractions(reg); } } /** - * Test method for - * {@link VTNInventoryManager#close()}. + * Test case for {@link VTNInventoryManager#close()}. + * + * @throws Exception An error occurred. */ @Test - public void testClose() { - try { - vtnInventoryManager.close(); - } catch (Exception exception) { - Assert.fail("VTNInventoryManager test case failed..................."); + public void testClose() throws Exception { + List expected = new ArrayList<>(); + for (int i = 0; i < 10; i++) { + VTNInventoryListener l = mock(VTNInventoryListener.class); + expected.add(l); + inventoryManager.addListener(l); + } + + List listeners = + getFieldValue(inventoryManager, List.class, "vtnListeners"); + assertEquals(expected, listeners); + + ListenerRegistration[] regs = { + nodeListenerReg, + ncListenerReg, + topoListenerReg, + inventoryListenerReg, + }; + + for (ListenerRegistration reg: regs) { + verifyZeroInteractions(reg); + } + assertEquals(true, inventoryManager.isAlive()); + + inventoryManager.close(); + assertEquals(false, inventoryManager.isAlive()); + for (ListenerRegistration reg: regs) { + verify(reg).close(); + } + + listeners = + getFieldValue(inventoryManager, List.class, "vtnListeners"); + expected = Collections.emptyList(); + assertEquals(expected, listeners); + + // Listener registrations should never be closed twice. + inventoryManager.close(); + assertEquals(false, inventoryManager.isAlive()); + for (ListenerRegistration reg: regs) { + verify(reg).close(); } } /** - * Test method for - * {@link VTNInventoryManager#getComparator()}. + * Test case for {@link VTNInventoryManager#getComparator()}. */ @Test public void testGetComparator() { - IdentifierTargetComparator identifierTargetComparator = vtnInventoryManager.getComparator(); - Assert.assertTrue(identifierTargetComparator instanceof IdentifierTargetComparator); + IdentifierTargetComparator comp = inventoryManager.getComparator(); + assertTrue(comp.getOrder(VtnNode.class).intValue() < + comp.getOrder(VtnPort.class).intValue()); + + // Sort instance identifiers. + InstanceIdentifier nodePath1 = + new SalNode(1L).getVtnNodeIdentifier(); + InstanceIdentifier nodePath2 = + new SalNode(2L).getVtnNodeIdentifier(); + InstanceIdentifier portPath1 = + new SalPort(1L, 1L).getVtnPortIdentifier(); + InstanceIdentifier portPath2 = + new SalPort(1L, 2L).getVtnPortIdentifier(); + List> list = new ArrayList<>(); + Collections.addAll(list, nodePath1, portPath1, nodePath2, portPath2); + + Collections.sort(list, comp); + assertEquals(VtnNode.class, list.get(0).getTargetType()); + assertEquals(VtnNode.class, list.get(1).getTargetType()); + assertEquals(VtnPort.class, list.get(2).getTargetType()); + assertEquals(VtnPort.class, list.get(3).getTargetType()); } /** - * Test method for - * {@link VTNInventoryManager#getOrder(VtnUpdateType)}. + * Test case for {@link VTNInventoryManager#getOrder(VtnUpdateType)}. */ @Test public void testGetOrder() { - Assert.assertTrue(vtnInventoryManager.getOrder(VtnUpdateType.CREATED)); - Assert.assertTrue(vtnInventoryManager.getOrder(VtnUpdateType.CHANGED)); - Assert.assertFalse(vtnInventoryManager.getOrder(VtnUpdateType.REMOVED)); + assertEquals(true, inventoryManager.getOrder(VtnUpdateType.CREATED)); + assertEquals(true, inventoryManager.getOrder(VtnUpdateType.CHANGED)); + assertEquals(false, inventoryManager.getOrder(VtnUpdateType.REMOVED)); } /** - * Test method for + * Test case for * {@link VTNInventoryManager#enterEvent(AsyncDataChangeEvent)}. */ @Test public void testEnterEvent() { - Assert.assertNull(vtnInventoryManager.enterEvent(Mockito.mock(AsyncDataChangeEvent.class))); + AsyncDataChangeEvent ev = null; + assertEquals(null, inventoryManager.enterEvent(ev)); } /** - * Test method for + * Test case for * {@link VTNInventoryManager#exitEvent(Void)}. */ @Test public void testExitEvent() { - try { - vtnInventoryManager.exitEvent(null); - } catch (Exception exception) { - Assert.fail("VTNInventoryManager test case failed..................."); - } + // exitEvent() should do nothing. + inventoryManager.exitEvent(null); } /** - * Test method for - * {@link VTNInventoryManager#onCreated(Void,IdentifiedData)}. + * Ensure that creation events are delivered to + * {@link VTNInventoryListener}. + * + *
    + *
  • {@link VTNInventoryManager#onCreated(Void,IdentifiedData)}
  • + *
  • {@link VTNInventoryManager#addListener(VTNInventoryListener)}
  • + *
+ * + * @throws Exception An error occurred. */ @Test - public void testOnCreated() { - try { - vtnInventoryManager.onCreated(null, Mockito.mock(IdentifiedData.class)); - } catch (Exception exception) { - Assert.fail("VTNInventoryManager test case failed..................."); - } + public void testOnCreated() throws Exception { + testOnCreatedOrRemoved(VtnUpdateType.CREATED); } /** - * Test method for - * {@link VTNInventoryManager#onUpdated(Void,ChangedData)}. + * Ensure that update events are delivered to + * {@link VTNInventoryListener}. + * + *
    + *
  • {@link VTNInventoryManager#onUpdated(Void,ChangedData)}
  • + *
  • {@link VTNInventoryManager#addListener(VTNInventoryListener)}
  • + *
+ * + * @throws Exception An error occurred. */ @Test - public void testOnUpdated() { - try { - InstanceIdentifier instanceIdentifier = InstanceIdentifier.builder(Nodes.class).child(Node.class).child(NodeConnector.class) - .augmentation(FlowCapableNodeConnector.class).build(); - ChangedData changedData = new ChangedData(instanceIdentifier, Mockito.mock(FlowCapableNodeConnector.class), Mockito.mock(FlowCapableNodeConnector.class)); - vtnInventoryManager.onUpdated(null, changedData); - } catch (Exception exception) { - Assert.fail("VTNInventoryManager test case failed................... "); + public void testOnUpdated() throws Exception { + reset(vtnProvider); + final int nlisteners = 3; + VTNInventoryListener[] listeners = new VTNInventoryListener[nlisteners]; + for (int i = 0; i < nlisteners; i++) { + VTNInventoryListener l = mock(VTNInventoryListener.class); + listeners[i] = l; + inventoryManager.addListener(l); } - try { - InstanceIdentifier instanceIdentifier = InstanceIdentifier.builder(VtnNodes.class).child(VtnNode.class).build(); - ChangedData changedData = new ChangedData(instanceIdentifier, Mockito.mock(VtnNode.class), Mockito.mock(VtnNode.class)); - vtnInventoryManager.onUpdated(null, changedData); - } catch (Exception exception) { - Assert.fail("VTNInventoryManager test case failed................... "); + + // In case of node event. + SalNode snode = new SalNode(1L); + VtnNode vnodeOld = mock(VtnNode.class); + when(vnodeOld.getId()).thenReturn(snode.getNodeId()); + when(vnodeOld.getOpenflowVersion()). + thenReturn((VtnOpenflowVersion)null); + VtnNode vnodeNew = mock(VtnNode.class); + when(vnodeNew.getId()).thenReturn(snode.getNodeId()); + when(vnodeNew.getOpenflowVersion()). + thenReturn(VtnOpenflowVersion.OF10); + ChangedData ndata = new ChangedData<>( + snode.getVtnNodeIdentifier(), vnodeNew, vnodeOld); + inventoryManager.onUpdated(null, ndata); + + // Node change event should never be delivered to listeners. + verifyZeroInteractions(vtnProvider); + for (VTNInventoryListener l: listeners) { + verifyZeroInteractions(l); + } + + // The change of OpenFlow version should be logged. + verify(vnodeOld, never()).getId(); + verify(vnodeOld).getOpenflowVersion(); + verify(vnodeNew).getId(); + verify(vnodeNew).getOpenflowVersion(); + + // In case where the node is not changed. + vnodeOld = mock(VtnNode.class); + when(vnodeOld.getId()).thenReturn(snode.getNodeId()); + when(vnodeOld.getOpenflowVersion()). + thenReturn((VtnOpenflowVersion)null); + vnodeNew = mock(VtnNode.class); + when(vnodeNew.getId()).thenReturn(snode.getNodeId()); + when(vnodeNew.getOpenflowVersion()). + thenReturn((VtnOpenflowVersion)null); + ndata = new ChangedData<>(snode.getVtnNodeIdentifier(), vnodeNew, + vnodeOld); + inventoryManager.onUpdated(null, ndata); + + verifyZeroInteractions(vtnProvider); + for (VTNInventoryListener l: listeners) { + verifyZeroInteractions(l); + } + + verify(vnodeOld, never()).getId(); + verify(vnodeOld).getOpenflowVersion(); + verify(vnodeNew, never()).getId(); + verify(vnodeNew).getOpenflowVersion(); + + // In case where the port name is enabled. + SalPort sport = new SalPort(123L, 456L); + VtnPort vportOld = new VtnPortBuilder(). + setId(sport.getNodeConnectorId()). + setEnabled(true). + setCost(1000L). + build(); + VtnPort vportNew = new VtnPortBuilder(). + setId(sport.getNodeConnectorId()). + setName("port-456"). + setEnabled(true). + setCost(1000L). + build(); + ChangedData pdata1 = new ChangedData<>( + sport.getVtnPortIdentifier(), vportNew, vportOld); + inventoryManager.onUpdated(null, pdata1); + + // Vefiry delivered events. + ArgumentCaptor captor = + ArgumentCaptor.forClass(VtnPortEvent.class); + verify(vtnProvider, never()).post(isA(VtnNodeEvent.class)); + verify(vtnProvider, times(nlisteners)).post(captor.capture()); + List delivered = captor.getAllValues(); + assertEquals(listeners.length, delivered.size()); + for (int i = 0; i < nlisteners; i++) { + VtnPortEvent ev = delivered.get(i); + assertEquals(listeners[i], + getFieldValue(ev, VTNInventoryListener.class, + "listener")); + assertEquals(sport, ev.getSalPort()); + assertEquals(vportNew, ev.getVtnPort()); + assertEquals(null, ev.getInterSwitchLinkChange()); + assertEquals(VtnUpdateType.CHANGED, ev.getUpdateType()); + assertEquals(false, ev.isDisabled()); + verifyZeroInteractions(listeners[i]); + } + reset(vtnProvider); + + // In case where the port link is changed. + PortLink plink = new PortLinkBuilder(). + setLinkId(new LinkId("link:1")). + setPeer(new NodeConnectorId("openflow:3:4")). + build(); + vportOld = new VtnPortBuilder(). + setId(sport.getNodeConnectorId()). + setName("port-456"). + setPortLink(Collections.emptyList()). + setEnabled(true). + setCost(1000L). + build(); + vportNew = new VtnPortBuilder(). + setId(sport.getNodeConnectorId()). + setName("port-456"). + setPortLink(Collections.singletonList(plink)). + setEnabled(true). + setCost(1000L). + build(); + ChangedData pdata2 = new ChangedData<>( + sport.getVtnPortIdentifier(), vportNew, vportOld); + inventoryManager.onUpdated(null, pdata2); + + // Vefiry delivered events. + captor = ArgumentCaptor.forClass(VtnPortEvent.class); + verify(vtnProvider, never()).post(isA(VtnNodeEvent.class)); + verify(vtnProvider, times(nlisteners)).post(captor.capture()); + delivered = captor.getAllValues(); + assertEquals(listeners.length, delivered.size()); + for (int i = 0; i < nlisteners; i++) { + VtnPortEvent ev = delivered.get(i); + assertEquals(listeners[i], + getFieldValue(ev, VTNInventoryListener.class, + "listener")); + assertEquals(sport, ev.getSalPort()); + assertEquals(vportNew, ev.getVtnPort()); + assertEquals(Boolean.TRUE, ev.getInterSwitchLinkChange()); + assertEquals(VtnUpdateType.CHANGED, ev.getUpdateType()); + assertEquals(false, ev.isDisabled()); + verifyZeroInteractions(listeners[i]); + } + reset(vtnProvider); + + // In case where the port link is deleted, and the port is disabled. + vportOld = new VtnPortBuilder(). + setId(sport.getNodeConnectorId()). + setName("port-456"). + setPortLink(Collections.singletonList(plink)). + setEnabled(true). + setCost(1000L). + build(); + vportNew = new VtnPortBuilder(). + setId(sport.getNodeConnectorId()). + setName("port-456"). + setEnabled(false). + setCost(1000L). + build(); + ChangedData pdata3 = new ChangedData<>( + sport.getVtnPortIdentifier(), vportNew, vportOld); + inventoryManager.onUpdated(null, pdata3); + + // Vefiry delivered events. + captor = ArgumentCaptor.forClass(VtnPortEvent.class); + verify(vtnProvider, never()).post(isA(VtnNodeEvent.class)); + verify(vtnProvider, times(nlisteners)).post(captor.capture()); + delivered = captor.getAllValues(); + assertEquals(listeners.length, delivered.size()); + for (int i = 0; i < nlisteners; i++) { + VtnPortEvent ev = delivered.get(i); + assertEquals(listeners[i], + getFieldValue(ev, VTNInventoryListener.class, + "listener")); + assertEquals(sport, ev.getSalPort()); + assertEquals(vportNew, ev.getVtnPort()); + assertEquals(Boolean.FALSE, ev.getInterSwitchLinkChange()); + assertEquals(VtnUpdateType.CHANGED, ev.getUpdateType()); + assertEquals(true, ev.isDisabled()); + verifyZeroInteractions(listeners[i]); + } + + // In case of unexpected event. + InstanceIdentifier badPath = InstanceIdentifier. + builder(Nodes.class). + child(Node.class, new NodeKey(new NodeId("unknown:1"))). + build(); + Node badNode1 = mock(Node.class); + Node badNode2 = mock(Node.class); + ChangedData badData = + new ChangedData<>(badPath, badNode1, badNode2); + inventoryManager.onUpdated(null, badData); + + verifyZeroInteractions(vtnProvider); + verifyZeroInteractions(badNode1); + verifyZeroInteractions(badNode2); + for (VTNInventoryListener l: listeners) { + verifyZeroInteractions(l); + } + + // No events should be delivered after shutdown. + inventoryManager.shutdown(); + inventoryManager.onUpdated(null, ndata); + inventoryManager.onUpdated(null, pdata1); + inventoryManager.onUpdated(null, pdata2); + inventoryManager.onUpdated(null, pdata3); + inventoryManager.onUpdated(null, badData); + + verifyZeroInteractions(vtnProvider); + for (VTNInventoryListener l: listeners) { + verifyZeroInteractions(l); } } /** - * Test method for - * {@link VTNInventoryManager#onRemoved(Void,IdentifiedData)}. + * Ensure that removal events are delivered to + * {@link VTNInventoryListener}. + * + *
    + *
  • {@link VTNInventoryManager#onRemoved(Void,IdentifiedData)}
  • + *
  • {@link VTNInventoryManager#addListener(VTNInventoryListener)}
  • + *
+ * + * @throws Exception An error occurred. */ @Test - public void testOnRemoved() { - try { - vtnInventoryManager.onRemoved(null, Mockito.mock(IdentifiedData.class)); - } catch (Exception exception) { - Assert.fail("VTNInventoryManager test case failed..................."); + public void testOnRemoved() throws Exception { + testOnCreatedOrRemoved(VtnUpdateType.REMOVED); + } + + /** + * Ensure that a data change event is processed correctly. + * + *
    + *
  • + * {@link VTNInventoryManager#onDataChanged(AsyncDataChangeEvent)} + *
  • + *
  • {@link VTNInventoryManager#onCreated(Void,IdentifiedData)}
  • + *
  • {@link VTNInventoryManager#onUpdated(Void,ChangedData)}
  • + *
  • {@link VTNInventoryManager#onRemoved(Void,IdentifiedData)}
  • + *
  • {@link VTNInventoryManager#addListener(VTNInventoryListener)}
  • + *
+ * + * @throws Exception An error occurred. + */ + @Test + public void testEvent() throws Exception { + reset(vtnProvider); + final int nlisteners = 3; + VTNInventoryListener[] listeners = new VTNInventoryListener[nlisteners]; + for (int i = 0; i < nlisteners; i++) { + VTNInventoryListener l = mock(VTNInventoryListener.class); + listeners[i] = l; + inventoryManager.addListener(l); + } + + // 3 nodes have been created. + Map, DataObject> created = new HashMap<>(); + Map createdNodes = new HashMap(); + VtnOpenflowVersion[] vers = { + null, + VtnOpenflowVersion.OF10, + VtnOpenflowVersion.OF13, + }; + long dpid = 1L; + for (VtnOpenflowVersion ver: vers) { + SalNode snode = new SalNode(dpid); + VtnNode vnode = new VtnNodeBuilder(). + setId(snode.getNodeId()). + setOpenflowVersion(ver). + build(); + VtnNodeEvent nev = + new VtnNodeEvent(null, vnode, VtnUpdateType.CREATED); + assertNull(createdNodes.put(snode, nev)); + assertNull(created.put(snode.getVtnNodeIdentifier(), vnode)); + dpid++; + } + + // 2 nodes have been changed. + Map, DataObject> original = new HashMap<>(); + Map, DataObject> updated = new HashMap<>(); + SalNode snode = new SalNode(10L); + VtnNode vnodeOld = new VtnNodeBuilder(). + setId(snode.getNodeId()). + build(); + VtnNode vnode = new VtnNodeBuilder(). + setId(snode.getNodeId()). + setOpenflowVersion(VtnOpenflowVersion.OF10). + build(); + InstanceIdentifier vnPath = snode.getVtnNodeIdentifier(); + assertNull(original.put(vnPath, vnodeOld)); + assertNull(updated.put(vnPath, vnode)); + + snode = new SalNode(11L); + vnodeOld = new VtnNodeBuilder(). + setId(snode.getNodeId()). + build(); + vnode = new VtnNodeBuilder(). + setId(snode.getNodeId()). + setOpenflowVersion(VtnOpenflowVersion.OF13). + build(); + vnPath = snode.getVtnNodeIdentifier(); + assertNull(original.put(vnPath, vnodeOld)); + assertNull(updated.put(vnPath, vnode)); + + // 3 nodes have been removed. + Set> removed = new HashSet<>(); + Map removedNodes = new HashMap<>(); + dpid = 100L; + for (VtnOpenflowVersion ver: vers) { + snode = new SalNode(dpid); + vnode = new VtnNodeBuilder(). + setId(snode.getNodeId()). + setOpenflowVersion(ver). + build(); + VtnNodeEvent nev = + new VtnNodeEvent(null, vnode, VtnUpdateType.REMOVED); + vnPath = snode.getVtnNodeIdentifier(); + assertNull(removedNodes.put(snode, nev)); + assertTrue(removed.add(vnPath)); + assertNull(original.put(vnPath, vnode)); + dpid++; + } + + Map createdPorts = new HashMap<>(); + PortLink plink = new PortLinkBuilder(). + setLinkId(new LinkId("link:1")). + setPeer(new NodeConnectorId("openflow:3:4")). + build(); + List plinks = Collections.singletonList(plink); + for (long dp = 1L; dp <= 2L; dp++) { + // 2 edge ports per node are created. + for (long pnum = 1L; pnum <= 2L; pnum++) { + SalPort sport = new SalPort(dp, pnum); + VtnPort vport = new VtnPortBuilder(). + setId(sport.getNodeConnectorId()). + setName("port-" + pnum). + setEnabled(true). + setCost(1000L). + build(); + VtnPortEvent pev = new VtnPortEvent( + null, vport, Boolean.FALSE, VtnUpdateType.CREATED); + assertNull(createdPorts.put(sport, pev)); + assertNull(created.put(sport.getVtnPortIdentifier(), vport)); + } + + // 2 inter-switch link per node are created. + for (long pnum = 10L; pnum <= 11L; pnum++) { + SalPort sport = new SalPort(dp, pnum); + VtnPort vport = new VtnPortBuilder(). + setId(sport.getNodeConnectorId()). + setName("port-" + pnum). + setEnabled(true). + setPortLink(plinks). + setCost(1000L). + build(); + VtnPortEvent pev = new VtnPortEvent( + null, vport, Boolean.TRUE, VtnUpdateType.CREATED); + assertNull(createdPorts.put(sport, pev)); + assertNull(created.put(sport.getVtnPortIdentifier(), vport)); + } + } + + // 1 port has been enabled. + Map changedPorts = new HashMap<>(); + SalPort sport = new SalPort(123L, 1L); + VtnPort vportOld = new VtnPortBuilder(). + setId(sport.getNodeConnectorId()). + setName("port-1"). + setEnabled(false). + setCost(1000L). + build(); + VtnPort vport = new VtnPortBuilder(vportOld). + setEnabled(true). + build(); + VtnPortEvent pev = + new VtnPortEvent(null, vport, null, VtnUpdateType.CHANGED); + InstanceIdentifier vpPath = sport.getVtnPortIdentifier(); + assertNull(changedPorts.put(sport, pev)); + assertNull(original.put(vpPath, vportOld)); + assertNull(updated.put(vpPath, vport)); + + // 1 port has been disabled. + sport = new SalPort(-1L, 3333L); + vportOld = new VtnPortBuilder(). + setId(sport.getNodeConnectorId()). + setName("port-3333"). + setEnabled(true). + setCost(1000L). + build(); + vport = new VtnPortBuilder(vportOld). + setEnabled(false). + build(); + pev = new VtnPortEvent(null, vport, null, VtnUpdateType.CHANGED); + vpPath = sport.getVtnPortIdentifier(); + assertNull(changedPorts.put(sport, pev)); + assertNull(original.put(vpPath, vportOld)); + assertNull(updated.put(vpPath, vport)); + + // 1 port has become inter-link port. + sport = new SalPort(12345L, 6L); + vportOld = new VtnPortBuilder(). + setId(sport.getNodeConnectorId()). + setName("port-6"). + setEnabled(true). + setCost(1000L). + build(); + vport = new VtnPortBuilder(vportOld). + setPortLink(plinks). + build(); + pev = new VtnPortEvent(null, vport, Boolean.TRUE, + VtnUpdateType.CHANGED); + vpPath = sport.getVtnPortIdentifier(); + assertNull(changedPorts.put(sport, pev)); + assertNull(original.put(vpPath, vportOld)); + assertNull(updated.put(vpPath, vport)); + + // 1 port has become edge port. + sport = new SalPort(9999L, 88L); + vportOld = new VtnPortBuilder(). + setId(sport.getNodeConnectorId()). + setName("port-88"). + setEnabled(true). + setPortLink(plinks). + setCost(1000L). + build(); + vport = new VtnPortBuilder(vportOld). + setPortLink(null). + build(); + pev = new VtnPortEvent(null, vport, Boolean.FALSE, + VtnUpdateType.CHANGED); + vpPath = sport.getVtnPortIdentifier(); + assertNull(changedPorts.put(sport, pev)); + assertNull(original.put(vpPath, vportOld)); + assertNull(updated.put(vpPath, vport)); + + // 3 ports have been removed. + Map removedPorts = new HashMap<>(); + sport = new SalPort(1111L, 222L); + vport = new VtnPortBuilder(). + setId(sport.getNodeConnectorId()). + setName("port-222"). + setEnabled(true). + setPortLink(plinks). + setCost(1000L). + build(); + pev = new VtnPortEvent(null, vport, Boolean.TRUE, + VtnUpdateType.REMOVED); + vpPath = sport.getVtnPortIdentifier(); + assertNull(removedPorts.put(sport, pev)); + assertTrue(removed.add(sport.getVtnPortIdentifier())); + assertNull(original.put(vpPath, vport)); + + sport = new SalPort(45L, 678L); + vport = new VtnPortBuilder(). + setId(sport.getNodeConnectorId()). + setName("port-678"). + setEnabled(true). + setCost(1000L). + build(); + pev = new VtnPortEvent(null, vport, Boolean.FALSE, + VtnUpdateType.REMOVED); + vpPath = sport.getVtnPortIdentifier(); + assertNull(removedPorts.put(sport, pev)); + assertTrue(removed.add(sport.getVtnPortIdentifier())); + assertNull(original.put(vpPath, vport)); + + sport = new SalPort(123456789L, 3L); + vport = new VtnPortBuilder(). + setId(sport.getNodeConnectorId()). + setName("port-3"). + setEnabled(false). + setCost(10000L). + build(); + pev = new VtnPortEvent(null, vport, Boolean.FALSE, + VtnUpdateType.REMOVED); + vpPath = sport.getVtnPortIdentifier(); + assertNull(removedPorts.put(sport, pev)); + assertTrue(removed.add(sport.getVtnPortIdentifier())); + assertNull(original.put(vpPath, vport)); + + // Construct an AsyncDataChangeEvent. + AsyncDataChangeEvent, DataObject> event = + mock(AsyncDataChangeEvent.class); + when(event.getCreatedData()). + thenReturn(Collections.unmodifiableMap(created)); + when(event.getUpdatedData()). + thenReturn(Collections.unmodifiableMap(updated)); + when(event.getRemovedPaths()). + thenReturn(Collections.unmodifiableSet(removed)); + when(event.getOriginalData()). + thenReturn(Collections.unmodifiableMap(original)); + + // Notify data change event. + inventoryManager.onDataChanged(event); + + // Verify delivered events and order. + // Node creation events must come first. + ArgumentCaptor captor = + ArgumentCaptor.forClass(TxEvent.class); + int numNodeEvents = + (createdNodes.size() + removedNodes.size()) * nlisteners; + int numPortEvents = + (createdPorts.size() + changedPorts.size() + removedPorts.size()) * + nlisteners; + int numEvents = numNodeEvents + numPortEvents; + verify(vtnProvider, times(numEvents)).post(captor.capture()); + List delivered = captor.getAllValues(); + assertEquals(numEvents, delivered.size()); + Iterator it = delivered.iterator(); + Map nodeEvents = new HashMap<>(createdNodes); + for (int i = 0; i < createdNodes.size(); i++) { + TxEvent tev = it.next(); + assertTrue(tev instanceof VtnNodeEvent); + VtnNodeEvent nev = (VtnNodeEvent)tev; + snode = nev.getSalNode(); + VtnNodeEvent expected = nodeEvents.remove(snode); + assertNotNull(expected); + for (int j = 0; j < nlisteners; j++) { + if (j != 0) { + tev = it.next(); + assertTrue(tev instanceof VtnNodeEvent); + nev = (VtnNodeEvent)tev; + } + assertEquals(listeners[j], + getFieldValue(nev, VTNInventoryListener.class, + "listener")); + assertEquals(snode, nev.getSalNode()); + assertSame(expected.getVtnNode(), nev.getVtnNode()); + assertEquals(VtnUpdateType.CREATED, nev.getUpdateType()); + } + } + assertTrue(nodeEvents.isEmpty()); + + // The next must be port creation events. + Map portEvents = new HashMap<>(createdPorts); + for (int i = 0; i < createdPorts.size(); i++) { + TxEvent tev = it.next(); + assertTrue(tev instanceof VtnPortEvent); + pev = (VtnPortEvent)tev; + sport = pev.getSalPort(); + VtnPortEvent expected = portEvents.remove(sport); + assertNotNull(expected); + for (int j = 0; j < nlisteners; j++) { + if (j != 0) { + tev = it.next(); + assertTrue(tev instanceof VtnPortEvent); + pev = (VtnPortEvent)tev; + } + assertEquals(listeners[j], + getFieldValue(pev, VTNInventoryListener.class, + "listener")); + assertEquals(sport, pev.getSalPort()); + assertSame(expected.getVtnPort(), pev.getVtnPort()); + assertEquals(expected.getInterSwitchLinkChange(), + pev.getInterSwitchLinkChange()); + assertEquals(VtnUpdateType.CREATED, pev.getUpdateType()); + assertEquals(expected.isDisabled(), pev.isDisabled()); + } + } + assertTrue(portEvents.isEmpty()); + + // The next must be port update events. + portEvents = new HashMap<>(changedPorts); + for (int i = 0; i < changedPorts.size(); i++) { + TxEvent tev = it.next(); + assertTrue(tev instanceof VtnPortEvent); + pev = (VtnPortEvent)tev; + sport = pev.getSalPort(); + VtnPortEvent expected = portEvents.remove(sport); + assertNotNull(expected); + for (int j = 0; j < nlisteners; j++) { + if (j != 0) { + tev = it.next(); + assertTrue(tev instanceof VtnPortEvent); + pev = (VtnPortEvent)tev; + } + assertEquals(listeners[j], + getFieldValue(pev, VTNInventoryListener.class, + "listener")); + assertEquals(sport, pev.getSalPort()); + assertSame(expected.getVtnPort(), pev.getVtnPort()); + assertEquals(expected.getInterSwitchLinkChange(), + pev.getInterSwitchLinkChange()); + assertEquals(VtnUpdateType.CHANGED, pev.getUpdateType()); + assertEquals(expected.isDisabled(), pev.isDisabled()); + } + } + assertTrue(portEvents.isEmpty()); + + // The next must be port removal events. + portEvents = new HashMap<>(removedPorts); + for (int i = 0; i < removedPorts.size(); i++) { + TxEvent tev = it.next(); + assertTrue(tev instanceof VtnPortEvent); + pev = (VtnPortEvent)tev; + sport = pev.getSalPort(); + VtnPortEvent expected = portEvents.remove(sport); + assertNotNull(expected); + for (int j = 0; j < nlisteners; j++) { + if (j != 0) { + tev = it.next(); + assertTrue(tev instanceof VtnPortEvent); + pev = (VtnPortEvent)tev; + } + assertEquals(listeners[j], + getFieldValue(pev, VTNInventoryListener.class, + "listener")); + assertEquals(sport, pev.getSalPort()); + assertSame(expected.getVtnPort(), pev.getVtnPort()); + assertEquals(expected.getInterSwitchLinkChange(), + pev.getInterSwitchLinkChange()); + assertEquals(VtnUpdateType.REMOVED, pev.getUpdateType()); + assertEquals(true, pev.isDisabled()); + } + } + assertTrue(portEvents.isEmpty()); + + // Node removal events must come last. + nodeEvents = new HashMap<>(removedNodes); + for (int i = 0; i < removedNodes.size(); i++) { + TxEvent tev = it.next(); + assertTrue(tev instanceof VtnNodeEvent); + VtnNodeEvent nev = (VtnNodeEvent)tev; + snode = nev.getSalNode(); + VtnNodeEvent expected = nodeEvents.remove(snode); + assertNotNull(expected); + for (int j = 0; j < nlisteners; j++) { + if (j != 0) { + tev = it.next(); + assertTrue(tev instanceof VtnNodeEvent); + nev = (VtnNodeEvent)tev; + } + assertEquals(listeners[j], + getFieldValue(nev, VTNInventoryListener.class, + "listener")); + assertEquals(snode, nev.getSalNode()); + assertSame(expected.getVtnNode(), nev.getVtnNode()); + assertEquals(VtnUpdateType.REMOVED, nev.getUpdateType()); + } + } + assertTrue(nodeEvents.isEmpty()); + assertFalse(it.hasNext()); + + for (VTNInventoryListener l: listeners) { + verifyZeroInteractions(l); } } /** - * Test method for + * Test case for * {@link VTNInventoryManager#getWildcardPath()}. */ @Test public void testGetWildcardPath() { - try { - Assert.assertTrue(vtnInventoryManager.getWildcardPath() instanceof InstanceIdentifier); - } catch (Exception exception) { - Assert.fail("VTNInventoryManager test case failed..................."); - } + assertEquals(getPath(), inventoryManager.getWildcardPath()); } /** - * Test method for - * {@link VTNInventoryManager#getLogger()}. + * Test case for {@link VTNInventoryManager#getLogger()}. */ @Test public void testGetLogger() { - try { - Assert.assertTrue(vtnInventoryManager.getLogger() instanceof Logger); - } catch (Exception exception) { - Assert.fail("VTNInventoryManager test case failed..................."); + Logger logger = inventoryManager.getLogger(); + assertEquals(VTNInventoryManager.class.getName(), logger.getName()); + } + + /** + * Return a wildcard path to the MD-SAL data model to listen. + */ + private InstanceIdentifier getPath() { + return InstanceIdentifier.builder(VtnNodes.class). + child(VtnNode.class).build(); + } + + /** + * Common test for creation and removal event delivery. + * + * @param utype A {@link VtnUpdateType} instance. + * @throws Exception An error occurred. + */ + private void testOnCreatedOrRemoved(VtnUpdateType utype) throws Exception { + final int nlisteners = 3; + VTNInventoryListener[] listeners = new VTNInventoryListener[nlisteners]; + for (int i = 0; i < nlisteners; i++) { + VTNInventoryListener l = mock(VTNInventoryListener.class); + listeners[i] = l; + inventoryManager.addListener(l); + } + + // In case of node event. + SalNode snode = new SalNode(1L); + VtnNode vnode = new VtnNodeBuilder(). + setId(snode.getNodeId()). + setOpenflowVersion(VtnOpenflowVersion.OF13). + build(); + IdentifiedData ndata = + new IdentifiedData<>(snode.getVtnNodeIdentifier(), vnode); + boolean created = (utype == VtnUpdateType.CREATED); + if (created) { + inventoryManager.onCreated(null, ndata); + } else { + inventoryManager.onRemoved(null, ndata); + } + + // Verify delivered events. + ArgumentCaptor ncaptor = + ArgumentCaptor.forClass(VtnNodeEvent.class); + verify(vtnProvider, never()).post(isA(VtnPortEvent.class)); + verify(vtnProvider, times(nlisteners)).post(ncaptor.capture()); + List ndelivered = ncaptor.getAllValues(); + assertEquals(listeners.length, ndelivered.size()); + for (int i = 0; i < nlisteners; i++) { + VtnNodeEvent ev = ndelivered.get(i); + assertEquals(listeners[i], + getFieldValue(ev, VTNInventoryListener.class, + "listener")); + assertEquals(snode, ev.getSalNode()); + assertSame(vnode, ev.getVtnNode()); + assertEquals(utype, ev.getUpdateType()); + verifyZeroInteractions(listeners[i]); + } + reset(vtnProvider); + + // In case of edge port event. + SalPort esport = new SalPort(123L, 456L); + VtnPort evport = new VtnPortBuilder(). + setId(esport.getNodeConnectorId()). + setName("port-456"). + setEnabled(true). + setCost(1000L). + build(); + IdentifiedData epdata = + new IdentifiedData<>(esport.getVtnPortIdentifier(), evport); + if (created) { + inventoryManager.onCreated(null, epdata); + } else { + inventoryManager.onRemoved(null, epdata); + } + + // Verify delivered events. + ArgumentCaptor epcaptor = + ArgumentCaptor.forClass(VtnPortEvent.class); + verify(vtnProvider, never()).post(isA(VtnNodeEvent.class)); + verify(vtnProvider, times(nlisteners)).post(epcaptor.capture()); + List pdelivered = epcaptor.getAllValues(); + assertEquals(listeners.length, pdelivered.size()); + for (int i = 0; i < nlisteners; i++) { + VtnPortEvent ev = pdelivered.get(i); + assertEquals(listeners[i], + getFieldValue(ev, VTNInventoryListener.class, + "listener")); + assertEquals(esport, ev.getSalPort()); + assertSame(evport, ev.getVtnPort()); + assertEquals(Boolean.FALSE, ev.getInterSwitchLinkChange()); + assertEquals(utype, ev.getUpdateType()); + assertEquals(!created, ev.isDisabled()); + verifyZeroInteractions(listeners[i]); + } + reset(vtnProvider); + + // In case of inter-switch link port event. + SalPort isport = new SalPort(-1L, 0xffffff00L); + PortLink plink = new PortLinkBuilder(). + setLinkId(new LinkId("link:1")). + setPeer(new NodeConnectorId("openflow:3:4")). + build(); + VtnPort ivport = new VtnPortBuilder(). + setId(isport.getNodeConnectorId()). + setName("port-MAX"). + setEnabled(true). + setCost(2000L). + setPortLink(Collections.singletonList(plink)). + build(); + IdentifiedData ipdata = + new IdentifiedData<>(isport.getVtnPortIdentifier(), ivport); + if (created) { + inventoryManager.onCreated(null, ipdata); + } else { + inventoryManager.onRemoved(null, ipdata); + } + + // Verify delivered events. + ArgumentCaptor ipcaptor = + ArgumentCaptor.forClass(VtnPortEvent.class); + verify(vtnProvider, never()).post(isA(VtnNodeEvent.class)); + verify(vtnProvider, times(nlisteners)).post(ipcaptor.capture()); + pdelivered = ipcaptor.getAllValues(); + assertEquals(listeners.length, pdelivered.size()); + for (int i = 0; i < nlisteners; i++) { + VtnPortEvent ev = pdelivered.get(i); + assertEquals(listeners[i], + getFieldValue(ev, VTNInventoryListener.class, + "listener")); + assertEquals(isport, ev.getSalPort()); + assertSame(ivport, ev.getVtnPort()); + assertEquals(Boolean.TRUE, ev.getInterSwitchLinkChange()); + assertEquals(utype, ev.getUpdateType()); + assertEquals(!created, ev.isDisabled()); + verifyZeroInteractions(listeners[i]); + } + reset(vtnProvider); + + // In case of unexpected event. + InstanceIdentifier badPath = InstanceIdentifier. + builder(Nodes.class). + child(Node.class, new NodeKey(new NodeId("unknown:1"))). + build(); + Node badNode = mock(Node.class); + IdentifiedData badData = new IdentifiedData<>(badPath, badNode); + if (created) { + inventoryManager.onCreated(null, badData); + } else { + inventoryManager.onRemoved(null, badData); + } + + verifyZeroInteractions(vtnProvider); + verifyZeroInteractions(badNode); + for (VTNInventoryListener l: listeners) { + verifyZeroInteractions(l); + } + + // No events should be delivered after shutdown. + inventoryManager.shutdown(); + inventoryManager.onCreated(null, ndata); + inventoryManager.onCreated(null, epdata); + inventoryManager.onCreated(null, ipdata); + inventoryManager.onCreated(null, badData); + inventoryManager.onRemoved(null, ndata); + inventoryManager.onRemoved(null, epdata); + inventoryManager.onRemoved(null, ipdata); + inventoryManager.onRemoved(null, badData); + + verifyZeroInteractions(vtnProvider); + for (VTNInventoryListener l: listeners) { + verifyZeroInteractions(l); } } } diff --git a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/routing/VTNRoutingManagerTest.java b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/routing/VTNRoutingManagerTest.java index 126cbad6..89827c9a 100644 --- a/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/routing/VTNRoutingManagerTest.java +++ b/manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/routing/VTNRoutingManagerTest.java @@ -9,371 +9,1328 @@ package org.opendaylight.vtn.manager.internal.routing; -import org.junit.Test; -import org.slf4j.Logger; -import org.junit.Assert; -import org.mockito.Mockito; -import org.junit.AfterClass; -import org.junit.BeforeClass; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.isA; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; import java.util.Set; import java.util.concurrent.Future; -import org.slf4j.LoggerFactory; import java.util.concurrent.TimeUnit; -import com.google.common.base.Optional; -import org.opendaylight.vtn.manager.VTNException; + +import org.slf4j.Logger; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; + +import org.opendaylight.vtn.manager.internal.FlowRemover; +import org.opendaylight.vtn.manager.internal.RouteResolver; +import org.opendaylight.vtn.manager.internal.TxContext; +import org.opendaylight.vtn.manager.internal.TxTask; import org.opendaylight.vtn.manager.internal.VTNManagerProvider; +import org.opendaylight.vtn.manager.internal.flow.remove.AllFlowRemover; +import org.opendaylight.vtn.manager.internal.flow.remove.PathPolicyFlowRemover; +import org.opendaylight.vtn.manager.internal.util.ChangedData; +import org.opendaylight.vtn.manager.internal.util.CompositeAutoCloseable; +import org.opendaylight.vtn.manager.internal.util.IdentifiedData; +import org.opendaylight.vtn.manager.internal.util.concurrent.SettableVTNFuture; +import org.opendaylight.vtn.manager.internal.util.concurrent.VTNFuture; +import org.opendaylight.vtn.manager.internal.util.inventory.InventoryUtils; +import org.opendaylight.vtn.manager.internal.util.inventory.LinkEdge; +import org.opendaylight.vtn.manager.internal.util.inventory.SalNode; +import org.opendaylight.vtn.manager.internal.util.inventory.SalPort; + +import org.opendaylight.vtn.manager.internal.TestBase; + import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.vtn.manager.internal.VTNManagerImpl; -import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; -import org.opendaylight.vtn.manager.internal.RouteResolver; import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; -import org.opendaylight.yangtools.concepts.ListenerRegistration; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; -import org.opendaylight.vtn.manager.internal.util.AbstractDataChangeListener; -import com.google.common.util.concurrent.CheckedFuture; -import org.opendaylight.vtn.manager.internal.util.concurrent.VTNFuture; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration; import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; -import org.opendaylight.vtn.manager.internal.util.CompositeAutoCloseable; -import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.pathpolicy.rev150209.SetPathPolicyInput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.pathpolicy.rev150209.SetPathPolicyInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.types.rev150209.VtnUpdateOperationType; + +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.Notification; +import org.opendaylight.yangtools.yang.common.RpcResult; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.topology.rev150209.RoutingUpdated; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.topology.rev150209.RoutingUpdatedBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.topology.rev150209.VtnTopology; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.topology.rev150209.VtnTopologyBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.topology.rev150209.routing.updated.AddedLink; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.topology.rev150209.routing.updated.AddedLinkBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.topology.rev150209.routing.updated.RemovedLink; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.topology.rev150209.routing.updated.RemovedLinkBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.topology.rev150209.vtn.topology.VtnLink; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.topology.rev150209.vtn.topology.VtnLinkBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.pathpolicy.rev150209.ClearPathPolicyOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.pathpolicy.rev150209.RemovePathCostInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.pathpolicy.rev150209.RemovePathCostInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.pathpolicy.rev150209.RemovePathCostOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.pathpolicy.rev150209.RemovePathPolicyInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.pathpolicy.rev150209.RemovePathPolicyInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.pathpolicy.rev150209.SetPathCostInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.pathpolicy.rev150209.SetPathCostInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.pathpolicy.rev150209.RemovePathCostInput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.pathpolicy.rev150209.RemovePathCostInputBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.pathpolicy.rev150209.ClearPathPolicyOutput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.topology.rev150209.VtnTopology; -import org.opendaylight.yangtools.yang.common.RpcResult; -import org.opendaylight.vtn.manager.internal.util.IdentifiedData; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.pathpolicy.rev150209.SetPathCostOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.pathpolicy.rev150209.SetPathPolicyInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.pathpolicy.rev150209.SetPathPolicyInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.pathpolicy.rev150209.SetPathPolicyOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.pathpolicy.rev150209.VtnPathPolicies; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.pathpolicy.rev150209.VtnPathPoliciesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.pathpolicy.rev150209.VtnPathPolicyService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.pathpolicy.rev150209.remove.path.cost.output.RemovePathCostResult; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.pathpolicy.rev150209.remove.path.cost.output.RemovePathCostResultBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.pathpolicy.rev150209.set.path.cost.input.PathCostList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.pathpolicy.rev150209.set.path.cost.input.PathCostListBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.pathpolicy.rev150209.set.path.cost.output.SetPathCostResult; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.pathpolicy.rev150209.set.path.cost.output.SetPathCostResultBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.pathpolicy.rev150209.vtn.path.policies.VtnPathPolicy; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.pathpolicy.rev150209.vtn.path.policies.VtnPathPolicyBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.types.rev150209.VtnPortDesc; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.types.rev150209.VtnUpdateOperationType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.types.rev150209.VtnUpdateType; + +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.LinkId; /** * JUnit test for {@link VTNRoutingManager}. */ -public class VTNRoutingManagerTest { - /** - * Static instance of VTNRoutingManager to perform unit testing. - */ - private static VTNRoutingManager vtnRoutingManager; - /** - * Static instance of VTNManagerProvider to perform unit testing. - */ - private static VTNManagerProvider vtnManagerProvider; - /** - * Static instance of VTNRoutingListener to perform unit testing. - */ - private static VTNRoutingListener vtnRoutingListener; - /** - * Static instance of DataBroker to perform unit testing. - */ - private static DataBroker dataBroker; - - /** - * This method creates the requird objects to perform unit testing - */ - @BeforeClass - public static void setUpBeforeClass() { - try { - vtnManagerProvider = Mockito.mock(VTNManagerProvider.class); - dataBroker = Mockito.mock(DataBroker.class); - ReadOnlyTransaction readOnlyTransaction = Mockito.mock(ReadOnlyTransaction.class); - CheckedFuture checkedFuture = Mockito.mock(CheckedFuture.class); - Optional optional = Mockito.mock(Optional.class); - VtnTopology vtnTopology = Mockito.mock(VtnTopology.class); - Mockito.when(optional.orNull()).thenReturn(vtnTopology); - Mockito.when(checkedFuture.checkedGet(Mockito.anyLong(), Mockito.eq(TimeUnit.SECONDS))).thenReturn(optional); - Mockito.when(readOnlyTransaction.read(Mockito.isA(LogicalDatastoreType.class), Mockito.isA(InstanceIdentifier.class))).thenReturn(checkedFuture); - Mockito.when(dataBroker.newReadOnlyTransaction()).thenReturn(readOnlyTransaction); - Mockito.when(dataBroker.registerDataChangeListener(Mockito.isA(LogicalDatastoreType.class), Mockito.isA(InstanceIdentifier.class) - , Mockito.isA(AbstractDataChangeListener.class), Mockito.isA(DataChangeScope.class))).thenReturn(Mockito.mock(ListenerRegistration.class)); - Mockito.when(vtnManagerProvider.getDataBroker()).thenReturn(dataBroker); - vtnRoutingManager = new VTNRoutingManager(vtnManagerProvider); - vtnRoutingListener = new VTNManagerImpl(); - } catch (Exception exception) { - Assert.fail("VTNRoutingManager test case failed..................."); - } - //To test negative scenario - try { - VTNManagerProvider vtnManagerProvider2 = Mockito.mock(VTNManagerProvider.class); - DataBroker dataBroker2 = Mockito.mock(DataBroker.class); - ReadOnlyTransaction readOnlyTransaction2 = Mockito.mock(ReadOnlyTransaction.class); - CheckedFuture checkedFuture2 = Mockito.mock(CheckedFuture.class); - Optional optional2 = Mockito.mock(Optional.class); - Mockito.when(optional2.orNull()).thenThrow(new NullPointerException()); - Mockito.when(checkedFuture2.checkedGet(Mockito.anyLong(), Mockito.eq(TimeUnit.SECONDS))).thenReturn(optional2); - Mockito.when(readOnlyTransaction2.read(Mockito.isA(LogicalDatastoreType.class), Mockito.isA(InstanceIdentifier.class))).thenReturn(checkedFuture2); - Mockito.when(dataBroker2.newReadOnlyTransaction()).thenReturn(readOnlyTransaction2); - Mockito.when(dataBroker2.registerDataChangeListener(Mockito.isA(LogicalDatastoreType.class), Mockito.isA(InstanceIdentifier.class) - , Mockito.isA(AbstractDataChangeListener.class), Mockito.isA(DataChangeScope.class))).thenReturn(Mockito.mock(ListenerRegistration.class)); - Mockito.when(vtnManagerProvider2.getDataBroker()).thenReturn(dataBroker2); - VTNRoutingManager vtnRoutingManager2 = new VTNRoutingManager(vtnManagerProvider2); - } catch (Exception exception) { - Assert.assertTrue(exception instanceof IllegalStateException); - } - //To test negative scenario - try { - VTNManagerProvider vtnManagerProvider3 = Mockito.mock(VTNManagerProvider.class); - DataBroker dataBroker3 = Mockito.mock(DataBroker.class); - ReadOnlyTransaction readOnlyTransaction3 = Mockito.mock(ReadOnlyTransaction.class); - CheckedFuture checkedFuture3 = Mockito.mock(CheckedFuture.class); - Optional optional3 = Mockito.mock(Optional.class); - Mockito.when(optional3.orNull()).thenReturn(null); - Mockito.when(checkedFuture3.checkedGet(Mockito.anyLong(), Mockito.eq(TimeUnit.SECONDS))).thenReturn(optional3); - Mockito.when(readOnlyTransaction3.read(Mockito.isA(LogicalDatastoreType.class), Mockito.isA(InstanceIdentifier.class))).thenReturn(checkedFuture3); - Mockito.when(dataBroker3.newReadOnlyTransaction()).thenReturn(readOnlyTransaction3); - Mockito.when(dataBroker3.registerDataChangeListener(Mockito.isA(LogicalDatastoreType.class), Mockito.isA(InstanceIdentifier.class) - , Mockito.isA(AbstractDataChangeListener.class), Mockito.isA(DataChangeScope.class))).thenThrow(new RuntimeException()); - Mockito.when(vtnManagerProvider3.getDataBroker()).thenReturn(dataBroker3); - VTNRoutingManager vtnRoutingManager3 = new VTNRoutingManager(vtnManagerProvider3); - } catch (Exception exception) { - Assert.assertTrue(exception instanceof IllegalStateException); - } +public class VTNRoutingManagerTest extends TestBase { + /** + * Mock-up of {@link VTNManagerProvider}. + */ + @Mock + private VTNManagerProvider vtnProvider; + + /** + * Mock-up of {@link DataBroker}. + */ + @Mock + private DataBroker dataBroker; + + /** + * Mock-up of {@link ReadOnlyTransaction} to be associated with + * {@link #dataBroker}. + */ + @Mock + private ReadOnlyTransaction roTransaction; + + /** + * Registration to be associated with {@link PathPolicyListener}. + */ + @Mock + private ListenerRegistration ppListenerReg; + + /** + * Registration to be associated with {@link VTNRoutingManager}. + */ + @Mock + private ListenerRegistration routingListenerReg; + + /** + * A {@link VtnTopology} instance which contains the initial network + * topology. + */ + private VtnTopology initialTopology; + + /** + * A {@link VTNRoutingManager} instance for test. + */ + private VTNRoutingManager routingManager; + + /** + * Set up test environment. + */ + @Before + public void setUp() { + initMocks(this); + + when(vtnProvider.getDataBroker()).thenReturn(dataBroker); + when(dataBroker.newReadOnlyTransaction()).thenReturn(roTransaction); + + InstanceIdentifier topoPath = + InstanceIdentifier.create(VtnTopology.class); + LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL; + when(roTransaction.read(oper, topoPath)). + thenReturn(getReadResult(initialTopology)); + + when(dataBroker.registerDataChangeListener( + any(LogicalDatastoreType.class), any(InstanceIdentifier.class), + isA(PathPolicyListener.class), any(DataChangeScope.class))). + thenReturn(ppListenerReg); + + when(dataBroker.registerDataChangeListener( + any(LogicalDatastoreType.class), any(InstanceIdentifier.class), + isA(VTNRoutingManager.class), any(DataChangeScope.class))). + thenReturn(routingListenerReg); + + routingManager = new VTNRoutingManager(vtnProvider); } /** - * This method makes unnecessary objects eligible for garbage collection + * Tear down test environment. */ - @AfterClass - public static void tearDownAfterClass() { - vtnRoutingManager = null; - vtnManagerProvider = null; - vtnRoutingListener = null; - dataBroker = null; + @After + public void tearDown() { + initialTopology = null; } /** - * Test method for - * {@link VTNRoutingManager#addListener(VTNRoutingListener)}. + * Test case for + * {@link VTNRoutingManager#VTNRoutingManager(VTNManagerProvider)}. + * + * @throws Exception An error occurred. */ @Test - public void testAddListener() { - try { - vtnRoutingManager.addListener(vtnRoutingListener); - } catch (Exception exception) { - Assert.fail("VTNRoutingManager test case failed..................."); + public void testConstructor() throws Exception { + verifyRoutingManager(); + + // Ensure that the topology graph is empty. + TopologyGraph topo = getTopologyGraph(routingManager); + Set nodes = new HashSet<>(); + assertTrue(topo.getVertices().isEmpty()); + + // Ensure that the topology graph is initialized if the network + // topology is not empty. + SalNode snode1 = new SalNode(1L); + SalNode snode2 = new SalNode(2L); + SalNode snode3 = new SalNode(3L); + Collections.addAll(nodes, snode1, snode2, snode3); + + // openflow:1:1 <-> openflow:2:1 + List vlinks = new ArrayList<>(); + createVtnLink(vlinks, snode1, 1L, snode2, 1L); + + // openflow:1:2 <-> openflow:3:1 + createVtnLink(vlinks, snode1, 2L, snode3, 1L); + initialTopology = new VtnTopologyBuilder().setVtnLink(vlinks).build(); + setUp(); + verifyRoutingManager(); + + topo = getTopologyGraph(routingManager); + Collection verts = topo.getVertices(); + assertEquals(nodes.size(), verts.size()); + for (SalNode snode: verts) { + assertEquals(true, nodes.contains(snode)); + } + + SalPort sport11 = new SalPort(1L, 1L); + SalPort sport12 = new SalPort(1L, 2L); + SalPort sport21 = new SalPort(2L, 1L); + SalPort sport31 = new SalPort(3L, 1L); + + // openflow:1:1 -> openflow:2:1 + checkRoute(snode1, snode2, sport11, sport21); + + // openflow:2:1 -> openflow:1:1 + checkRoute(snode2, snode1, sport21, sport11); + + // openflow:1:2 -> openflow:3:1 + checkRoute(snode1, snode3, sport12, sport31); + + // openflow:3:1 -> openflow:1:2 + checkRoute(snode3, snode1, sport31, sport12); + + // openflow:2:1 -> openflow:1:1, openflow:1:2 -> openflow:3:1 + checkRoute(snode2, snode3, sport21, sport11, sport12, sport31); + + // openflow:3:1 -> openflow:1:2, openflow:1:1 -> openflow:2:1 + checkRoute(snode3, snode2, sport31, sport12, sport11, sport21); + + // In case of unknown node. + RouteResolver rr = routingManager.getRouteResolver(0); + for (long dpid = 10L; dpid <= 20L; dpid++) { + SalNode snode = new SalNode(dpid); + assertEquals(null, rr.getRoute(null, snode, snode1)); + assertEquals(null, rr.getRoute(null, snode, snode2)); + assertEquals(null, rr.getRoute(null, snode, snode3)); + assertEquals(null, rr.getRoute(null, snode1, snode)); + assertEquals(null, rr.getRoute(null, snode2, snode)); + assertEquals(null, rr.getRoute(null, snode3, snode)); } } /** - * Test method for - * {@link VTNRoutingManager#getRouteResolver(Integer)}. + * Test case for {@link VTNRoutingManager#addListener(VTNRoutingListener)}. + * + * @throws Exception An error occurred. */ @Test - public void testGetRouteResolver() { - Assert.assertTrue(vtnRoutingManager.getRouteResolver(0) instanceof RouteResolver); + public void testAddListener() throws Exception { + List expected = new ArrayList<>(); + for (int i = 0; i < 10; i++) { + VTNRoutingListener l = mock(VTNRoutingListener.class); + expected.add(l); + routingManager.addListener(l); + + List listeners = + getFieldValue(routingManager, List.class, "vtnListeners"); + assertEquals(expected, listeners); + } + + // Below calls should do nothing because listeners are already added. + for (VTNRoutingListener l: expected) { + routingManager.addListener(l); + List listeners = + getFieldValue(routingManager, List.class, "vtnListeners"); + assertEquals(expected, listeners); + } } /** - * Test method for - * {@link VTNRoutingManager#close()}. + * Test case for {@link VTNRoutingManager#getRouteResolver(Integer)}. + * + * @throws Exception An error occurred. */ @Test - public void testClose() { - try { - vtnRoutingManager.close(); - } catch (Exception exception) { - Assert.fail("VTNRoutingManager test case failed..................."); + public void testGetRouteResolver() throws Exception { + RouteResolver res0 = routingManager.getRouteResolver(0); + assertNotNull(res0); + assertEquals(0, res0.getPathPolicyId()); + + TopologyGraph topo = getTopologyGraph(routingManager); + for (int i = 1; i <= 3; i++) { + assertEquals(null, routingManager.getRouteResolver(i)); + topo.updateResolver(i); + RouteResolver rr = routingManager.getRouteResolver(i); + assertNotNull(rr); + assertEquals(i, rr.getPathPolicyId()); } + + for (int i = 1; i <= 3; i++) { + RouteResolver rr = routingManager.getRouteResolver(i); + assertNotNull(rr); + assertEquals(i, rr.getPathPolicyId()); + topo.removeResolver(i); + assertEquals(null, routingManager.getRouteResolver(i)); + } + + assertSame(res0, routingManager.getRouteResolver(0)); + assertEquals(null, routingManager.getRouteResolver(null)); } /** - * Test method for + * Test case for {@link VTNRoutingManager#close()}. + * + * @throws Exception An error occurred. + */ + @Test + public void testClose() throws Exception { + List expected = new ArrayList<>(); + for (int i = 0; i < 10; i++) { + VTNRoutingListener l = mock(VTNRoutingListener.class); + expected.add(l); + routingManager.addListener(l); + } + + List listeners = + getFieldValue(routingManager, List.class, "vtnListeners"); + assertEquals(expected, listeners); + + verifyZeroInteractions(ppListenerReg); + verifyZeroInteractions(routingListenerReg); + + // Listener registrations should be closed only once. + expected = Collections.emptyList(); + for (int i = 0; i < 10; i++) { + routingManager.close(); + listeners = + getFieldValue(routingManager, List.class, "vtnListeners"); + assertEquals(expected, listeners); + verify(ppListenerReg).close(); + verify(routingListenerReg).close(); + } + } + + /** + * Test case for * {@link VTNRoutingManager#enterEvent(AsyncDataChangeEvent)}. */ @Test public void testEnterEvent() { - Assert.assertTrue(vtnRoutingManager.enterEvent(Mockito.mock(AsyncDataChangeEvent.class)) instanceof TopologyEventContext); + AsyncDataChangeEvent ev = null; + TopologyEventContext ectx = routingManager.enterEvent(ev); + assertNotNull(ectx); + assertEquals(0, ectx.getCreated().size()); + assertEquals(0, ectx.getRemoved().size()); } /** - * Test method for - * {@link VTNRoutingManager#exitEvent(TopologyEventContext)}. + * Test case for {@link VTNRoutingManager#exitEvent(TopologyEventContext)}. + * + * @throws Exception An error occurred. */ @Test - public void testExitEvent() { - try { - TopologyEventContext topologyEventContext = new TopologyEventContext(); - vtnRoutingManager.exitEvent(topologyEventContext); - } catch (Exception exception) { - Assert.fail("VTNRoutingManager test case failed..................."); + public void testExitEvent() throws Exception { + final int nlisteners = 3; + VTNRoutingListener[] listeners = new VTNRoutingListener[nlisteners]; + for (int i = 0; i < nlisteners; i++) { + VTNRoutingListener l = mock(VTNRoutingListener.class); + listeners[i] = l; + routingManager.addListener(l); + } + + // In case where topology was not changed. + reset(vtnProvider); + TopologyEventContext ectx = new TopologyEventContext(); + routingManager.exitEvent(ectx); + verify(vtnProvider, never()).post(any(TxTask.class)); + verify(vtnProvider, never()).publish(any(Notification.class)); + for (VTNRoutingListener l: listeners) { + verifyZeroInteractions(l); + } + + // In case where 2 links were added. + TopologyGraph topo = getTopologyGraph(routingManager); + assertTrue(topo.getVertices().isEmpty()); + SalNode snode1 = new SalNode(1L); + SalNode snode2 = new SalNode(2L); + Set nodes = new HashSet<>(); + Collections.addAll(nodes, snode1, snode2); + + List vlinks = new ArrayList<>(); + createVtnLink(vlinks, snode1, 1L, snode2, 1L); + + List addedLinks = new ArrayList<>(); + for (VtnLink vlink: vlinks) { + ectx.addCreated(vlink); + addedLinks.add(new AddedLinkBuilder(vlink).build()); + } + RoutingUpdated updated = new RoutingUpdatedBuilder(). + setAddedLink(addedLinks). + setRemovedLink(Collections.emptyList()). + build(); + routingManager.exitEvent(ectx); + verify(vtnProvider).publish(updated); + verify(vtnProvider, times(nlisteners)).post(any(TxTask.class)); + ArgumentCaptor captor = + ArgumentCaptor.forClass(RoutingEvent.class); + verify(vtnProvider, times(nlisteners)).post(captor.capture()); + List delivered = captor.getAllValues(); + assertEquals(nlisteners, delivered.size()); + for (int i = 0; i < nlisteners; i++) { + RoutingEvent ev = delivered.get(i); + assertEquals(listeners[i], + getFieldValue(ev, VTNRoutingListener.class, + "listener")); + verifyZeroInteractions(listeners[i]); + } + + Collection verts = topo.getVertices(); + assertEquals(nodes.size(), verts.size()); + for (SalNode snode: verts) { + assertEquals(true, nodes.contains(snode)); + } + + // openflow:1:1 -> openflow:2:1 + SalPort sport11 = new SalPort(1L, 1L); + SalPort sport21 = new SalPort(2L, 1L); + checkRoute(snode1, snode2, sport11, sport21); + + // openflow:2:1 -> openflow:1:1 + checkRoute(snode2, snode1, sport21, sport11); + + // In case where the link from openflow:1:1 to openflow:2:1 was + // removed. + reset(vtnProvider); + VtnLink vlink = new VtnLinkBuilder(). + setLinkId(new LinkId(sport11.toString())). + setSource(sport11.getNodeConnectorId()). + setDestination(sport21.getNodeConnectorId()). + build(); + List removedLinks = + Collections.singletonList(new RemovedLinkBuilder(vlink).build()); + updated = new RoutingUpdatedBuilder(). + setAddedLink(Collections.emptyList()). + setRemovedLink(removedLinks). + build(); + ectx = new TopologyEventContext(); + ectx.addRemoved(vlink); + routingManager.exitEvent(ectx); + verify(vtnProvider).publish(updated); + verify(vtnProvider, times(nlisteners)).post(any(TxTask.class)); + captor = ArgumentCaptor.forClass(RoutingEvent.class); + verify(vtnProvider, times(nlisteners)).post(captor.capture()); + delivered = captor.getAllValues(); + assertEquals(nlisteners, delivered.size()); + for (int i = 0; i < nlisteners; i++) { + RoutingEvent ev = delivered.get(i); + assertEquals(listeners[i], + getFieldValue(ev, VTNRoutingListener.class, + "listener")); + verifyZeroInteractions(listeners[i]); + } + + verts = topo.getVertices(); + assertEquals(nodes.size(), verts.size()); + for (SalNode snode: verts) { + assertEquals(true, nodes.contains(snode)); } + + // openflow:1:1 -> openflow:2:1 + checkRoute(snode1, snode2); + + // openflow:2:1 -> openflow:1:1 + checkRoute(snode2, snode1, sport21, sport11); } /** - * Test method for + * Test case for * {@link VTNRoutingManager#onCreated(TopologyEventContext,IdentifiedData)}. */ @Test public void testOnCreated() { - try { - TopologyEventContext topologyEventContext = new TopologyEventContext(); - IdentifiedData identifiedData = Mockito.mock(IdentifiedData.class); - vtnRoutingManager.onCreated(topologyEventContext, identifiedData); - } catch (Exception exception) { - Assert.fail("VTNRoutingManager test case failed..................."); + TopologyEventContext ectx = new TopologyEventContext(); + List expected = new ArrayList<>(); + List empty = Collections.emptyList(); + for (long l = 0; l <= 10; l++) { + assertEquals(expected, ectx.getCreated()); + assertEquals(empty, ectx.getRemoved()); + + SalPort src = new SalPort(1L + l, 2L + l); + SalPort dst = new SalPort(10L + l, 20L + l); + VtnLink vlink = new VtnLinkBuilder(). + setLinkId(new LinkId(src.toString())). + setSource(src.getNodeConnectorId()). + setDestination(dst.getNodeConnectorId()). + build(); + expected.add(vlink); + InstanceIdentifier path = + InventoryUtils.toVtnLinkIdentifier(vlink.getLinkId()); + IdentifiedData data = new IdentifiedData<>(path, vlink); + routingManager.onCreated(ectx, data); + + assertEquals(expected, ectx.getCreated()); + assertEquals(empty, ectx.getRemoved()); } } /** - * Test method for + * Test case for * {@link VTNRoutingManager#onUpdated(TopologyEventContext,ChangedData)}. */ @Test public void testOnUpdated() { - try { - vtnRoutingManager.onUpdated(new TopologyEventContext(), null); - } catch (Exception exception) { - Assert.assertTrue(exception instanceof IllegalStateException); + TopologyEventContext ectx = new TopologyEventContext(); + List empty = Collections.emptyList(); + for (long l = 0; l <= 10; l++) { + assertEquals(empty, ectx.getCreated()); + assertEquals(empty, ectx.getRemoved()); + + SalPort src = new SalPort(1L + l, 2L + l); + SalPort dst1 = new SalPort(10L + l, 20L + l); + SalPort dst2 = new SalPort(10L + l, 21L + l); + VtnLink vlinkOld = new VtnLinkBuilder(). + setLinkId(new LinkId(src.toString())). + setSource(src.getNodeConnectorId()). + setDestination(dst1.getNodeConnectorId()). + build(); + VtnLink vlink = new VtnLinkBuilder(). + setLinkId(vlinkOld.getLinkId()). + setSource(src.getNodeConnectorId()). + setDestination(dst2.getNodeConnectorId()). + build(); + InstanceIdentifier path = + InventoryUtils.toVtnLinkIdentifier(vlink.getLinkId()); + ChangedData data = + new ChangedData<>(path, vlink, vlinkOld); + try { + routingManager.onUpdated(ectx, data); + unexpected(); + } catch (IllegalStateException e) { + } } } /** - * Test method for + * Test case for * {@link VTNRoutingManager#onRemoved(TopologyEventContext,IdentifiedData)}. */ @Test public void testOnRemoved() { - try { - TopologyEventContext topologyEventContext = new TopologyEventContext(); - IdentifiedData identifiedData = Mockito.mock(IdentifiedData.class); - vtnRoutingManager.onRemoved(topologyEventContext, identifiedData); - } catch (Exception exception) { - Assert.fail("VTNRoutingManager test case failed..................."); + TopologyEventContext ectx = new TopologyEventContext(); + List expected = new ArrayList<>(); + List empty = Collections.emptyList(); + for (long l = 0; l <= 10; l++) { + assertEquals(empty, ectx.getCreated()); + assertEquals(expected, ectx.getRemoved()); + + SalPort src = new SalPort(1L + l, 2L + l); + SalPort dst = new SalPort(10L + l, 20L + l); + VtnLink vlink = new VtnLinkBuilder(). + setLinkId(new LinkId(src.toString())). + setSource(src.getNodeConnectorId()). + setDestination(dst.getNodeConnectorId()). + build(); + expected.add(vlink); + InstanceIdentifier path = + InventoryUtils.toVtnLinkIdentifier(vlink.getLinkId()); + IdentifiedData data = new IdentifiedData<>(path, vlink); + routingManager.onRemoved(ectx, data); + + assertEquals(empty, ectx.getCreated()); + assertEquals(expected, ectx.getRemoved()); + } + } + + /** + * Ensure that a data change event is processed correctly. + * + *
    + *
  • + * {@link VTNRoutingManager#onDataChanged(AsyncDataChangeEvent)} + *
  • + *
  • + * {@link VTNRoutingManager#onCreated(TopologyEventContext,IdentifiedData)} + *
  • + *
  • + * {@link VTNRoutingManager#onRemoved(TopologyEventContext,IdentifiedData)} + *
  • + *
  • {@link VTNRoutingManager#addListener(VTNRoutingListener)}
  • + *
+ * + * @throws Exception An error occurred. + */ + @Test + public void testEvent() throws Exception { + reset(vtnProvider); + final int nlisteners = 3; + VTNRoutingListener[] listeners = new VTNRoutingListener[nlisteners]; + for (int i = 0; i < nlisteners; i++) { + VTNRoutingListener l = mock(VTNRoutingListener.class); + listeners[i] = l; + routingManager.addListener(l); + } + + // Set up initial topology. + SalNode snode1 = new SalNode(1L); + SalNode snode2 = new SalNode(2L); + SalNode snode3 = new SalNode(3L); + Set nodes = new HashSet<>(); + Collections.addAll(nodes, snode1, snode2, snode3); + + // openflow:1:1 <-> openflow:2:1 + List vlinks = new ArrayList<>(); + createVtnLink(vlinks, snode1, 1L, snode2, 1L); + + // openflow:1:2 <-> openflow:3:1 + List deleted = new ArrayList<>(); + createVtnLink(deleted, snode1, 2L, snode3, 1L); + vlinks.addAll(deleted); + + TopologyGraph topo = getTopologyGraph(routingManager); + assertEquals(true, + topo.update(vlinks, Collections.emptyList())); + Collection verts = topo.getVertices(); + assertEquals(nodes.size(), verts.size()); + for (SalNode snode: verts) { + assertEquals(true, nodes.contains(snode)); + } + + // Verify initial topology. + SalPort sport11 = new SalPort(1L, 1L); + SalPort sport12 = new SalPort(1L, 2L); + SalPort sport21 = new SalPort(2L, 1L); + SalPort sport31 = new SalPort(3L, 1L); + checkRoute(snode1, snode2, sport11, sport21); + checkRoute(snode2, snode1, sport21, sport11); + checkRoute(snode1, snode3, sport12, sport31); + checkRoute(snode3, snode1, sport31, sport12); + checkRoute(snode2, snode3, sport21, sport11, sport12, sport31); + checkRoute(snode3, snode2, sport31, sport12, sport11, sport21); + + // Create links between openflow:4 and openflow:2. + Map, DataObject> created = new HashMap<>(); + List added = new ArrayList<>(); + List addedLinks = new ArrayList<>(); + Set addedSet = new HashSet<>(); + SalNode snode4 = new SalNode(4L); + createVtnLink(added, snode2, 2L, snode4, 1L); + for (VtnLink vlink: added) { + InstanceIdentifier path = + InventoryUtils.toVtnLinkIdentifier(vlink.getLinkId()); + assertEquals(null, created.put(path, vlink)); + AddedLink al = new AddedLinkBuilder(vlink).build(); + addedLinks.add(al); + assertEquals(true, addedSet.add(al)); + } + + // Remove links between openflow:1 and openflow:3. + Map, DataObject> original = new HashMap<>(); + Set> removed = new HashSet<>(); + List removedLinks = new ArrayList<>(); + Set removedSet = new HashSet<>(); + for (VtnLink vlink: deleted) { + InstanceIdentifier path = + InventoryUtils.toVtnLinkIdentifier(vlink.getLinkId()); + assertEquals(true, removed.add(path)); + assertEquals(null, original.put(path, vlink)); + RemovedLink rl = new RemovedLinkBuilder(vlink).build(); + removedLinks.add(rl); + assertEquals(true, removedSet.add(rl)); + } + + // Create updated data to be ignored. + List ignored = new ArrayList<>(); + SalNode snode100 = new SalNode(100L); + SalNode snode101 = new SalNode(101L); + createVtnLink(ignored, snode100, 1L, snode101, 1L); + Map, DataObject> updated = new HashMap<>(); + for (VtnLink vlink: ignored) { + InstanceIdentifier path = + InventoryUtils.toVtnLinkIdentifier(vlink.getLinkId()); + VtnLink old = new VtnLinkBuilder(). + setLinkId(vlink.getLinkId()).build(); + assertEquals(null, original.put(path, old)); + assertEquals(null, updated.put(path, vlink)); + } + + // Construct an AsyncDataChangeEvent. + AsyncDataChangeEvent, DataObject> event = + mock(AsyncDataChangeEvent.class); + when(event.getCreatedData()). + thenReturn(Collections.unmodifiableMap(created)); + when(event.getUpdatedData()). + thenReturn(Collections.unmodifiableMap(updated)); + when(event.getRemovedPaths()). + thenReturn(Collections.unmodifiableSet(removed)); + when(event.getOriginalData()). + thenReturn(Collections.unmodifiableMap(original)); + + // Notify data change event. + routingManager.onDataChanged(event); + + // Verify MD-SAL notification. + verify(vtnProvider).publish(any(Notification.class)); + ArgumentCaptor ncaptor = + ArgumentCaptor.forClass(RoutingUpdated.class); + verify(vtnProvider).publish(ncaptor.capture()); + List notifications = ncaptor.getAllValues(); + assertEquals(1, notifications.size()); + RoutingUpdated ru = notifications.get(0); + for (AddedLink al: ru.getAddedLink()) { + assertEquals(true, addedSet.remove(al)); + } + for (RemovedLink rl: ru.getRemovedLink()) { + assertEquals(true, removedSet.remove(rl)); + } + assertEquals(true, addedSet.isEmpty()); + assertEquals(true, removedSet.isEmpty()); + + // Verify routing events are delivered to listeners. + verify(vtnProvider, times(nlisteners)).post(any(TxTask.class)); + ArgumentCaptor ecaptor = + ArgumentCaptor.forClass(RoutingEvent.class); + verify(vtnProvider, times(nlisteners)).post(ecaptor.capture()); + List delivered = ecaptor.getAllValues(); + assertEquals(nlisteners, delivered.size()); + for (int i = 0; i < nlisteners; i++) { + RoutingEvent ev = delivered.get(i); + assertEquals(listeners[i], + getFieldValue(ev, VTNRoutingListener.class, + "listener")); + verifyZeroInteractions(listeners[i]); + } + + // openflow:3 should be removed from the topology, and openflow:4 + // should be added to the topology. + assertEquals(true, nodes.remove(snode3)); + assertEquals(true, nodes.add(snode4)); + verts = topo.getVertices(); + assertEquals(nodes.size(), verts.size()); + for (SalNode snode: verts) { + assertEquals(true, nodes.contains(snode)); + + // openflow:3 should be unreachable. + checkRoute(snode, snode3); + checkRoute(snode3, snode); } + + // Links between openflow:1 and openflow2 should be still active. + checkRoute(snode1, snode2, sport11, sport21); + checkRoute(snode2, snode1, sport21, sport11); + + // openflow:4 should be reachable. + SalPort sport22 = new SalPort(2L, 2L); + SalPort sport41 = new SalPort(4L, 1L); + checkRoute(snode2, snode4, sport22, sport41); + checkRoute(snode4, snode2, sport41, sport22); + checkRoute(snode1, snode4, sport11, sport21, sport22, sport41); + checkRoute(snode4, snode1, sport41, sport22, sport21, sport11); } /** - * Test method for - * {@link VTNRoutingManager#getWildcardPath()}. + * Test case for {@link VTNRoutingManager#getWildcardPath()}. */ @Test public void testGetWildcardPath() { - Assert.assertTrue(vtnRoutingManager.getWildcardPath() instanceof InstanceIdentifier); + assertEquals(getPath(), routingManager.getWildcardPath()); } /** - * Test method for - * {@link VTNRoutingManager#getRequiredEvents()}. + * Test case for {@link VTNRoutingManager#getRequiredEvents()}. */ @Test public void testGetRequiredEvents() { - try { - Assert.assertTrue(vtnRoutingManager.getRequiredEvents() instanceof Set); - } catch (Exception exception) { - Assert.fail("VTNRoutingManager test case failed..................."); - } + Set events = routingManager.getRequiredEvents(); + assertEquals(2, events.size()); + assertEquals(true, events.contains(VtnUpdateType.CREATED)); + assertEquals(true, events.contains(VtnUpdateType.REMOVED)); } /** - * Test method for - * {@link VTNRoutingManager#getLogger()}. + * Test case for {@link VTNRoutingManager#getLogger()}. */ @Test public void testGetLogger() { - Assert.assertTrue(vtnRoutingManager.getLogger() instanceof Logger); + Logger logger = routingManager.getLogger(); + assertEquals(VTNRoutingManager.class.getName(), logger.getName()); } /** - * Test method for - * {@link VTNRoutingManager#initConfig(boolean)}. + * Test case for {@link VTNRoutingManager#initConfig(boolean)}. */ @Test public void testInitConfig() { - try { - VTNFuture vtnFuture = vtnRoutingManager.initConfig(true); - vtnFuture = vtnRoutingManager.initConfig(true); - } catch (Exception exception) { - Assert.fail("VTNRoutingManager test case failed..................."); + Map cases = new HashMap<>(); + String baseName = PathPolicyListener.class.getName(); + cases.put(true, baseName + ".PathPolicyLoadTask"); + cases.put(false, baseName + ".PathPolicySaveTask"); + for (Map.Entry entry: cases.entrySet()) { + reset(vtnProvider); + boolean master = entry.getKey().booleanValue(); + VTNFuture future = mock(VTNFuture.class); + when(vtnProvider.post(any(TxTask.class))).thenReturn(future); + assertEquals(future, routingManager.initConfig(master)); + ArgumentCaptor captor = + ArgumentCaptor.forClass(TxTask.class); + verify(vtnProvider).post(captor.capture()); + List tasks = captor.getAllValues(); + assertEquals(1, tasks.size()); + TxTask task = tasks.get(0); + assertEquals(entry.getValue(), task.getClass().getCanonicalName()); } } /** - * Test method for + * Test case for * {@link VTNRoutingManager#initRpcServices(RpcProviderRegistry,CompositeAutoCloseable)}. */ @Test public void testInitRpcServices() { - try { - vtnRoutingManager.initRpcServices(Mockito.mock(RpcProviderRegistry.class), new CompositeAutoCloseable(LoggerFactory.getLogger(VTNRoutingManager.class))); - } catch (Exception exception) { - Assert.fail("VTNRoutingManager test case failed..................."); - } + Logger logger = mock(Logger.class); + CompositeAutoCloseable closeables = new CompositeAutoCloseable(logger); + RpcProviderRegistry rpcReg = mock(RpcProviderRegistry.class); + RpcRegistration reg = mock(RpcRegistration.class); + Class type = VtnPathPolicyService.class; + when(rpcReg.addRpcImplementation(type, routingManager)). + thenReturn(reg); + + routingManager.initRpcServices(rpcReg, closeables); + verify(rpcReg).addRpcImplementation(type, routingManager); + verifyZeroInteractions(reg); + + closeables.close(); + verify(reg).close(); + verifyZeroInteractions(logger); } /** - * Test method for + * Test case for * {@link VTNRoutingManager#setPathPolicy(SetPathPolicyInput)}. + * + * @throws Exception An error occurred. */ @Test - public void testSetPathPolicy() { - try { - SetPathPolicyInputBuilder setPathPolicyInputBuilder = new SetPathPolicyInputBuilder().setId(1).setOperation(VtnUpdateOperationType.SET).setPresent(true); - SetPathPolicyInput setPathPolicyInput = setPathPolicyInputBuilder.build(); - vtnRoutingManager.setPathPolicy(setPathPolicyInput); - } catch (Exception exception) { - Assert.fail("VTNRoutingManager test case failed..................."); - } + public void testSetPathPolicy() throws Exception { + int id = 1; + TopologyGraph topo = getTopologyGraph(routingManager); + assertEquals(null, routingManager.getRouteResolver(id)); + Long rev = topo.getRevision(id); + assertEquals(0L, rev.longValue()); + + // In case of successful completion. + reset(vtnProvider); + SetPathPolicyInput input = new SetPathPolicyInputBuilder(). + setId(id). + setDefaultCost(100L). + setOperation(VtnUpdateOperationType.SET). + build(); + SettableVTNFuture taskFuture = new SettableVTNFuture<>(); + when(vtnProvider.postSync(isA(SetPathPolicyTask.class))). + thenReturn(taskFuture); + SettableVTNFuture flowFuture = new SettableVTNFuture<>(); + when(vtnProvider.removeFlows(isA(AllFlowRemover.class))). + thenReturn(flowFuture); + Future> future = + routingManager.setPathPolicy(input); + VtnUpdateType utype = VtnUpdateType.CREATED; + ArgumentCaptor tcaptor = + ArgumentCaptor.forClass(SetPathPolicyTask.class); + verify(vtnProvider).postSync(tcaptor.capture()); + List tasks = tcaptor.getAllValues(); + assertEquals(1, tasks.size()); + SetPathPolicyTask task = tasks.get(0); + task.onSuccess(vtnProvider, utype); + topo.updateResolver(id); + taskFuture.set(utype); + + TimeUnit unit = TimeUnit.SECONDS; + RpcResult result = future.get(1L, unit); + assertEquals(true, result.isSuccessful()); + SetPathPolicyOutput output = result.getResult(); + assertEquals(utype, output.getStatus()); + verify(vtnProvider).removeFlows(isA(AllFlowRemover.class)); + RouteResolver rr = routingManager.getRouteResolver(id); + assertNotNull(rr); + assertEquals(id, rr.getPathPolicyId()); + assertNotEquals(rev, topo.getRevision(id)); + + // In case of failure. + reset(vtnProvider); + input = null; + verifyRpcInputNull(routingManager.setPathPolicy(input)); + verifyZeroInteractions(vtnProvider); } /** - * Test method for + * Test case for * {@link VTNRoutingManager#removePathPolicy(RemovePathPolicyInput)}. + * + * @throws Exception An error occurred. */ @Test - public void testRemovePathPolicy() { - try { - RemovePathPolicyInputBuilder removePathPolicyInputBuilder = new RemovePathPolicyInputBuilder().setId(1); - RemovePathPolicyInput removePathPolicyInput = removePathPolicyInputBuilder.build(); - vtnRoutingManager.removePathPolicy(removePathPolicyInput); - } catch (Exception exception) { - Assert.fail("VTNRoutingManager test case failed..................."); - } + public void testRemovePathPolicy() throws Exception { + // Prepare route resolver for path policy to be removed. + int id = 1; + TopologyGraph topo = getTopologyGraph(routingManager); + assertTrue(topo.updateResolver(id)); + assertNotNull(routingManager.getRouteResolver(id)); + Long rev = topo.getRevision(id); + + // In case of successful completion. + reset(vtnProvider); + RemovePathPolicyInput input = new RemovePathPolicyInputBuilder(). + setId(id).build(); + SettableVTNFuture taskFuture = new SettableVTNFuture<>(); + when(vtnProvider.postSync(isA(RemovePathPolicyTask.class))). + thenReturn(taskFuture); + VTNFuture flowFuture = new SettableVTNFuture<>(); + when(vtnProvider.removeFlows(any(FlowRemover.class))). + thenReturn(flowFuture); + Future> future = + routingManager.removePathPolicy(input); + ArgumentCaptor tcaptor = + ArgumentCaptor.forClass(RemovePathPolicyTask.class); + verify(vtnProvider).postSync(tcaptor.capture()); + List tasks = tcaptor.getAllValues(); + assertEquals(1, tasks.size()); + RemovePathPolicyTask task = tasks.get(0); + VtnUpdateType utype = VtnUpdateType.REMOVED; + task.onSuccess(vtnProvider, utype); + topo.removeResolver(id); + taskFuture.set(utype); + + TimeUnit unit = TimeUnit.SECONDS; + RpcResult result = future.get(1L, unit); + assertEquals(true, result.isSuccessful()); + ArgumentCaptor fcaptor = + ArgumentCaptor.forClass(PathPolicyFlowRemover.class); + verify(vtnProvider).removeFlows(fcaptor.capture()); + List removers = fcaptor.getAllValues(); + assertEquals(1, removers.size()); + Set idSet = removers.get(0).getPathPolicyIds(); + assertEquals(1, idSet.size()); + assertEquals(true, idSet.contains(id)); + assertEquals(null, routingManager.getRouteResolver(id)); + assertNotEquals(rev, topo.getRevision(id)); + + // In case of failure. + reset(vtnProvider); + input = null; + verifyRpcInputNull(routingManager.removePathPolicy(input)); + verifyZeroInteractions(vtnProvider); } /** - * Test method for + * Test case for * {@link VTNRoutingManager#setPathCost(SetPathCostInput)}. + * + * @throws Exception An error occurred. */ @Test - public void testSetPathCost() { - try { - SetPathCostInputBuilder setPathCostInputBuilder = new SetPathCostInputBuilder().setId(1); - SetPathCostInput setPathCostInput = setPathCostInputBuilder.build(); - vtnRoutingManager.setPathCost(setPathCostInput); - } catch (Exception exception) { - Assert.fail("VTNRoutingManager test case failed..................."); - } + public void testSetPathCost() throws Exception { + // Prepare route resolver for path policy to be changed. + int id = 2; + TopologyGraph topo = getTopologyGraph(routingManager); + assertTrue(topo.updateResolver(id)); + assertNotNull(routingManager.getRouteResolver(id)); + Long rev = topo.getRevision(id); + + // In case of successful completion. + reset(vtnProvider); + List costs = new ArrayList<>(); + List expected = new ArrayList<>(); + List taskResults = new ArrayList<>(); + VtnPortDesc unchanged = new VtnPortDesc("openflow:3,10,,"); + PathCostList pcl = new PathCostListBuilder(). + setPortDesc(unchanged).setCost(12345L).build(); + costs.add(pcl); + taskResults.add(null); + SetPathCostResult r = new SetPathCostResultBuilder(). + setPortDesc(unchanged).build(); + expected.add(r); + + VtnPortDesc created = new VtnPortDesc("openflow:1,3,eth3"); + pcl = new PathCostListBuilder(). + setPortDesc(created).setCost(999L).build(); + costs.add(pcl); + VtnUpdateType utype = VtnUpdateType.CREATED; + taskResults.add(utype); + r = new SetPathCostResultBuilder(). + setPortDesc(created).setStatus(utype).build(); + expected.add(r); + + VtnPortDesc changed = new VtnPortDesc("openflow:2,,eth10"); + pcl = new PathCostListBuilder(). + setPortDesc(changed).setCost(100000L).build(); + costs.add(pcl); + utype = VtnUpdateType.CHANGED; + taskResults.add(utype); + r = new SetPathCostResultBuilder(). + setPortDesc(changed).setStatus(utype).build(); + expected.add(r); + + SetPathCostInput input = new SetPathCostInputBuilder(). + setId(id).setPathCostList(costs).build(); + SettableVTNFuture> taskFuture = + new SettableVTNFuture<>(); + when(vtnProvider.postSync(isA(SetPathCostTask.class))). + thenReturn(taskFuture); + VTNFuture flowFuture = new SettableVTNFuture<>(); + when(vtnProvider.removeFlows(any(FlowRemover.class))). + thenReturn(flowFuture); + Future> future = + routingManager.setPathCost(input); + ArgumentCaptor tcaptor = + ArgumentCaptor.forClass(SetPathCostTask.class); + verify(vtnProvider).postSync(tcaptor.capture()); + List tasks = tcaptor.getAllValues(); + assertEquals(1, tasks.size()); + SetPathCostTask task = tasks.get(0); + task.onSuccess(vtnProvider, taskResults); + topo.updateResolver(id); + taskFuture.set(taskResults); + + TimeUnit unit = TimeUnit.SECONDS; + RpcResult result = future.get(1L, unit); + assertEquals(true, result.isSuccessful()); + SetPathCostOutput output = result.getResult(); + assertEquals(expected, output.getSetPathCostResult()); + ArgumentCaptor fcaptor = + ArgumentCaptor.forClass(PathPolicyFlowRemover.class); + verify(vtnProvider).removeFlows(fcaptor.capture()); + List removers = fcaptor.getAllValues(); + assertEquals(1, removers.size()); + Set idSet = removers.get(0).getPathPolicyIds(); + assertEquals(1, idSet.size()); + assertEquals(true, idSet.contains(id)); + assertNotEquals(rev, topo.getRevision(id)); + + // In case of failure. + reset(vtnProvider); + input = null; + verifyRpcInputNull(routingManager.setPathCost(input)); + verifyZeroInteractions(vtnProvider); } /** - * Test method for + * Test case for * {@link VTNRoutingManager#removePathCost(RemovePathCostInput)}. + * + * @throws Exception An error occurred. */ @Test - public void testRemovePathCost() { - try { - RemovePathCostInputBuilder removePathCostInputBuilder = new RemovePathCostInputBuilder().setId(1); - RemovePathCostInput removePathCostInput = removePathCostInputBuilder.build(); - vtnRoutingManager.removePathCost(removePathCostInput); - } catch (Exception exception) { - Assert.fail("VTNRoutingManager test case failed..................."); + public void testRemovePathCost() throws Exception { + // Prepare route resolver for path policy to be changed. + int id = 3; + TopologyGraph topo = getTopologyGraph(routingManager); + assertTrue(topo.updateResolver(id)); + assertNotNull(routingManager.getRouteResolver(id)); + Long rev = topo.getRevision(id); + + // In case of successful completion. + reset(vtnProvider); + Map map = new HashMap<>(); + List descs = new ArrayList<>(); + VtnPortDesc notfound1 = new VtnPortDesc("openflow:3,10,"); + map.put(notfound1, null); + descs.add(notfound1); + + VtnPortDesc notfound2 = new VtnPortDesc("openflow:1,2,"); + map.put(notfound2, null); + descs.add(notfound2); + + VtnPortDesc removed = new VtnPortDesc("openflow:10,5,eth5"); + map.put(removed, VtnUpdateType.REMOVED); + descs.add(removed); + + RemovePathCostInput input = new RemovePathCostInputBuilder(). + setId(id).setPortDesc(descs).build(); + SettableVTNFuture> taskFuture = + new SettableVTNFuture<>(); + when(vtnProvider.postSync(isA(RemovePathCostTask.class))). + thenReturn(taskFuture); + VTNFuture flowFuture = new SettableVTNFuture<>(); + when(vtnProvider.removeFlows(any(FlowRemover.class))). + thenReturn(flowFuture); + Future> future = + routingManager.removePathCost(input); + + ArgumentCaptor tcaptor = + ArgumentCaptor.forClass(RemovePathCostTask.class); + verify(vtnProvider).postSync(tcaptor.capture()); + List tasks = tcaptor.getAllValues(); + assertEquals(1, tasks.size()); + RemovePathCostTask task = tasks.get(0); + List taskResults = new ArrayList<>(); + List expected = new ArrayList<>(); + for (RemoveCostTask rtask: task.getSubTasks()) { + VtnPortDesc vdesc = rtask.getPortDesc(); + assertTrue(map.containsKey(vdesc)); + VtnUpdateType status = map.remove(vdesc); + RemovePathCostResult r = new RemovePathCostResultBuilder(). + setPortDesc(vdesc).setStatus(status).build(); + expected.add(r); + taskResults.add(status); } + assertEquals(0, map.size()); + + task.onSuccess(vtnProvider, taskResults); + topo.updateResolver(id); + taskFuture.set(taskResults); + + TimeUnit unit = TimeUnit.SECONDS; + RpcResult result = future.get(1L, unit); + assertEquals(true, result.isSuccessful()); + RemovePathCostOutput output = result.getResult(); + assertEquals(expected, output.getRemovePathCostResult()); + ArgumentCaptor fcaptor = + ArgumentCaptor.forClass(PathPolicyFlowRemover.class); + verify(vtnProvider).removeFlows(fcaptor.capture()); + List removers = fcaptor.getAllValues(); + assertEquals(1, removers.size()); + Set idSet = removers.get(0).getPathPolicyIds(); + assertEquals(1, idSet.size()); + assertEquals(true, idSet.contains(id)); + assertNotEquals(rev, topo.getRevision(id)); + + // In case of failure. + reset(vtnProvider); + input = null; + verifyRpcInputNull(routingManager.removePathCost(input)); + verifyZeroInteractions(vtnProvider); } /** - * Test method for + * Test case for * {@link VTNRoutingManager#clearPathPolicy()}. + * + * @throws Exception An error occurred. */ @Test - public void testClearPathPolicy() { - try { - Future> future = vtnRoutingManager.clearPathPolicy(); - } catch (Exception exception) { - Assert.assertFalse(exception instanceof VTNException); + public void testClearPathPolicy() throws Exception { + // Prepare path policies to be removed. + TopologyGraph topo = getTopologyGraph(routingManager); + List policies = new ArrayList<>(); + Set policyIds = new HashSet<>(); + for (int id = 1; id <= 3; id++) { + policyIds.add(id); + VtnPathPolicy vpp = new VtnPathPolicyBuilder().setId(id).build(); + policies.add(vpp); + topo.updateResolver(id); + assertNotNull(routingManager.getRouteResolver(id)); + } + VtnPathPolicies root = new VtnPathPoliciesBuilder(). + setVtnPathPolicy(policies).build(); + + reset(vtnProvider); + SettableVTNFuture taskFuture = new SettableVTNFuture<>(); + when(vtnProvider.postSync(isA(ClearPathPolicyTask.class))). + thenReturn(taskFuture); + VTNFuture flowFuture = new SettableVTNFuture<>(); + when(vtnProvider.removeFlows(any(FlowRemover.class))). + thenReturn(flowFuture); + Future> future = + routingManager.clearPathPolicy(); + ArgumentCaptor tcaptor = + ArgumentCaptor.forClass(ClearPathPolicyTask.class); + verify(vtnProvider).postSync(tcaptor.capture()); + List tasks = tcaptor.getAllValues(); + assertEquals(1, tasks.size()); + ClearPathPolicyTask task = tasks.get(0); + TxContext ctx = mock(TxContext.class); + ReadWriteTransaction tx = mock(ReadWriteTransaction.class); + InstanceIdentifier path = + InstanceIdentifier.create(VtnPathPolicies.class); + LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL; + when(tx.read(oper, path)).thenReturn(getReadResult(root)); + when(ctx.getReadWriteTransaction()).thenReturn(tx); + VtnUpdateType utype = task.execute(ctx); + assertEquals(VtnUpdateType.REMOVED, utype); + verify(ctx).getReadWriteTransaction(); + verify(tx).read(oper, path); + VtnPathPolicies empty = new VtnPathPoliciesBuilder().build(); + verify(tx).put(oper, path, empty, true); + + task.onSuccess(vtnProvider, utype); + for (int id = 1; id <= 3; id++) { + topo.removeResolver(id); + } + taskFuture.set(utype); + + TimeUnit unit = TimeUnit.SECONDS; + RpcResult result = future.get(1L, unit); + assertEquals(true, result.isSuccessful()); + ClearPathPolicyOutput output = result.getResult(); + assertEquals(utype, output.getStatus()); + ArgumentCaptor fcaptor = + ArgumentCaptor.forClass(PathPolicyFlowRemover.class); + verify(vtnProvider).removeFlows(fcaptor.capture()); + List removers = fcaptor.getAllValues(); + assertEquals(1, removers.size()); + assertEquals(policyIds, removers.get(0).getPathPolicyIds()); + for (int id = 1; id <= 3; id++) { + assertEquals(null, routingManager.getRouteResolver(id)); } } -} + /** + * Return a wildcard path to the MD-SAL data model to listen. + */ + private InstanceIdentifier getPath() { + return InstanceIdentifier.builder(VtnTopology.class). + child(VtnLink.class).build(); + } + + /** + * Return a {@link TopologyGraph} instance configured in the given + * routing manager. + * + * @param rtm A {@link VTNRoutingManager} instance. + * @return A {@link TopologyGraph} instance. + * @throws Exception An error occurred. + */ + private TopologyGraph getTopologyGraph(VTNRoutingManager rtm) + throws Exception { + return getFieldValue(rtm, TopologyGraph.class, "topology"); + } + + /** + * Ensure that the routing manager was initialized correctly. + */ + private void verifyRoutingManager() { + LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL; + DataChangeScope scope = DataChangeScope.SUBTREE; + + // Ensure that PathPolicyListener is registered as data change + // listener. + InstanceIdentifier ppath = InstanceIdentifier. + builder(VtnPathPolicies.class). + child(VtnPathPolicy.class). + build(); + verify(dataBroker).registerDataChangeListener( + eq(oper), eq(ppath), isA(PathPolicyListener.class), eq(scope)); + + // Ensure that VTNRoutingManager is registered as data change listener. + verify(dataBroker).registerDataChangeListener( + eq(oper), eq(getPath()), isA(VTNRoutingManager.class), eq(scope)); + + verifyZeroInteractions(ppListenerReg); + verifyZeroInteractions(routingListenerReg); + + // Default route resolver must be always present. + RouteResolver rr = routingManager.getRouteResolver(0); + assertNotNull(rr); + assertEquals(0, rr.getPathPolicyId()); + + for (int i = 1; i <= 10; i++) { + assertEquals(null, routingManager.getRouteResolver(i)); + } + } + + /** + * Create network topology links which conntects the given 2 switch ports. + * + * @param vlinks A list to store created links. + * @param node1 The first node to be connected. + * @param port1 The port number of {@code node1} to be connected. + * @param node2 The second node to be connected. + * @param port2 The port number of {@code node2} to be connected. + */ + private void createVtnLink(List vlinks, SalNode node1, long port1, + SalNode node2, long port2) { + SalPort sport1 = new SalPort(node1.getNodeNumber(), port1); + SalPort sport2 = new SalPort(node2.getNodeNumber(), port2); + VtnLink vlink = new VtnLinkBuilder(). + setLinkId(new LinkId(sport1.toString())). + setSource(sport1.getNodeConnectorId()). + setDestination(sport2.getNodeConnectorId()). + build(); + vlinks.add(vlink); + + vlink = new VtnLinkBuilder(). + setLinkId(new LinkId(sport2.toString())). + setSource(sport2.getNodeConnectorId()). + setDestination(sport1.getNodeConnectorId()). + build(); + vlinks.add(vlink); + } + + /** + * Check the packet routing table. + * + * @param src The source node of the packet. + * @param dst The destination node of the packet. + * @param ports Switch ports which represents the expected packet route. + */ + private void checkRoute(SalNode src, SalNode dst, SalPort ... ports) { + RouteResolver rr = routingManager.getRouteResolver(0); + List route = rr.getRoute(null, src, dst); + if (ports.length == 0) { + assertEquals(null, route); + return; + } + + assertEquals(0, ports.length & 1); + int idx = 0; + for (LinkEdge le: route) { + assertEquals(ports[idx], le.getSourcePort()); + assertEquals(ports[idx + 1], le.getDestinationPort()); + idx += 2; + } + assertEquals(ports.length, idx); + } +} diff --git a/manager/implementation/src/test/resources/logback.xml b/manager/implementation/src/test/resources/logback.xml index 19ae8321..30866afb 100644 --- a/manager/implementation/src/test/resources/logback.xml +++ b/manager/implementation/src/test/resources/logback.xml @@ -34,6 +34,10 @@ level="OFF"/> + +