From 7ca0240e8a967cf516e58f256b993c29d4841337 Mon Sep 17 00:00:00 2001 From: Jozef Gloncak Date: Wed, 15 Apr 2015 13:56:11 +0200 Subject: [PATCH] Topology manager - removing links with after removing termination point. If termination point or whole node is removed then also all corresponding links are removed from topology. Fix of corresponding tests. Splitting original testing class (FlowCapableTopologyExporterTest) to - FlowCapableTopologyExporterTest - NodeChangeListenerImplTest - TerminationPointChangeListenerImplTest - TestUtils.java - contains common testing methods DataChangeListenerBase - is common ancestor for NodeChangeListenerImplTest and TerminationPointChangeListenerImplTest Change-Id: I051de4e5d54d50134b14f1399db9c44123990384 Signed-off-by: Jozef Gloncak --- .../manager/FlowCapableTopologyExporter.java | 111 +--- .../manager/NodeChangeListenerImpl.java | 4 +- .../TerminationPointChangeListenerImpl.java | 56 +- .../manager/DataChangeListenerBase.java | 95 +++ .../FlowCapableTopologyExporterTest.java | 555 +----------------- .../manager/NodeChangeListenerImplTest.java | 184 ++++++ ...erminationPointChangeListenerImplTest.java | 293 +++++++++ .../topology/manager/TestUtils.java | 165 ++++++ 8 files changed, 800 insertions(+), 663 deletions(-) create mode 100644 applications/topology-manager/src/test/java/org/opendaylight/openflowplugin/applications/topology/manager/DataChangeListenerBase.java create mode 100644 applications/topology-manager/src/test/java/org/opendaylight/openflowplugin/applications/topology/manager/NodeChangeListenerImplTest.java create mode 100644 applications/topology-manager/src/test/java/org/opendaylight/openflowplugin/applications/topology/manager/TerminationPointChangeListenerImplTest.java create mode 100644 applications/topology-manager/src/test/java/org/opendaylight/openflowplugin/applications/topology/manager/TestUtils.java diff --git a/applications/topology-manager/src/main/java/org/opendaylight/openflowplugin/applications/topology/manager/FlowCapableTopologyExporter.java b/applications/topology-manager/src/main/java/org/opendaylight/openflowplugin/applications/topology/manager/FlowCapableTopologyExporter.java index 459ac47789..f7ff99f792 100644 --- a/applications/topology-manager/src/main/java/org/opendaylight/openflowplugin/applications/topology/manager/FlowCapableTopologyExporter.java +++ b/applications/topology-manager/src/main/java/org/opendaylight/openflowplugin/applications/topology/manager/FlowCapableTopologyExporter.java @@ -13,20 +13,13 @@ import com.google.common.base.Preconditions; import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorUpdated; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeUpdated; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.FlowTopologyDiscoveryListener; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.LinkDiscovered; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.LinkOverutilized; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.LinkRemoved; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.LinkUtilizationNormal; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRemoved; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorUpdated; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRemoved; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeUpdated; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.OpendaylightInventoryListener; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId; @@ -42,13 +35,11 @@ import org.slf4j.LoggerFactory; import static org.opendaylight.openflowplugin.applications.topology.manager.FlowCapableNodeMapping.getNodeConnectorKey; import static org.opendaylight.openflowplugin.applications.topology.manager.FlowCapableNodeMapping.getNodeKey; -import static org.opendaylight.openflowplugin.applications.topology.manager.FlowCapableNodeMapping.toTerminationPoint; import static org.opendaylight.openflowplugin.applications.topology.manager.FlowCapableNodeMapping.toTerminationPointId; import static org.opendaylight.openflowplugin.applications.topology.manager.FlowCapableNodeMapping.toTopologyLink; -import static org.opendaylight.openflowplugin.applications.topology.manager.FlowCapableNodeMapping.toTopologyNode; import static org.opendaylight.openflowplugin.applications.topology.manager.FlowCapableNodeMapping.toTopologyNodeId; -class FlowCapableTopologyExporter implements FlowTopologyDiscoveryListener, OpendaylightInventoryListener { +class FlowCapableTopologyExporter implements FlowTopologyDiscoveryListener { private static final Logger LOG = LoggerFactory.getLogger(FlowCapableTopologyExporter.class); protected final InstanceIdentifier iiToTopology; @@ -60,106 +51,6 @@ class FlowCapableTopologyExporter implements FlowTopologyDiscoveryListener, Open this.iiToTopology = Preconditions.checkNotNull(topology); } - @Override - public void onNodeRemoved(final NodeRemoved notification) { - - final NodeId nodeId = toTopologyNodeId(getNodeKey(notification.getNodeRef()).getId()); - final InstanceIdentifier nodeInstance = toNodeIdentifier(notification.getNodeRef()); - - processor.enqueueOperation(new TopologyOperation() { - @Override - public void applyOperation(ReadWriteTransaction transaction) { - TopologyManagerUtil.removeAffectedLinks(nodeId, transaction, iiToTopology); - transaction.delete(LogicalDatastoreType.OPERATIONAL, nodeInstance); - } - - @Override - public String toString() { - return "onNodeRemoved"; - } - }); - } - - @Override - public void onNodeUpdated(final NodeUpdated notification) { - FlowCapableNodeUpdated fcnu = notification.getAugmentation(FlowCapableNodeUpdated.class); - if (fcnu != null) { - processor.enqueueOperation(new TopologyOperation() { - @Override - public void applyOperation(final ReadWriteTransaction transaction) { - final Node node = toTopologyNode(toTopologyNodeId(notification.getId()), notification.getNodeRef()); - final InstanceIdentifier path = getNodePath(toTopologyNodeId(notification.getId())); - transaction.merge(LogicalDatastoreType.OPERATIONAL, path, node, true); - } - - @Override - public String toString() { - return "onNodeUpdated"; - } - }); - } - } - - @Override - public void onNodeConnectorRemoved(final NodeConnectorRemoved notification) { - - final InstanceIdentifier tpInstance = toTerminationPointIdentifier( - notification.getNodeConnectorRef()); - - final InstanceIdentifier node = tpInstance.firstIdentifierOf(Node.class); - - final TpId tpId = toTerminationPointId(getNodeConnectorKey( - notification.getNodeConnectorRef()).getId()); - - processor.enqueueOperation(new TopologyOperation() { - @Override - public void applyOperation(ReadWriteTransaction transaction) { - Optional nodeOptional = Optional.absent(); - try { - nodeOptional = transaction.read(LogicalDatastoreType.OPERATIONAL, node).checkedGet(); - } catch (ReadFailedException e) { - LOG.error("Error occured when trying to read NodeConnector ", e); - } - if (nodeOptional.isPresent()) { - TopologyManagerUtil.removeAffectedLinks(tpId, transaction, iiToTopology); - transaction.delete(LogicalDatastoreType.OPERATIONAL, tpInstance); - } - } - - @Override - public String toString() { - return "onNodeConnectorRemoved"; - } - }); - } - - @Override - public void onNodeConnectorUpdated(final NodeConnectorUpdated notification) { - final FlowCapableNodeConnectorUpdated fcncu = notification.getAugmentation( - FlowCapableNodeConnectorUpdated.class); - if (fcncu != null) { - processor.enqueueOperation(new TopologyOperation() { - @Override - public void applyOperation(final ReadWriteTransaction transaction) { - final NodeId nodeId = toTopologyNodeId(getNodeKey(notification.getNodeConnectorRef()).getId()); - TerminationPoint point = toTerminationPoint(toTerminationPointId(notification.getId()), - notification.getNodeConnectorRef()); - final InstanceIdentifier path = tpPath(nodeId, point.getKey().getTpId()); - transaction.merge(LogicalDatastoreType.OPERATIONAL, path, point, true); - if ((fcncu.getState() != null && fcncu.getState().isLinkDown()) - || (fcncu.getConfiguration() != null && fcncu.getConfiguration().isPORTDOWN())) { - TopologyManagerUtil.removeAffectedLinks(point.getTpId(), transaction, iiToTopology); - } - } - - @Override - public String toString() { - return "onNodeConnectorUpdated"; - } - }); - } - } - @Override public void onLinkDiscovered(final LinkDiscovered notification) { processor.enqueueOperation(new TopologyOperation() { diff --git a/applications/topology-manager/src/main/java/org/opendaylight/openflowplugin/applications/topology/manager/NodeChangeListenerImpl.java b/applications/topology-manager/src/main/java/org/opendaylight/openflowplugin/applications/topology/manager/NodeChangeListenerImpl.java index 6c4f1b6136..f4482eda83 100644 --- a/applications/topology-manager/src/main/java/org/opendaylight/openflowplugin/applications/topology/manager/NodeChangeListenerImpl.java +++ b/applications/topology-manager/src/main/java/org/opendaylight/openflowplugin/applications/topology/manager/NodeChangeListenerImpl.java @@ -50,13 +50,15 @@ public class NodeChangeListenerImpl extends DataChangeListenerImpl { */ private void processRemovedNode(Set> removedNodes) { for (InstanceIdentifier removedNode : removedNodes) { - final InstanceIdentifier iiToTopologyRemovedNode = provideIIToTopologyNode(provideTopologyNodeId(removedNode)); + final NodeId nodeId = provideTopologyNodeId(removedNode); + final InstanceIdentifier iiToTopologyRemovedNode = provideIIToTopologyNode(nodeId); if (iiToTopologyRemovedNode != null) { operationProcessor.enqueueOperation(new TopologyOperation() { @Override public void applyOperation(ReadWriteTransaction transaction) { transaction.delete(LogicalDatastoreType.OPERATIONAL, iiToTopologyRemovedNode); + TopologyManagerUtil.removeAffectedLinks(nodeId, transaction, II_TO_TOPOLOGY); } }); } else { diff --git a/applications/topology-manager/src/main/java/org/opendaylight/openflowplugin/applications/topology/manager/TerminationPointChangeListenerImpl.java b/applications/topology-manager/src/main/java/org/opendaylight/openflowplugin/applications/topology/manager/TerminationPointChangeListenerImpl.java index b4714f3646..c260e692be 100644 --- a/applications/topology-manager/src/main/java/org/opendaylight/openflowplugin/applications/topology/manager/TerminationPointChangeListenerImpl.java +++ b/applications/topology-manager/src/main/java/org/opendaylight/openflowplugin/applications/topology/manager/TerminationPointChangeListenerImpl.java @@ -7,8 +7,9 @@ */ package org.opendaylight.openflowplugin.applications.topology.manager; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import com.google.common.base.Optional; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.topology.inventory.rev131030.InventoryNodeConnector; - import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef; import org.opendaylight.yang.gen.v1.urn.opendaylight.model.topology.inventory.rev131030.InventoryNodeConnectorBuilder; import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; @@ -54,14 +55,27 @@ public class TerminationPointChangeListenerImpl extends DataChangeListenerImpl { */ private void processRemovedTerminationPoints(Set> removedNodes) { for (final InstanceIdentifier removedNode : removedNodes) { - InstanceIdentifier iiToTopologyTerminationPoint = provideIIToTopologyTerminationPoint( - provideTopologyTerminationPointId(removedNode), removedNode); + final TpId terminationPointId = provideTopologyTerminationPointId(removedNode); + final InstanceIdentifier iiToTopologyTerminationPoint = provideIIToTopologyTerminationPoint( + terminationPointId, removedNode); + final InstanceIdentifier node = iiToTopologyTerminationPoint.firstIdentifierOf(org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node.class); + + if (iiToTopologyTerminationPoint != null) { operationProcessor.enqueueOperation(new TopologyOperation() { @Override public void applyOperation(ReadWriteTransaction transaction) { - transaction.delete(LogicalDatastoreType.OPERATIONAL, removedNode); + Optional nodeOptional = Optional.absent(); + try { + nodeOptional = transaction.read(LogicalDatastoreType.OPERATIONAL, node).checkedGet(); + } catch (ReadFailedException e) { + LOG.error("Error occured when trying to read NodeConnector ", e); + } + if (nodeOptional.isPresent()) { + TopologyManagerUtil.removeAffectedLinks(terminationPointId, transaction, II_TO_TOPOLOGY); + transaction.delete(LogicalDatastoreType.OPERATIONAL, iiToTopologyTerminationPoint); + } } }); @@ -89,13 +103,33 @@ public class TerminationPointChangeListenerImpl extends DataChangeListenerImpl { if (terminationPointIdInTopology != null) { InstanceIdentifier iiToTopologyTerminationPoint = provideIIToTopologyTerminationPoint( terminationPointIdInTopology, iiToNodeInInventory); - sendToTransactionChain(prepareTopologyTerminationPoint(terminationPointIdInTopology, iiToNodeInInventory), - iiToTopologyTerminationPoint); + TerminationPoint point = prepareTopologyTerminationPoint(terminationPointIdInTopology, iiToNodeInInventory); + sendToTransactionChain(point, iiToTopologyTerminationPoint); + if (data instanceof FlowCapableNodeConnector) { + removeLinks((FlowCapableNodeConnector) data, point); + } + } else { LOG.debug("Inventory node connector key is null. Data can't be written to topology termination point"); } } + /** + * @param data + */ + private void removeLinks(final FlowCapableNodeConnector flowCapNodeConnector, final TerminationPoint point) { + operationProcessor.enqueueOperation(new TopologyOperation() { + + @Override + public void applyOperation(ReadWriteTransaction transaction) { + if ((flowCapNodeConnector.getState() != null && flowCapNodeConnector.getState().isLinkDown()) + || (flowCapNodeConnector.getConfiguration() != null && flowCapNodeConnector.getConfiguration().isPORTDOWN())) { + TopologyManagerUtil.removeAffectedLinks(point.getTpId(), transaction, II_TO_TOPOLOGY); + } + } + }); + } + private TerminationPoint prepareTopologyTerminationPoint(final TpId terminationPointIdInTopology, final InstanceIdentifier iiToNodeInInventory) { final InventoryNodeConnector inventoryNodeConnector = new InventoryNodeConnectorBuilder() @@ -115,9 +149,13 @@ public class TerminationPointChangeListenerImpl extends DataChangeListenerImpl { private InstanceIdentifier provideIIToTopologyTerminationPoint(TpId terminationPointIdInTopology, InstanceIdentifier iiToNodeInInventory) { NodeId nodeIdInTopology = provideTopologyNodeId(iiToNodeInInventory); - InstanceIdentifier iiToTopologyNode = provideIIToTopologyNode(nodeIdInTopology); - return iiToTopologyNode.builder() - .child(TerminationPoint.class, new TerminationPointKey(terminationPointIdInTopology)).build(); + if (terminationPointIdInTopology != null && nodeIdInTopology != null) { + InstanceIdentifier iiToTopologyNode = provideIIToTopologyNode(nodeIdInTopology); + return iiToTopologyNode.builder().child(TerminationPoint.class, new TerminationPointKey(terminationPointIdInTopology)).build(); + } else { + LOG.debug("Value of termination point ID in topology is null. Instance identifier to topology can't be built"); + return null; + } } /** diff --git a/applications/topology-manager/src/test/java/org/opendaylight/openflowplugin/applications/topology/manager/DataChangeListenerBase.java b/applications/topology-manager/src/test/java/org/opendaylight/openflowplugin/applications/topology/manager/DataChangeListenerBase.java new file mode 100644 index 0000000000..e88e27a7c0 --- /dev/null +++ b/applications/topology-manager/src/test/java/org/opendaylight/openflowplugin/applications/topology/manager/DataChangeListenerBase.java @@ -0,0 +1,95 @@ +/** + * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * 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.openflowplugin.applications.topology.manager; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doReturn; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import org.mockito.Mock; +import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; +import org.junit.After; +import org.junit.Before; +import org.mockito.MockitoAnnotations; +import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener; +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 java.util.Collections; +import java.util.Map; +import java.util.Set; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortConfig; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.flow.capable.port.StateBuilder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * @author joe + * + */ +public abstract class DataChangeListenerBase { + + @Mock + private DataBroker mockDataBroker; + + @Mock + protected BindingTransactionChain mockTxChain; + + @Mock + protected AsyncDataChangeEvent, DataObject> mockedDataChangeListener; + + private OperationProcessor processor; + + protected InstanceIdentifier topologyIID; + + protected TerminationPointChangeListenerImpl terminationPointListener; + protected NodeChangeListenerImpl nodeChangeListener; + + private final ExecutorService executor = Executors.newFixedThreadPool(1); + + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + doReturn(mockTxChain).when(mockDataBroker) + .createTransactionChain(any(TransactionChainListener.class)); + + processor = new OperationProcessor(mockDataBroker); + + topologyIID = InstanceIdentifier.create(NetworkTopology.class) + .child(Topology.class, new TopologyKey(new TopologyId("flow:1"))); + terminationPointListener = new TerminationPointChangeListenerImpl(mockDataBroker, processor); + nodeChangeListener = new NodeChangeListenerImpl(mockDataBroker, processor); + + executor.execute(processor); + } + + @After + public void tearDown() { + executor.shutdownNow(); + } + + protected void mockDataChangeListener(Map,DataObject> createdData, Map, DataObject> updatedData, Set removedPaths) { + doReturn(createdData == null ? Collections.emptyMap() : createdData).when(mockedDataChangeListener).getCreatedData(); + doReturn(updatedData == null ? Collections.emptyMap() : updatedData).when(mockedDataChangeListener).getUpdatedData(); + doReturn(removedPaths == null ? Collections.emptySet() : removedPaths).when(mockedDataChangeListener).getRemovedPaths(); + } + + protected FlowCapableNodeConnector provideFlowCapableNodeConnector(final boolean isLinkDown, final boolean isPortDown) { + FlowCapableNodeConnectorBuilder builder = new FlowCapableNodeConnectorBuilder(); + builder.setState(new StateBuilder().setLinkDown(isLinkDown).build()); + builder.setConfiguration(new PortConfig(true, true, true, isPortDown)); + return builder.build(); + } +} diff --git a/applications/topology-manager/src/test/java/org/opendaylight/openflowplugin/applications/topology/manager/FlowCapableTopologyExporterTest.java b/applications/topology-manager/src/test/java/org/opendaylight/openflowplugin/applications/topology/manager/FlowCapableTopologyExporterTest.java index d716e02150..e3e669adc9 100644 --- a/applications/topology-manager/src/test/java/org/opendaylight/openflowplugin/applications/topology/manager/FlowCapableTopologyExporterTest.java +++ b/applications/topology-manager/src/test/java/org/opendaylight/openflowplugin/applications/topology/manager/FlowCapableTopologyExporterTest.java @@ -8,91 +8,42 @@ package org.opendaylight.openflowplugin.applications.topology.manager; +import static org.opendaylight.openflowplugin.applications.topology.manager.TestUtils.*; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; +import org.opendaylight.yangtools.yang.binding.DataObject; import com.google.common.base.Optional; -import com.google.common.util.concurrent.CheckedFuture; import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.SettableFuture; -import com.google.common.util.concurrent.Uninterruptibles; - import org.junit.After; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; -import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener; -import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; import org.opendaylight.openflowplugin.applications.topology.manager.FlowCapableTopologyExporter; import org.opendaylight.openflowplugin.applications.topology.manager.OperationProcessor; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorUpdated; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorUpdatedBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeUpdated; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeUpdatedBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.LinkDiscoveredBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.LinkRemovedBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortConfig; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.flow.capable.port.StateBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRemovedBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorUpdatedBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRemovedBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeUpdatedBuilder; -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.node.NodeConnectorKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.topology.inventory.rev131030.InventoryNode; -import org.opendaylight.yang.gen.v1.urn.opendaylight.model.topology.inventory.rev131030.InventoryNodeConnector; 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.NodeId; 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.TpId; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.Destination; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.DestinationBuilder; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.Source; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.SourceBuilder; 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.TopologyBuilder; 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; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.LinkBuilder; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.LinkKey; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint; -import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; - import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; import static org.mockito.Mockito.any; -import static org.mockito.Mockito.atLeast; -import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.eq; -import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -109,10 +60,16 @@ public class FlowCapableTopologyExporterTest { private FlowCapableTopologyExporter exporter; + private TerminationPointChangeListenerImpl terminationPointListener; + private NodeChangeListenerImpl nodeChangeListener; + private InstanceIdentifier topologyIID; private final ExecutorService executor = Executors.newFixedThreadPool(1); + @Mock + private AsyncDataChangeEvent, DataObject> mockedDataChangeListener; + @Before public void setUp() { MockitoAnnotations.initMocks(this); @@ -123,8 +80,10 @@ public class FlowCapableTopologyExporterTest { processor = new OperationProcessor(mockDataBroker); topologyIID = InstanceIdentifier.create(NetworkTopology.class) - .child(Topology.class, new TopologyKey(new TopologyId("test"))); + .child(Topology.class, new TopologyKey(new TopologyId("flow:1"))); exporter = new FlowCapableTopologyExporter(processor, topologyIID); + terminationPointListener = new TerminationPointChangeListenerImpl(mockDataBroker, processor); + nodeChangeListener = new NodeChangeListenerImpl(mockDataBroker, processor); executor.execute(processor); } @@ -134,385 +93,6 @@ public class FlowCapableTopologyExporterTest { executor.shutdownNow(); } - @SuppressWarnings({ "rawtypes" }) - @Test - public void testOnNodeRemoved() { - - NodeKey topoNodeKey = new NodeKey(new NodeId("node1")); - InstanceIdentifier topoNodeII = topologyIID.child(Node.class, topoNodeKey); - Node topoNode = new NodeBuilder().setKey(topoNodeKey).build(); - - org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey - nodeKey = newInvNodeKey(topoNodeKey.getNodeId().getValue()); - InstanceIdentifier invNodeID = InstanceIdentifier.create(Nodes.class).child( - org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, - nodeKey); - - List linkList = Arrays.asList( - newLink("link1", newSourceNode("node1"), newDestNode("dest")), - newLink("link2", newSourceNode("source"), newDestNode("node1")), - newLink("link2", newSourceNode("source2"), newDestNode("dest2"))); - final Topology topology = new TopologyBuilder().setLink(linkList).build(); - - InstanceIdentifier[] expDeletedIIDs = { - topologyIID.child(Link.class, linkList.get(0).getKey()), - topologyIID.child(Link.class, linkList.get(1).getKey()), - topologyIID.child(Node.class, new NodeKey(new NodeId("node1"))) - }; - - SettableFuture> readFuture = SettableFuture.create(); - readFuture.set(Optional.of(topology)); - ReadWriteTransaction mockTx1 = mock(ReadWriteTransaction.class); - doReturn(Futures.makeChecked(readFuture, ReadFailedException.MAPPER)).when(mockTx1) - .read(LogicalDatastoreType.OPERATIONAL, topologyIID); - - SettableFuture> readFutureNode = SettableFuture.create(); - readFutureNode.set(Optional.of(topoNode)); - doReturn(Futures.makeChecked(readFutureNode, ReadFailedException.MAPPER)).when(mockTx1) - .read(LogicalDatastoreType.OPERATIONAL, topoNodeII); - - CountDownLatch submitLatch1 = setupStubbedSubmit(mockTx1); - - int expDeleteCalls = expDeletedIIDs.length; - CountDownLatch deleteLatch = new CountDownLatch(expDeleteCalls); - ArgumentCaptor deletedLinkIDs = - ArgumentCaptor.forClass(InstanceIdentifier.class); - setupStubbedDeletes(mockTx1, deletedLinkIDs, deleteLatch); - - doReturn(mockTx1).when(mockTxChain).newReadWriteTransaction(); - - exporter.onNodeRemoved(new NodeRemovedBuilder().setNodeRef(new NodeRef(invNodeID)).build()); - - waitForSubmit(submitLatch1); - - setReadFutureAsync(topology, readFuture); - - waitForDeletes(expDeleteCalls, deleteLatch); - - assertDeletedIDs(expDeletedIIDs, deletedLinkIDs); - - verifyMockTx(mockTx1); - } - - @SuppressWarnings({ "rawtypes" }) - @Test - public void testOnNodeRemovedWithNoTopology() { - - NodeKey topoNodeKey = new NodeKey(new NodeId("node1")); - InstanceIdentifier topoNodeII = topologyIID.child(Node.class, topoNodeKey); - Node topoNode = new NodeBuilder().setKey(topoNodeKey).build(); - - org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey - nodeKey = newInvNodeKey(topoNodeKey.getNodeId().getValue()); - InstanceIdentifier invNodeID = InstanceIdentifier.create(Nodes.class).child( - org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, - nodeKey); - - InstanceIdentifier[] expDeletedIIDs = { - topologyIID.child(Node.class, new NodeKey(new NodeId("node1"))) - }; - - ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class); - doReturn(Futures.immediateCheckedFuture(Optional.absent())).when(mockTx) - .read(LogicalDatastoreType.OPERATIONAL, topologyIID); - CountDownLatch submitLatch = setupStubbedSubmit(mockTx); - - SettableFuture> readFutureNode = SettableFuture.create(); - readFutureNode.set(Optional.of(topoNode)); - doReturn(Futures.makeChecked(readFutureNode, ReadFailedException.MAPPER)).when(mockTx) - .read(LogicalDatastoreType.OPERATIONAL, topoNodeII); - - CountDownLatch deleteLatch = new CountDownLatch(1); - ArgumentCaptor deletedLinkIDs = - ArgumentCaptor.forClass(InstanceIdentifier.class); - setupStubbedDeletes(mockTx, deletedLinkIDs, deleteLatch); - - doReturn(mockTx).when(mockTxChain).newReadWriteTransaction(); - - exporter.onNodeRemoved(new NodeRemovedBuilder().setNodeRef(new NodeRef(invNodeID)).build()); - - waitForSubmit(submitLatch); - - waitForDeletes(1, deleteLatch); - - assertDeletedIDs(expDeletedIIDs, deletedLinkIDs); - } - - @SuppressWarnings("rawtypes") - @Test - public void testOnNodeConnectorRemoved() { - - NodeKey topoNodeKey = new NodeKey(new NodeId("node1")); - TerminationPointKey terminationPointKey = new TerminationPointKey(new TpId("tp1")); - - InstanceIdentifier topoNodeII = topologyIID.child(Node.class, topoNodeKey); - Node topoNode = new NodeBuilder().setKey(topoNodeKey).build(); - - org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey - nodeKey = newInvNodeKey(topoNodeKey.getNodeId().getValue()); - - org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey ncKey = - newInvNodeConnKey(terminationPointKey.getTpId().getValue()); - - InstanceIdentifier invNodeConnID = newNodeConnID(nodeKey, ncKey); - - List linkList = Arrays.asList( - newLink("link1", newSourceTp("tp1"), newDestTp("dest")), - newLink("link2", newSourceTp("source"), newDestTp("tp1")), - newLink("link3", newSourceTp("source2"), newDestTp("dest2"))); - final Topology topology = new TopologyBuilder().setLink(linkList).build(); - - InstanceIdentifier[] expDeletedIIDs = { - topologyIID.child(Link.class, linkList.get(0).getKey()), - topologyIID.child(Link.class, linkList.get(1).getKey()), - topologyIID.child(Node.class, new NodeKey(new NodeId("node1"))) - .child(TerminationPoint.class, new TerminationPointKey(new TpId("tp1"))) - }; - - final SettableFuture> readFuture = SettableFuture.create(); - readFuture.set(Optional.of(topology)); - ReadWriteTransaction mockTx1 = mock(ReadWriteTransaction.class); - doReturn(Futures.makeChecked(readFuture, ReadFailedException.MAPPER)).when(mockTx1) - .read(LogicalDatastoreType.OPERATIONAL, topologyIID); - - SettableFuture> readFutureNode = SettableFuture.create(); - readFutureNode.set(Optional.of(topoNode)); - doReturn(Futures.makeChecked(readFutureNode, ReadFailedException.MAPPER)).when(mockTx1) - .read(LogicalDatastoreType.OPERATIONAL, topoNodeII); - - CountDownLatch submitLatch1 = setupStubbedSubmit(mockTx1); - - int expDeleteCalls = expDeletedIIDs.length; - CountDownLatch deleteLatch = new CountDownLatch(expDeleteCalls); - ArgumentCaptor deletedLinkIDs = - ArgumentCaptor.forClass(InstanceIdentifier.class); - setupStubbedDeletes(mockTx1, deletedLinkIDs, deleteLatch); - - doReturn(mockTx1).when(mockTxChain).newReadWriteTransaction(); - - exporter.onNodeConnectorRemoved(new NodeConnectorRemovedBuilder().setNodeConnectorRef( - new NodeConnectorRef(invNodeConnID)).build()); - - waitForSubmit(submitLatch1); - - setReadFutureAsync(topology, readFuture); - - waitForDeletes(expDeleteCalls, deleteLatch); - - assertDeletedIDs(expDeletedIIDs, deletedLinkIDs); - - verifyMockTx(mockTx1); - } - - @SuppressWarnings("rawtypes") - @Test - public void testOnNodeConnectorRemovedWithNoTopology() { - - NodeKey topoNodeKey = new NodeKey(new NodeId("node1")); - TerminationPointKey terminationPointKey = new TerminationPointKey(new TpId("tp1")); - - InstanceIdentifier topoNodeII = topologyIID.child(Node.class, topoNodeKey); - Node topoNode = new NodeBuilder().setKey(topoNodeKey).build(); - - org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey - nodeKey = newInvNodeKey(topoNodeKey.getNodeId().getValue()); - - org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey ncKey = - newInvNodeConnKey(terminationPointKey.getTpId().getValue()); - - InstanceIdentifier invNodeConnID = newNodeConnID(nodeKey, ncKey); - - InstanceIdentifier[] expDeletedIIDs = { - topologyIID.child(Node.class, new NodeKey(new NodeId("node1"))) - .child(TerminationPoint.class, new TerminationPointKey(new TpId("tp1"))) - }; - - ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class); - doReturn(Futures.immediateCheckedFuture(Optional.absent())).when(mockTx) - .read(LogicalDatastoreType.OPERATIONAL, topologyIID); - CountDownLatch submitLatch = setupStubbedSubmit(mockTx); - - SettableFuture> readFutureNode = SettableFuture.create(); - readFutureNode.set(Optional.of(topoNode)); - doReturn(Futures.makeChecked(readFutureNode, ReadFailedException.MAPPER)).when(mockTx) - .read(LogicalDatastoreType.OPERATIONAL, topoNodeII); - - CountDownLatch deleteLatch = new CountDownLatch(1); - ArgumentCaptor deletedLinkIDs = - ArgumentCaptor.forClass(InstanceIdentifier.class); - setupStubbedDeletes(mockTx, deletedLinkIDs, deleteLatch); - - doReturn(mockTx).when(mockTxChain).newReadWriteTransaction(); - - exporter.onNodeConnectorRemoved(new NodeConnectorRemovedBuilder().setNodeConnectorRef( - new NodeConnectorRef(invNodeConnID)).build()); - - waitForSubmit(submitLatch); - - waitForDeletes(1, deleteLatch); - - assertDeletedIDs(expDeletedIIDs, deletedLinkIDs); - } - - @Test - public void testOnNodeUpdated() { - - org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey - nodeKey = newInvNodeKey("node1"); - InstanceIdentifier invNodeID = InstanceIdentifier.create(Nodes.class).child( - org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, - nodeKey); - - ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class); - CountDownLatch submitLatch = setupStubbedSubmit(mockTx); - doReturn(mockTx).when(mockTxChain).newReadWriteTransaction(); - - exporter.onNodeUpdated(new NodeUpdatedBuilder().setNodeRef(new NodeRef(invNodeID)) - .setId(nodeKey.getId()).addAugmentation(FlowCapableNodeUpdated.class, - new FlowCapableNodeUpdatedBuilder().build()).build()); - - waitForSubmit(submitLatch); - - ArgumentCaptor mergedNode = ArgumentCaptor.forClass(Node.class); - NodeId expNodeId = new NodeId("node1"); - verify(mockTx).merge(eq(LogicalDatastoreType.OPERATIONAL), eq(topologyIID.child(Node.class, - new NodeKey(expNodeId))), mergedNode.capture(), eq(true)); - assertEquals("getNodeId", expNodeId, mergedNode.getValue().getNodeId()); - InventoryNode augmentation = mergedNode.getValue().getAugmentation(InventoryNode.class); - assertNotNull("Missing augmentation", augmentation); - assertEquals("getInventoryNodeRef", new NodeRef(invNodeID), augmentation.getInventoryNodeRef()); - } - - @Test - public void testOnNodeConnectorUpdated() { - - org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey - nodeKey = newInvNodeKey("node1"); - - org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey ncKey = - newInvNodeConnKey("tp1"); - - InstanceIdentifier invNodeConnID = newNodeConnID(nodeKey, ncKey); - - ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class); - CountDownLatch submitLatch = setupStubbedSubmit(mockTx); - doReturn(mockTx).when(mockTxChain).newReadWriteTransaction(); - - exporter.onNodeConnectorUpdated(new NodeConnectorUpdatedBuilder().setNodeConnectorRef( - new NodeConnectorRef(invNodeConnID)).setId(ncKey.getId()).addAugmentation( - FlowCapableNodeConnectorUpdated.class, - new FlowCapableNodeConnectorUpdatedBuilder().build()).build()); - - waitForSubmit(submitLatch); - - ArgumentCaptor mergedNode = ArgumentCaptor.forClass(TerminationPoint.class); - NodeId expNodeId = new NodeId("node1"); - TpId expTpId = new TpId("tp1"); - InstanceIdentifier expTpPath = topologyIID.child( - Node.class, new NodeKey(expNodeId)).child(TerminationPoint.class, - new TerminationPointKey(expTpId)); - verify(mockTx).merge(eq(LogicalDatastoreType.OPERATIONAL), eq(expTpPath), - mergedNode.capture(), eq(true)); - assertEquals("getTpId", expTpId, mergedNode.getValue().getTpId()); - InventoryNodeConnector augmentation = mergedNode.getValue().getAugmentation( - InventoryNodeConnector.class); - assertNotNull("Missing augmentation", augmentation); - assertEquals("getInventoryNodeConnectorRef", new NodeConnectorRef(invNodeConnID), - augmentation.getInventoryNodeConnectorRef()); - } - - @SuppressWarnings("rawtypes") - @Test - public void testOnNodeConnectorUpdatedWithLinkStateDown() { - - org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey - nodeKey = newInvNodeKey("node1"); - - org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey ncKey = - newInvNodeConnKey("tp1"); - - InstanceIdentifier invNodeConnID = newNodeConnID(nodeKey, ncKey); - - List linkList = Arrays.asList(newLink("link1", newSourceTp("tp1"), newDestTp("dest"))); - Topology topology = new TopologyBuilder().setLink(linkList).build(); - - ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class); - doReturn(Futures.immediateCheckedFuture(Optional.of(topology))).when(mockTx) - .read(LogicalDatastoreType.OPERATIONAL, topologyIID); - setupStubbedSubmit(mockTx); - - CountDownLatch deleteLatch = new CountDownLatch(1); - ArgumentCaptor deletedLinkIDs = - ArgumentCaptor.forClass(InstanceIdentifier.class); - setupStubbedDeletes(mockTx, deletedLinkIDs, deleteLatch); - - doReturn(mockTx).when(mockTxChain).newReadWriteTransaction(); - - exporter.onNodeConnectorUpdated(new NodeConnectorUpdatedBuilder().setNodeConnectorRef( - new NodeConnectorRef(invNodeConnID)).setId(ncKey.getId()).addAugmentation( - FlowCapableNodeConnectorUpdated.class, - new FlowCapableNodeConnectorUpdatedBuilder().setState( - new StateBuilder().setLinkDown(true).build()).build()).build()); - - waitForDeletes(1, deleteLatch); - - InstanceIdentifier expTpPath = topologyIID.child( - Node.class, new NodeKey(new NodeId("node1"))).child(TerminationPoint.class, - new TerminationPointKey(new TpId("tp1"))); - - verify(mockTx).merge(eq(LogicalDatastoreType.OPERATIONAL), eq(expTpPath), - any(TerminationPoint.class), eq(true)); - - assertDeletedIDs(new InstanceIdentifier[]{topologyIID.child(Link.class, - linkList.get(0).getKey())}, deletedLinkIDs); - } - - - @SuppressWarnings("rawtypes") - @Test - public void testOnNodeConnectorUpdatedWithPortDown() { - - org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey - nodeKey = newInvNodeKey("node1"); - - org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey ncKey = - newInvNodeConnKey("tp1"); - - InstanceIdentifier invNodeConnID = newNodeConnID(nodeKey, ncKey); - - List linkList = Arrays.asList(newLink("link1", newSourceTp("tp1"), newDestTp("dest"))); - Topology topology = new TopologyBuilder().setLink(linkList).build(); - - ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class); - doReturn(Futures.immediateCheckedFuture(Optional.of(topology))).when(mockTx) - .read(LogicalDatastoreType.OPERATIONAL, topologyIID); - setupStubbedSubmit(mockTx); - - CountDownLatch deleteLatch = new CountDownLatch(1); - ArgumentCaptor deletedLinkIDs = - ArgumentCaptor.forClass(InstanceIdentifier.class); - setupStubbedDeletes(mockTx, deletedLinkIDs, deleteLatch); - - doReturn(mockTx).when(mockTxChain).newReadWriteTransaction(); - - exporter.onNodeConnectorUpdated(new NodeConnectorUpdatedBuilder().setNodeConnectorRef( - new NodeConnectorRef(invNodeConnID)).setId(ncKey.getId()).addAugmentation( - FlowCapableNodeConnectorUpdated.class, - new FlowCapableNodeConnectorUpdatedBuilder().setConfiguration( - new PortConfig(true, true, true, true)).build()).build()); - - waitForDeletes(1, deleteLatch); - - InstanceIdentifier expTpPath = topologyIID.child( - Node.class, new NodeKey(new NodeId("node1"))).child(TerminationPoint.class, - new TerminationPointKey(new TpId("tp1"))); - - verify(mockTx).merge(eq(LogicalDatastoreType.OPERATIONAL), eq(expTpPath), - any(TerminationPoint.class), eq(true)); - - assertDeletedIDs(new InstanceIdentifier[]{topologyIID.child(Link.class, - linkList.get(0).getKey())}, deletedLinkIDs); - } @Test public void testOnLinkDiscovered() { @@ -618,115 +198,4 @@ public class FlowCapableTopologyExporterTest { Link.class, new LinkKey(new LinkId(sourceNodeConnKey.getId())))); } - private void verifyMockTx(ReadWriteTransaction mockTx) { - InOrder inOrder = inOrder(mockTx); - inOrder.verify(mockTx, atLeast(0)).submit(); - inOrder.verify(mockTx, never()).delete(eq(LogicalDatastoreType.OPERATIONAL), - any(InstanceIdentifier.class)); - } - - @SuppressWarnings("rawtypes") - private void assertDeletedIDs(InstanceIdentifier[] expDeletedIIDs, - ArgumentCaptor deletedLinkIDs) { - Set actualIIDs = new HashSet<>(deletedLinkIDs.getAllValues()); - for(InstanceIdentifier id: expDeletedIIDs) { - assertTrue("Missing expected deleted IID " + id, actualIIDs.contains(id)); - } - } - - private void setReadFutureAsync(final Topology topology, - final SettableFuture> readFuture) { - new Thread() { - @Override - public void run() { - Uninterruptibles.sleepUninterruptibly(50, TimeUnit.MILLISECONDS); - readFuture.set(Optional.of(topology)); - } - - }.start(); - } - - private void waitForSubmit(CountDownLatch latch) { - assertEquals("Transaction submitted", true, - Uninterruptibles.awaitUninterruptibly(latch, 5, TimeUnit.SECONDS)); - } - - private void waitForDeletes(int expDeleteCalls, final CountDownLatch latch) { - boolean done = Uninterruptibles.awaitUninterruptibly(latch, 5, TimeUnit.SECONDS); - if(!done) { - fail("Expected " + expDeleteCalls + " delete calls. Actual: " + - (expDeleteCalls - latch.getCount())); - } - } - - private CountDownLatch setupStubbedSubmit(ReadWriteTransaction mockTx) { - final CountDownLatch latch = new CountDownLatch(1); - doAnswer(new Answer>() { - @Override - public CheckedFuture answer( - InvocationOnMock invocation) { - latch.countDown(); - return Futures.immediateCheckedFuture(null); - } - }).when(mockTx).submit(); - - return latch; - } - - @SuppressWarnings("rawtypes") - private void setupStubbedDeletes(ReadWriteTransaction mockTx, - ArgumentCaptor deletedLinkIDs, final CountDownLatch latch) { - doAnswer(new Answer() { - @Override - public Void answer(InvocationOnMock invocation) { - latch.countDown(); - return null; - } - }).when(mockTx).delete(eq(LogicalDatastoreType.OPERATIONAL), deletedLinkIDs.capture()); - } - - private org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey - newInvNodeKey(String id) { - org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey nodeKey = - new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey( - new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory. - rev130819.NodeId(id)); - return nodeKey; - } - - private NodeConnectorKey newInvNodeConnKey(String id) { - return new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey( - new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819. - NodeConnectorId(id)); - } - - private KeyedInstanceIdentifier newNodeConnID( - org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey nodeKey, - org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey ncKey) { - return InstanceIdentifier.create(Nodes.class).child( - org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, - nodeKey).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory. - rev130819.node.NodeConnector.class, ncKey); - } - - private Link newLink(String id, Source source, Destination dest) { - return new LinkBuilder().setLinkId(new LinkId(id)) - .setSource(source).setDestination(dest).build(); - } - - private Destination newDestTp(String id) { - return new DestinationBuilder().setDestTp(new TpId(id)).build(); - } - - private Source newSourceTp(String id) { - return new SourceBuilder().setSourceTp(new TpId(id)).build(); - } - - private Destination newDestNode(String id) { - return new DestinationBuilder().setDestNode(new NodeId(id)).build(); - } - - private Source newSourceNode(String id) { - return new SourceBuilder().setSourceNode(new NodeId(id)).build(); - } } diff --git a/applications/topology-manager/src/test/java/org/opendaylight/openflowplugin/applications/topology/manager/NodeChangeListenerImplTest.java b/applications/topology-manager/src/test/java/org/opendaylight/openflowplugin/applications/topology/manager/NodeChangeListenerImplTest.java new file mode 100644 index 0000000000..2c8a260130 --- /dev/null +++ b/applications/topology-manager/src/test/java/org/opendaylight/openflowplugin/applications/topology/manager/NodeChangeListenerImplTest.java @@ -0,0 +1,184 @@ +/** + * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * 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.openflowplugin.applications.topology.manager; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.opendaylight.openflowplugin.applications.topology.manager.TestUtils.*; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.topology.inventory.rev131030.InventoryNode; +import org.opendaylight.yangtools.yang.binding.DataObject; + +import com.google.common.base.Optional; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.SettableFuture; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId; +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.TopologyBuilder; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * @author joe + * + */ +public class NodeChangeListenerImplTest extends DataChangeListenerBase { + @SuppressWarnings({ "rawtypes" }) + @Test + public void testOnNodeRemoved() { + + NodeKey topoNodeKey = new NodeKey(new NodeId("node1")); + InstanceIdentifier topoNodeII = topologyIID.child(Node.class, topoNodeKey); + Node topoNode = new NodeBuilder().setKey(topoNodeKey).build(); + + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey + nodeKey = newInvNodeKey(topoNodeKey.getNodeId().getValue()); + InstanceIdentifier invNodeID = InstanceIdentifier.create(Nodes.class).child( + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, + nodeKey); + + List linkList = Arrays.asList( + newLink("link1", newSourceNode("node1"), newDestNode("dest")), + newLink("link2", newSourceNode("source"), newDestNode("node1")), + newLink("link2", newSourceNode("source2"), newDestNode("dest2"))); + final Topology topology = new TopologyBuilder().setLink(linkList).build(); + + InstanceIdentifier[] expDeletedIIDs = { + topologyIID.child(Link.class, linkList.get(0).getKey()), + topologyIID.child(Link.class, linkList.get(1).getKey()), + topologyIID.child(Node.class, new NodeKey(new NodeId("node1"))) + }; + + SettableFuture> readFuture = SettableFuture.create(); + readFuture.set(Optional.of(topology)); + ReadWriteTransaction mockTx1 = mock(ReadWriteTransaction.class); + doReturn(Futures.makeChecked(readFuture, ReadFailedException.MAPPER)).when(mockTx1) + .read(LogicalDatastoreType.OPERATIONAL, topologyIID); + + SettableFuture> readFutureNode = SettableFuture.create(); + readFutureNode.set(Optional.of(topoNode)); + doReturn(Futures.makeChecked(readFutureNode, ReadFailedException.MAPPER)).when(mockTx1) + .read(LogicalDatastoreType.OPERATIONAL, topoNodeII); + + CountDownLatch submitLatch1 = setupStubbedSubmit(mockTx1); + + int expDeleteCalls = expDeletedIIDs.length; + CountDownLatch deleteLatch = new CountDownLatch(expDeleteCalls); + ArgumentCaptor deletedLinkIDs = + ArgumentCaptor.forClass(InstanceIdentifier.class); + setupStubbedDeletes(mockTx1, deletedLinkIDs, deleteLatch); + + doReturn(mockTx1).when(mockTxChain).newReadWriteTransaction(); + + mockDataChangeListener(null, null, Collections.singleton(invNodeID)); + nodeChangeListener.onDataChanged(mockedDataChangeListener); + + waitForSubmit(submitLatch1); + + setReadFutureAsync(topology, readFuture); + + waitForDeletes(expDeleteCalls, deleteLatch); + + assertDeletedIDs(expDeletedIIDs, deletedLinkIDs); + + verifyMockTx(mockTx1); + } + + @SuppressWarnings({ "rawtypes" }) + @Test + public void testOnNodeRemovedWithNoTopology() { + + NodeKey topoNodeKey = new NodeKey(new NodeId("node1")); + InstanceIdentifier topoNodeII = topologyIID.child(Node.class, topoNodeKey); + Node topoNode = new NodeBuilder().setKey(topoNodeKey).build(); + + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey + nodeKey = newInvNodeKey(topoNodeKey.getNodeId().getValue()); + InstanceIdentifier invNodeID = InstanceIdentifier.create(Nodes.class).child( + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, + nodeKey); + + InstanceIdentifier[] expDeletedIIDs = { + topologyIID.child(Node.class, new NodeKey(new NodeId("node1"))) + }; + + ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class); + doReturn(Futures.immediateCheckedFuture(Optional.absent())).when(mockTx) + .read(LogicalDatastoreType.OPERATIONAL, topologyIID); + CountDownLatch submitLatch = setupStubbedSubmit(mockTx); + + SettableFuture> readFutureNode = SettableFuture.create(); + readFutureNode.set(Optional.of(topoNode)); + doReturn(Futures.makeChecked(readFutureNode, ReadFailedException.MAPPER)).when(mockTx) + .read(LogicalDatastoreType.OPERATIONAL, topoNodeII); + + CountDownLatch deleteLatch = new CountDownLatch(1); + ArgumentCaptor deletedLinkIDs = + ArgumentCaptor.forClass(InstanceIdentifier.class); + setupStubbedDeletes(mockTx, deletedLinkIDs, deleteLatch); + + doReturn(mockTx).when(mockTxChain).newReadWriteTransaction(); + + mockDataChangeListener(null,null,Collections.singleton(invNodeID)); + nodeChangeListener.onDataChanged(mockedDataChangeListener); + + waitForSubmit(submitLatch); + + waitForDeletes(1, deleteLatch); + + assertDeletedIDs(expDeletedIIDs, deletedLinkIDs); + } + + @Test + public void testOnNodeAdded() { + + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey + nodeKey = newInvNodeKey("node1"); + InstanceIdentifier invNodeID = InstanceIdentifier.create(Nodes.class).child( + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, + nodeKey); + + ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class); + CountDownLatch submitLatch = setupStubbedSubmit(mockTx); + doReturn(mockTx).when(mockTxChain).newReadWriteTransaction(); + + mockDataChangeListener(Collections., DataObject> singletonMap( + invNodeID, null), null, null); + nodeChangeListener.onDataChanged(mockedDataChangeListener); + + waitForSubmit(submitLatch); + + ArgumentCaptor mergedNode = ArgumentCaptor.forClass(Node.class); + NodeId expNodeId = new NodeId("node1"); + verify(mockTx).merge(eq(LogicalDatastoreType.OPERATIONAL), eq(topologyIID.child(Node.class, + new NodeKey(expNodeId))), mergedNode.capture(), eq(true)); + assertEquals("getNodeId", expNodeId, mergedNode.getValue().getNodeId()); + InventoryNode augmentation = mergedNode.getValue().getAugmentation(InventoryNode.class); + assertNotNull("Missing augmentation", augmentation); + assertEquals("getInventoryNodeRef", new NodeRef(invNodeID), augmentation.getInventoryNodeRef()); + } + +} diff --git a/applications/topology-manager/src/test/java/org/opendaylight/openflowplugin/applications/topology/manager/TerminationPointChangeListenerImplTest.java b/applications/topology-manager/src/test/java/org/opendaylight/openflowplugin/applications/topology/manager/TerminationPointChangeListenerImplTest.java new file mode 100644 index 0000000000..8f46f13128 --- /dev/null +++ b/applications/topology-manager/src/test/java/org/opendaylight/openflowplugin/applications/topology/manager/TerminationPointChangeListenerImplTest.java @@ -0,0 +1,293 @@ +/** + * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * 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.openflowplugin.applications.topology.manager; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.opendaylight.openflowplugin.applications.topology.manager.TestUtils.*; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.model.topology.inventory.rev131030.InventoryNodeConnector; +import org.opendaylight.yangtools.yang.binding.DataObject; + +import com.google.common.base.Optional; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.SettableFuture; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId; +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.TopologyBuilder; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * @author joe + * + */ +public class TerminationPointChangeListenerImplTest extends DataChangeListenerBase{ + @SuppressWarnings("rawtypes") + @Test + public void testOnNodeConnectorRemoved() { + + NodeKey topoNodeKey = new NodeKey(new NodeId("node1")); + TerminationPointKey terminationPointKey = new TerminationPointKey(new TpId("tp1")); + + InstanceIdentifier topoNodeII = topologyIID.child(Node.class, topoNodeKey); + Node topoNode = new NodeBuilder().setKey(topoNodeKey).build(); + + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey + nodeKey = newInvNodeKey(topoNodeKey.getNodeId().getValue()); + + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey ncKey = + newInvNodeConnKey(terminationPointKey.getTpId().getValue()); + + InstanceIdentifier invNodeConnID = newNodeConnID(nodeKey, ncKey); + + List linkList = Arrays.asList( + newLink("link1", newSourceTp("tp1"), newDestTp("dest")), + newLink("link2", newSourceTp("source"), newDestTp("tp1")), + newLink("link3", newSourceTp("source2"), newDestTp("dest2"))); + final Topology topology = new TopologyBuilder().setLink(linkList).build(); + + InstanceIdentifier[] expDeletedIIDs = { + topologyIID.child(Link.class, linkList.get(0).getKey()), + topologyIID.child(Link.class, linkList.get(1).getKey()), + topologyIID.child(Node.class, new NodeKey(new NodeId("node1"))) + .child(TerminationPoint.class, new TerminationPointKey(new TpId("tp1"))) + }; + + final SettableFuture> readFuture = SettableFuture.create(); + readFuture.set(Optional.of(topology)); + ReadWriteTransaction mockTx1 = mock(ReadWriteTransaction.class); + doReturn(Futures.makeChecked(readFuture, ReadFailedException.MAPPER)).when(mockTx1) + .read(LogicalDatastoreType.OPERATIONAL, topologyIID); + + SettableFuture> readFutureNode = SettableFuture.create(); + readFutureNode.set(Optional.of(topoNode)); + doReturn(Futures.makeChecked(readFutureNode, ReadFailedException.MAPPER)).when(mockTx1) + .read(LogicalDatastoreType.OPERATIONAL, topoNodeII); + + CountDownLatch submitLatch1 = setupStubbedSubmit(mockTx1); + + int expDeleteCalls = expDeletedIIDs.length; + CountDownLatch deleteLatch = new CountDownLatch(expDeleteCalls); + ArgumentCaptor deletedLinkIDs = + ArgumentCaptor.forClass(InstanceIdentifier.class); + setupStubbedDeletes(mockTx1, deletedLinkIDs, deleteLatch); + + doReturn(mockTx1).when(mockTxChain).newReadWriteTransaction(); + + mockDataChangeListener(null, null, Collections.singleton(invNodeConnID)); + terminationPointListener.onDataChanged(mockedDataChangeListener); + + waitForSubmit(submitLatch1); + + setReadFutureAsync(topology, readFuture); + + waitForDeletes(expDeleteCalls, deleteLatch); + + assertDeletedIDs(expDeletedIIDs, deletedLinkIDs); + + verifyMockTx(mockTx1); + } + + @SuppressWarnings("rawtypes") + @Test + public void testOnNodeConnectorRemovedWithNoTopology() { + + NodeKey topoNodeKey = new NodeKey(new NodeId("node1")); + TerminationPointKey terminationPointKey = new TerminationPointKey(new TpId("tp1")); + + InstanceIdentifier topoNodeII = topologyIID.child(Node.class, topoNodeKey); + Node topoNode = new NodeBuilder().setKey(topoNodeKey).build(); + + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey + nodeKey = newInvNodeKey(topoNodeKey.getNodeId().getValue()); + + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey ncKey = + newInvNodeConnKey(terminationPointKey.getTpId().getValue()); + + InstanceIdentifier invNodeConnID = newNodeConnID(nodeKey, ncKey); + + InstanceIdentifier[] expDeletedIIDs = { + topologyIID.child(Node.class, new NodeKey(new NodeId("node1"))) + .child(TerminationPoint.class, new TerminationPointKey(new TpId("tp1"))) + }; + + ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class); + doReturn(Futures.immediateCheckedFuture(Optional.absent())).when(mockTx) + .read(LogicalDatastoreType.OPERATIONAL, topologyIID); + CountDownLatch submitLatch = setupStubbedSubmit(mockTx); + + SettableFuture> readFutureNode = SettableFuture.create(); + readFutureNode.set(Optional.of(topoNode)); + doReturn(Futures.makeChecked(readFutureNode, ReadFailedException.MAPPER)).when(mockTx) + .read(LogicalDatastoreType.OPERATIONAL, topoNodeII); + + CountDownLatch deleteLatch = new CountDownLatch(1); + ArgumentCaptor deletedLinkIDs = + ArgumentCaptor.forClass(InstanceIdentifier.class); + setupStubbedDeletes(mockTx, deletedLinkIDs, deleteLatch); + + doReturn(mockTx).when(mockTxChain).newReadWriteTransaction(); + + mockDataChangeListener(null, null, Collections.singleton(invNodeConnID)); + terminationPointListener.onDataChanged(mockedDataChangeListener); + + waitForSubmit(submitLatch); + + waitForDeletes(1, deleteLatch); + + assertDeletedIDs(expDeletedIIDs, deletedLinkIDs); + } + + @Test + public void testOnNodeConnectorUpdated() { + + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey + nodeKey = newInvNodeKey("node1"); + + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey ncKey = + newInvNodeConnKey("tp1"); + + InstanceIdentifier invNodeConnID = newNodeConnID(nodeKey, ncKey); + + ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class); + CountDownLatch submitLatch = setupStubbedSubmit(mockTx); + doReturn(mockTx).when(mockTxChain).newReadWriteTransaction(); + + mockDataChangeListener(Collections., DataObject> singletonMap( + invNodeConnID, null), null, null); + terminationPointListener.onDataChanged(mockedDataChangeListener); + + waitForSubmit(submitLatch); + + ArgumentCaptor mergedNode = ArgumentCaptor.forClass(TerminationPoint.class); + NodeId expNodeId = new NodeId("node1"); + TpId expTpId = new TpId("tp1"); + InstanceIdentifier expTpPath = topologyIID.child( + Node.class, new NodeKey(expNodeId)).child(TerminationPoint.class, + new TerminationPointKey(expTpId)); + verify(mockTx).merge(eq(LogicalDatastoreType.OPERATIONAL), eq(expTpPath), + mergedNode.capture(), eq(true)); + assertEquals("getTpId", expTpId, mergedNode.getValue().getTpId()); + InventoryNodeConnector augmentation = mergedNode.getValue().getAugmentation( + InventoryNodeConnector.class); + assertNotNull("Missing augmentation", augmentation); + assertEquals("getInventoryNodeConnectorRef", new NodeConnectorRef(invNodeConnID), + augmentation.getInventoryNodeConnectorRef()); + } + + @SuppressWarnings("rawtypes") + @Test + public void testOnNodeConnectorUpdatedWithLinkStateDown() { + + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey + nodeKey = newInvNodeKey("node1"); + + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey ncKey = + newInvNodeConnKey("tp1"); + + InstanceIdentifier invNodeConnID = newNodeConnID(nodeKey, ncKey); + + List linkList = Arrays.asList(newLink("link1", newSourceTp("tp1"), newDestTp("dest"))); + Topology topology = new TopologyBuilder().setLink(linkList).build(); + + ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class); + doReturn(Futures.immediateCheckedFuture(Optional.of(topology))).when(mockTx) + .read(LogicalDatastoreType.OPERATIONAL, topologyIID); + setupStubbedSubmit(mockTx); + + CountDownLatch deleteLatch = new CountDownLatch(1); + ArgumentCaptor deletedLinkIDs = + ArgumentCaptor.forClass(InstanceIdentifier.class); + setupStubbedDeletes(mockTx, deletedLinkIDs, deleteLatch); + + doReturn(mockTx).when(mockTxChain).newReadWriteTransaction(); + + mockDataChangeListener(Collections., DataObject> singletonMap( + invNodeConnID, provideFlowCapableNodeConnector(true, false)), null, null); + terminationPointListener.onDataChanged(mockedDataChangeListener); + + waitForDeletes(1, deleteLatch); + + InstanceIdentifier expTpPath = topologyIID.child( + Node.class, new NodeKey(new NodeId("node1"))).child(TerminationPoint.class, + new TerminationPointKey(new TpId("tp1"))); + + verify(mockTx).merge(eq(LogicalDatastoreType.OPERATIONAL), eq(expTpPath), + any(TerminationPoint.class), eq(true)); + + assertDeletedIDs(new InstanceIdentifier[]{topologyIID.child(Link.class, + linkList.get(0).getKey())}, deletedLinkIDs); + } + + + @SuppressWarnings("rawtypes") + @Test + public void testOnNodeConnectorUpdatedWithPortDown() { + + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey + nodeKey = newInvNodeKey("node1"); + + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey ncKey = + newInvNodeConnKey("tp1"); + + InstanceIdentifier invNodeConnID = newNodeConnID(nodeKey, ncKey); + + List linkList = Arrays.asList(newLink("link1", newSourceTp("tp1"), newDestTp("dest"))); + Topology topology = new TopologyBuilder().setLink(linkList).build(); + + ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class); + doReturn(Futures.immediateCheckedFuture(Optional.of(topology))).when(mockTx) + .read(LogicalDatastoreType.OPERATIONAL, topologyIID); + setupStubbedSubmit(mockTx); + + CountDownLatch deleteLatch = new CountDownLatch(1); + ArgumentCaptor deletedLinkIDs = + ArgumentCaptor.forClass(InstanceIdentifier.class); + setupStubbedDeletes(mockTx, deletedLinkIDs, deleteLatch); + + doReturn(mockTx).when(mockTxChain).newReadWriteTransaction(); + + mockDataChangeListener(Collections., DataObject> singletonMap( + invNodeConnID, provideFlowCapableNodeConnector(false, true)), null, null); + terminationPointListener.onDataChanged(mockedDataChangeListener); + + waitForDeletes(1, deleteLatch); + + InstanceIdentifier expTpPath = topologyIID.child( + Node.class, new NodeKey(new NodeId("node1"))).child(TerminationPoint.class, + new TerminationPointKey(new TpId("tp1"))); + + verify(mockTx).merge(eq(LogicalDatastoreType.OPERATIONAL), eq(expTpPath), + any(TerminationPoint.class), eq(true)); + + assertDeletedIDs(new InstanceIdentifier[]{topologyIID.child(Link.class, + linkList.get(0).getKey())}, deletedLinkIDs); + } +} diff --git a/applications/topology-manager/src/test/java/org/opendaylight/openflowplugin/applications/topology/manager/TestUtils.java b/applications/topology-manager/src/test/java/org/opendaylight/openflowplugin/applications/topology/manager/TestUtils.java new file mode 100644 index 0000000000..da5f80e113 --- /dev/null +++ b/applications/topology-manager/src/test/java/org/opendaylight/openflowplugin/applications/topology/manager/TestUtils.java @@ -0,0 +1,165 @@ +/** + * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * 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.openflowplugin.applications.topology.manager; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.atLeast; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.never; + +import com.google.common.base.Optional; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.SettableFuture; +import com.google.common.util.concurrent.Uninterruptibles; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import org.mockito.ArgumentCaptor; +import org.mockito.InOrder; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +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.node.NodeConnectorKey; +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.NodeId; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.Destination; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.DestinationBuilder; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.Source; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.SourceBuilder; +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.topology.Link; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.LinkBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; + +public class TestUtils { + static void verifyMockTx(ReadWriteTransaction mockTx) { + InOrder inOrder = inOrder(mockTx); + inOrder.verify(mockTx, atLeast(0)).submit(); + inOrder.verify(mockTx, never()).delete(eq(LogicalDatastoreType.OPERATIONAL), + any(InstanceIdentifier.class)); + } + + @SuppressWarnings("rawtypes") + static void assertDeletedIDs(InstanceIdentifier[] expDeletedIIDs, + ArgumentCaptor deletedLinkIDs) { + Set actualIIDs = new HashSet<>(deletedLinkIDs.getAllValues()); + for(InstanceIdentifier id: expDeletedIIDs) { + assertTrue("Missing expected deleted IID " + id, actualIIDs.contains(id)); + } + } + + static void setReadFutureAsync(final Topology topology, + final SettableFuture> readFuture) { + new Thread() { + @Override + public void run() { + Uninterruptibles.sleepUninterruptibly(50, TimeUnit.MILLISECONDS); + readFuture.set(Optional.of(topology)); + } + + }.start(); + } + + static void waitForSubmit(CountDownLatch latch) { + assertEquals("Transaction submitted", true, + Uninterruptibles.awaitUninterruptibly(latch, 5, TimeUnit.SECONDS)); + } + + static void waitForDeletes(int expDeleteCalls, final CountDownLatch latch) { + boolean done = Uninterruptibles.awaitUninterruptibly(latch, 5, TimeUnit.SECONDS); + if(!done) { + fail("Expected " + expDeleteCalls + " delete calls. Actual: " + + (expDeleteCalls - latch.getCount())); + } + } + + static CountDownLatch setupStubbedSubmit(ReadWriteTransaction mockTx) { + final CountDownLatch latch = new CountDownLatch(1); + doAnswer(new Answer>() { + @Override + public CheckedFuture answer( + InvocationOnMock invocation) { + latch.countDown(); + return Futures.immediateCheckedFuture(null); + } + }).when(mockTx).submit(); + + return latch; + } + + @SuppressWarnings("rawtypes") + static void setupStubbedDeletes(ReadWriteTransaction mockTx, + ArgumentCaptor deletedLinkIDs, final CountDownLatch latch) { + doAnswer(new Answer() { + @Override + public Void answer(InvocationOnMock invocation) { + latch.countDown(); + return null; + } + }).when(mockTx).delete(eq(LogicalDatastoreType.OPERATIONAL), deletedLinkIDs.capture()); + } + + static org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey + newInvNodeKey(String id) { + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey nodeKey = + new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey( + new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory. + rev130819.NodeId(id)); + return nodeKey; + } + + static NodeConnectorKey newInvNodeConnKey(String id) { + return new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey( + new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819. + NodeConnectorId(id)); + } + + static KeyedInstanceIdentifier newNodeConnID( + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey nodeKey, + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey ncKey) { + return InstanceIdentifier.create(Nodes.class).child( + org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, + nodeKey).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory. + rev130819.node.NodeConnector.class, ncKey); + } + + static Link newLink(String id, Source source, Destination dest) { + return new LinkBuilder().setLinkId(new LinkId(id)) + .setSource(source).setDestination(dest).build(); + } + + static Destination newDestTp(String id) { + return new DestinationBuilder().setDestTp(new TpId(id)).build(); + } + + static Source newSourceTp(String id) { + return new SourceBuilder().setSourceTp(new TpId(id)).build(); + } + + static Destination newDestNode(String id) { + return new DestinationBuilder().setDestNode(new NodeId(id)).build(); + } + + static Source newSourceNode(String id) { + return new SourceBuilder().setSourceNode(new NodeId(id)).build(); + } + +} -- 2.36.6