2 * Copyright (c) 2014 Brocade Communications Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.openflowplugin.applications.topology.manager;
11 import com.google.common.base.Optional;
12 import com.google.common.util.concurrent.CheckedFuture;
13 import com.google.common.util.concurrent.Futures;
14 import com.google.common.util.concurrent.SettableFuture;
15 import com.google.common.util.concurrent.Uninterruptibles;
17 import org.junit.After;
18 import org.junit.Before;
19 import org.junit.Test;
20 import org.mockito.ArgumentCaptor;
21 import org.mockito.InOrder;
22 import org.mockito.Mock;
23 import org.mockito.MockitoAnnotations;
24 import org.mockito.invocation.InvocationOnMock;
25 import org.mockito.stubbing.Answer;
26 import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
27 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
28 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
29 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
30 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
31 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
32 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
33 import org.opendaylight.openflowplugin.applications.topology.manager.FlowCapableTopologyExporter;
34 import org.opendaylight.openflowplugin.applications.topology.manager.OperationProcessor;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorUpdated;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorUpdatedBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeUpdated;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeUpdatedBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.LinkDiscoveredBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.LinkRemovedBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortConfig;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.flow.capable.port.StateBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRemovedBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorUpdatedBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRemovedBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeUpdatedBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.topology.inventory.rev131030.InventoryNode;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.topology.inventory.rev131030.InventoryNodeConnector;
54 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.LinkId;
55 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
56 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
57 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
58 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId;
59 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.Destination;
60 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.DestinationBuilder;
61 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.Source;
62 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.SourceBuilder;
63 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
64 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder;
65 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
66 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link;
67 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.LinkBuilder;
68 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.LinkKey;
69 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
70 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
71 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
72 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
73 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
74 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
75 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
77 import java.util.Arrays;
78 import java.util.HashSet;
79 import java.util.List;
81 import java.util.concurrent.CountDownLatch;
82 import java.util.concurrent.ExecutorService;
83 import java.util.concurrent.Executors;
84 import java.util.concurrent.TimeUnit;
86 import static org.junit.Assert.assertEquals;
87 import static org.junit.Assert.assertNotNull;
88 import static org.junit.Assert.assertTrue;
89 import static org.junit.Assert.fail;
90 import static org.mockito.Mockito.any;
91 import static org.mockito.Mockito.atLeast;
92 import static org.mockito.Mockito.doAnswer;
93 import static org.mockito.Mockito.doReturn;
94 import static org.mockito.Mockito.eq;
95 import static org.mockito.Mockito.inOrder;
96 import static org.mockito.Mockito.mock;
97 import static org.mockito.Mockito.never;
98 import static org.mockito.Mockito.verify;
100 public class FlowCapableTopologyExporterTest {
103 private DataBroker mockDataBroker;
106 private BindingTransactionChain mockTxChain;
108 private OperationProcessor processor;
110 private FlowCapableTopologyExporter exporter;
112 private InstanceIdentifier<Topology> topologyIID;
114 private final ExecutorService executor = Executors.newFixedThreadPool(1);
117 public void setUp() {
118 MockitoAnnotations.initMocks(this);
120 doReturn(mockTxChain).when(mockDataBroker)
121 .createTransactionChain(any(TransactionChainListener.class));
123 processor = new OperationProcessor(mockDataBroker);
125 topologyIID = InstanceIdentifier.create(NetworkTopology.class)
126 .child(Topology.class, new TopologyKey(new TopologyId("test")));
127 exporter = new FlowCapableTopologyExporter(processor, topologyIID);
129 executor.execute(processor);
133 public void tearDown() {
134 executor.shutdownNow();
137 @SuppressWarnings({ "rawtypes" })
139 public void testOnNodeRemoved() {
141 NodeKey topoNodeKey = new NodeKey(new NodeId("node1"));
142 InstanceIdentifier<Node> topoNodeII = topologyIID.child(Node.class, topoNodeKey);
143 Node topoNode = new NodeBuilder().setKey(topoNodeKey).build();
145 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
146 nodeKey = newInvNodeKey(topoNodeKey.getNodeId().getValue());
147 InstanceIdentifier<?> invNodeID = InstanceIdentifier.create(Nodes.class).child(
148 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
151 List<Link> linkList = Arrays.asList(
152 newLink("link1", newSourceNode("node1"), newDestNode("dest")),
153 newLink("link2", newSourceNode("source"), newDestNode("node1")),
154 newLink("link2", newSourceNode("source2"), newDestNode("dest2")));
155 final Topology topology = new TopologyBuilder().setLink(linkList).build();
157 InstanceIdentifier[] expDeletedIIDs = {
158 topologyIID.child(Link.class, linkList.get(0).getKey()),
159 topologyIID.child(Link.class, linkList.get(1).getKey()),
160 topologyIID.child(Node.class, new NodeKey(new NodeId("node1")))
163 SettableFuture<Optional<Topology>> readFuture = SettableFuture.create();
164 readFuture.set(Optional.of(topology));
165 ReadWriteTransaction mockTx1 = mock(ReadWriteTransaction.class);
166 doReturn(Futures.makeChecked(readFuture, ReadFailedException.MAPPER)).when(mockTx1)
167 .read(LogicalDatastoreType.OPERATIONAL, topologyIID);
169 SettableFuture<Optional<Node>> readFutureNode = SettableFuture.create();
170 readFutureNode.set(Optional.of(topoNode));
171 doReturn(Futures.makeChecked(readFutureNode, ReadFailedException.MAPPER)).when(mockTx1)
172 .read(LogicalDatastoreType.OPERATIONAL, topoNodeII);
174 CountDownLatch submitLatch1 = setupStubbedSubmit(mockTx1);
176 int expDeleteCalls = expDeletedIIDs.length;
177 CountDownLatch deleteLatch = new CountDownLatch(expDeleteCalls);
178 ArgumentCaptor<InstanceIdentifier> deletedLinkIDs =
179 ArgumentCaptor.forClass(InstanceIdentifier.class);
180 setupStubbedDeletes(mockTx1, deletedLinkIDs, deleteLatch);
182 doReturn(mockTx1).when(mockTxChain).newReadWriteTransaction();
184 exporter.onNodeRemoved(new NodeRemovedBuilder().setNodeRef(new NodeRef(invNodeID)).build());
186 waitForSubmit(submitLatch1);
188 setReadFutureAsync(topology, readFuture);
190 waitForDeletes(expDeleteCalls, deleteLatch);
192 assertDeletedIDs(expDeletedIIDs, deletedLinkIDs);
194 verifyMockTx(mockTx1);
197 @SuppressWarnings({ "rawtypes" })
199 public void testOnNodeRemovedWithNoTopology() {
201 NodeKey topoNodeKey = new NodeKey(new NodeId("node1"));
202 InstanceIdentifier<Node> topoNodeII = topologyIID.child(Node.class, topoNodeKey);
203 Node topoNode = new NodeBuilder().setKey(topoNodeKey).build();
205 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
206 nodeKey = newInvNodeKey(topoNodeKey.getNodeId().getValue());
207 InstanceIdentifier<?> invNodeID = InstanceIdentifier.create(Nodes.class).child(
208 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
211 InstanceIdentifier[] expDeletedIIDs = {
212 topologyIID.child(Node.class, new NodeKey(new NodeId("node1")))
215 ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class);
216 doReturn(Futures.immediateCheckedFuture(Optional.absent())).when(mockTx)
217 .read(LogicalDatastoreType.OPERATIONAL, topologyIID);
218 CountDownLatch submitLatch = setupStubbedSubmit(mockTx);
220 SettableFuture<Optional<Node>> readFutureNode = SettableFuture.create();
221 readFutureNode.set(Optional.of(topoNode));
222 doReturn(Futures.makeChecked(readFutureNode, ReadFailedException.MAPPER)).when(mockTx)
223 .read(LogicalDatastoreType.OPERATIONAL, topoNodeII);
225 CountDownLatch deleteLatch = new CountDownLatch(1);
226 ArgumentCaptor<InstanceIdentifier> deletedLinkIDs =
227 ArgumentCaptor.forClass(InstanceIdentifier.class);
228 setupStubbedDeletes(mockTx, deletedLinkIDs, deleteLatch);
230 doReturn(mockTx).when(mockTxChain).newReadWriteTransaction();
232 exporter.onNodeRemoved(new NodeRemovedBuilder().setNodeRef(new NodeRef(invNodeID)).build());
234 waitForSubmit(submitLatch);
236 waitForDeletes(1, deleteLatch);
238 assertDeletedIDs(expDeletedIIDs, deletedLinkIDs);
241 @SuppressWarnings("rawtypes")
243 public void testOnNodeConnectorRemoved() {
245 NodeKey topoNodeKey = new NodeKey(new NodeId("node1"));
246 TerminationPointKey terminationPointKey = new TerminationPointKey(new TpId("tp1"));
248 InstanceIdentifier<Node> topoNodeII = topologyIID.child(Node.class, topoNodeKey);
249 Node topoNode = new NodeBuilder().setKey(topoNodeKey).build();
251 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
252 nodeKey = newInvNodeKey(topoNodeKey.getNodeId().getValue());
254 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey ncKey =
255 newInvNodeConnKey(terminationPointKey.getTpId().getValue());
257 InstanceIdentifier<?> invNodeConnID = newNodeConnID(nodeKey, ncKey);
259 List<Link> linkList = Arrays.asList(
260 newLink("link1", newSourceTp("tp1"), newDestTp("dest")),
261 newLink("link2", newSourceTp("source"), newDestTp("tp1")),
262 newLink("link3", newSourceTp("source2"), newDestTp("dest2")));
263 final Topology topology = new TopologyBuilder().setLink(linkList).build();
265 InstanceIdentifier[] expDeletedIIDs = {
266 topologyIID.child(Link.class, linkList.get(0).getKey()),
267 topologyIID.child(Link.class, linkList.get(1).getKey()),
268 topologyIID.child(Node.class, new NodeKey(new NodeId("node1")))
269 .child(TerminationPoint.class, new TerminationPointKey(new TpId("tp1")))
272 final SettableFuture<Optional<Topology>> readFuture = SettableFuture.create();
273 readFuture.set(Optional.of(topology));
274 ReadWriteTransaction mockTx1 = mock(ReadWriteTransaction.class);
275 doReturn(Futures.makeChecked(readFuture, ReadFailedException.MAPPER)).when(mockTx1)
276 .read(LogicalDatastoreType.OPERATIONAL, topologyIID);
278 SettableFuture<Optional<Node>> readFutureNode = SettableFuture.create();
279 readFutureNode.set(Optional.of(topoNode));
280 doReturn(Futures.makeChecked(readFutureNode, ReadFailedException.MAPPER)).when(mockTx1)
281 .read(LogicalDatastoreType.OPERATIONAL, topoNodeII);
283 CountDownLatch submitLatch1 = setupStubbedSubmit(mockTx1);
285 int expDeleteCalls = expDeletedIIDs.length;
286 CountDownLatch deleteLatch = new CountDownLatch(expDeleteCalls);
287 ArgumentCaptor<InstanceIdentifier> deletedLinkIDs =
288 ArgumentCaptor.forClass(InstanceIdentifier.class);
289 setupStubbedDeletes(mockTx1, deletedLinkIDs, deleteLatch);
291 doReturn(mockTx1).when(mockTxChain).newReadWriteTransaction();
293 exporter.onNodeConnectorRemoved(new NodeConnectorRemovedBuilder().setNodeConnectorRef(
294 new NodeConnectorRef(invNodeConnID)).build());
296 waitForSubmit(submitLatch1);
298 setReadFutureAsync(topology, readFuture);
300 waitForDeletes(expDeleteCalls, deleteLatch);
302 assertDeletedIDs(expDeletedIIDs, deletedLinkIDs);
304 verifyMockTx(mockTx1);
307 @SuppressWarnings("rawtypes")
309 public void testOnNodeConnectorRemovedWithNoTopology() {
311 NodeKey topoNodeKey = new NodeKey(new NodeId("node1"));
312 TerminationPointKey terminationPointKey = new TerminationPointKey(new TpId("tp1"));
314 InstanceIdentifier<Node> topoNodeII = topologyIID.child(Node.class, topoNodeKey);
315 Node topoNode = new NodeBuilder().setKey(topoNodeKey).build();
317 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
318 nodeKey = newInvNodeKey(topoNodeKey.getNodeId().getValue());
320 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey ncKey =
321 newInvNodeConnKey(terminationPointKey.getTpId().getValue());
323 InstanceIdentifier<?> invNodeConnID = newNodeConnID(nodeKey, ncKey);
325 InstanceIdentifier[] expDeletedIIDs = {
326 topologyIID.child(Node.class, new NodeKey(new NodeId("node1")))
327 .child(TerminationPoint.class, new TerminationPointKey(new TpId("tp1")))
330 ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class);
331 doReturn(Futures.immediateCheckedFuture(Optional.absent())).when(mockTx)
332 .read(LogicalDatastoreType.OPERATIONAL, topologyIID);
333 CountDownLatch submitLatch = setupStubbedSubmit(mockTx);
335 SettableFuture<Optional<Node>> readFutureNode = SettableFuture.create();
336 readFutureNode.set(Optional.of(topoNode));
337 doReturn(Futures.makeChecked(readFutureNode, ReadFailedException.MAPPER)).when(mockTx)
338 .read(LogicalDatastoreType.OPERATIONAL, topoNodeII);
340 CountDownLatch deleteLatch = new CountDownLatch(1);
341 ArgumentCaptor<InstanceIdentifier> deletedLinkIDs =
342 ArgumentCaptor.forClass(InstanceIdentifier.class);
343 setupStubbedDeletes(mockTx, deletedLinkIDs, deleteLatch);
345 doReturn(mockTx).when(mockTxChain).newReadWriteTransaction();
347 exporter.onNodeConnectorRemoved(new NodeConnectorRemovedBuilder().setNodeConnectorRef(
348 new NodeConnectorRef(invNodeConnID)).build());
350 waitForSubmit(submitLatch);
352 waitForDeletes(1, deleteLatch);
354 assertDeletedIDs(expDeletedIIDs, deletedLinkIDs);
358 public void testOnNodeUpdated() {
360 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
361 nodeKey = newInvNodeKey("node1");
362 InstanceIdentifier<?> invNodeID = InstanceIdentifier.create(Nodes.class).child(
363 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
366 ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class);
367 CountDownLatch submitLatch = setupStubbedSubmit(mockTx);
368 doReturn(mockTx).when(mockTxChain).newReadWriteTransaction();
370 exporter.onNodeUpdated(new NodeUpdatedBuilder().setNodeRef(new NodeRef(invNodeID))
371 .setId(nodeKey.getId()).addAugmentation(FlowCapableNodeUpdated.class,
372 new FlowCapableNodeUpdatedBuilder().build()).build());
374 waitForSubmit(submitLatch);
376 ArgumentCaptor<Node> mergedNode = ArgumentCaptor.forClass(Node.class);
377 NodeId expNodeId = new NodeId("node1");
378 verify(mockTx).merge(eq(LogicalDatastoreType.OPERATIONAL), eq(topologyIID.child(Node.class,
379 new NodeKey(expNodeId))), mergedNode.capture(), eq(true));
380 assertEquals("getNodeId", expNodeId, mergedNode.getValue().getNodeId());
381 InventoryNode augmentation = mergedNode.getValue().getAugmentation(InventoryNode.class);
382 assertNotNull("Missing augmentation", augmentation);
383 assertEquals("getInventoryNodeRef", new NodeRef(invNodeID), augmentation.getInventoryNodeRef());
387 public void testOnNodeConnectorUpdated() {
389 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
390 nodeKey = newInvNodeKey("node1");
392 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey ncKey =
393 newInvNodeConnKey("tp1");
395 InstanceIdentifier<?> invNodeConnID = newNodeConnID(nodeKey, ncKey);
397 ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class);
398 CountDownLatch submitLatch = setupStubbedSubmit(mockTx);
399 doReturn(mockTx).when(mockTxChain).newReadWriteTransaction();
401 exporter.onNodeConnectorUpdated(new NodeConnectorUpdatedBuilder().setNodeConnectorRef(
402 new NodeConnectorRef(invNodeConnID)).setId(ncKey.getId()).addAugmentation(
403 FlowCapableNodeConnectorUpdated.class,
404 new FlowCapableNodeConnectorUpdatedBuilder().build()).build());
406 waitForSubmit(submitLatch);
408 ArgumentCaptor<TerminationPoint> mergedNode = ArgumentCaptor.forClass(TerminationPoint.class);
409 NodeId expNodeId = new NodeId("node1");
410 TpId expTpId = new TpId("tp1");
411 InstanceIdentifier<TerminationPoint> expTpPath = topologyIID.child(
412 Node.class, new NodeKey(expNodeId)).child(TerminationPoint.class,
413 new TerminationPointKey(expTpId));
414 verify(mockTx).merge(eq(LogicalDatastoreType.OPERATIONAL), eq(expTpPath),
415 mergedNode.capture(), eq(true));
416 assertEquals("getTpId", expTpId, mergedNode.getValue().getTpId());
417 InventoryNodeConnector augmentation = mergedNode.getValue().getAugmentation(
418 InventoryNodeConnector.class);
419 assertNotNull("Missing augmentation", augmentation);
420 assertEquals("getInventoryNodeConnectorRef", new NodeConnectorRef(invNodeConnID),
421 augmentation.getInventoryNodeConnectorRef());
424 @SuppressWarnings("rawtypes")
426 public void testOnNodeConnectorUpdatedWithLinkStateDown() {
428 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
429 nodeKey = newInvNodeKey("node1");
431 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey ncKey =
432 newInvNodeConnKey("tp1");
434 InstanceIdentifier<?> invNodeConnID = newNodeConnID(nodeKey, ncKey);
436 List<Link> linkList = Arrays.asList(newLink("link1", newSourceTp("tp1"), newDestTp("dest")));
437 Topology topology = new TopologyBuilder().setLink(linkList).build();
439 ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class);
440 doReturn(Futures.immediateCheckedFuture(Optional.of(topology))).when(mockTx)
441 .read(LogicalDatastoreType.OPERATIONAL, topologyIID);
442 setupStubbedSubmit(mockTx);
444 CountDownLatch deleteLatch = new CountDownLatch(1);
445 ArgumentCaptor<InstanceIdentifier> deletedLinkIDs =
446 ArgumentCaptor.forClass(InstanceIdentifier.class);
447 setupStubbedDeletes(mockTx, deletedLinkIDs, deleteLatch);
449 doReturn(mockTx).when(mockTxChain).newReadWriteTransaction();
451 exporter.onNodeConnectorUpdated(new NodeConnectorUpdatedBuilder().setNodeConnectorRef(
452 new NodeConnectorRef(invNodeConnID)).setId(ncKey.getId()).addAugmentation(
453 FlowCapableNodeConnectorUpdated.class,
454 new FlowCapableNodeConnectorUpdatedBuilder().setState(
455 new StateBuilder().setLinkDown(true).build()).build()).build());
457 waitForDeletes(1, deleteLatch);
459 InstanceIdentifier<TerminationPoint> expTpPath = topologyIID.child(
460 Node.class, new NodeKey(new NodeId("node1"))).child(TerminationPoint.class,
461 new TerminationPointKey(new TpId("tp1")));
463 verify(mockTx).merge(eq(LogicalDatastoreType.OPERATIONAL), eq(expTpPath),
464 any(TerminationPoint.class), eq(true));
466 assertDeletedIDs(new InstanceIdentifier[]{topologyIID.child(Link.class,
467 linkList.get(0).getKey())}, deletedLinkIDs);
471 @SuppressWarnings("rawtypes")
473 public void testOnNodeConnectorUpdatedWithPortDown() {
475 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
476 nodeKey = newInvNodeKey("node1");
478 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey ncKey =
479 newInvNodeConnKey("tp1");
481 InstanceIdentifier<?> invNodeConnID = newNodeConnID(nodeKey, ncKey);
483 List<Link> linkList = Arrays.asList(newLink("link1", newSourceTp("tp1"), newDestTp("dest")));
484 Topology topology = new TopologyBuilder().setLink(linkList).build();
486 ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class);
487 doReturn(Futures.immediateCheckedFuture(Optional.of(topology))).when(mockTx)
488 .read(LogicalDatastoreType.OPERATIONAL, topologyIID);
489 setupStubbedSubmit(mockTx);
491 CountDownLatch deleteLatch = new CountDownLatch(1);
492 ArgumentCaptor<InstanceIdentifier> deletedLinkIDs =
493 ArgumentCaptor.forClass(InstanceIdentifier.class);
494 setupStubbedDeletes(mockTx, deletedLinkIDs, deleteLatch);
496 doReturn(mockTx).when(mockTxChain).newReadWriteTransaction();
498 exporter.onNodeConnectorUpdated(new NodeConnectorUpdatedBuilder().setNodeConnectorRef(
499 new NodeConnectorRef(invNodeConnID)).setId(ncKey.getId()).addAugmentation(
500 FlowCapableNodeConnectorUpdated.class,
501 new FlowCapableNodeConnectorUpdatedBuilder().setConfiguration(
502 new PortConfig(true, true, true, true)).build()).build());
504 waitForDeletes(1, deleteLatch);
506 InstanceIdentifier<TerminationPoint> expTpPath = topologyIID.child(
507 Node.class, new NodeKey(new NodeId("node1"))).child(TerminationPoint.class,
508 new TerminationPointKey(new TpId("tp1")));
510 verify(mockTx).merge(eq(LogicalDatastoreType.OPERATIONAL), eq(expTpPath),
511 any(TerminationPoint.class), eq(true));
513 assertDeletedIDs(new InstanceIdentifier[]{topologyIID.child(Link.class,
514 linkList.get(0).getKey())}, deletedLinkIDs);
518 public void testOnLinkDiscovered() {
520 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
521 sourceNodeKey = newInvNodeKey("sourceNode");
522 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey
523 sourceNodeConnKey = newInvNodeConnKey("sourceTP");
524 InstanceIdentifier<?> sourceConnID = newNodeConnID(sourceNodeKey, sourceNodeConnKey);
526 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
527 destNodeKey = newInvNodeKey("destNode");
528 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey
529 destNodeConnKey = newInvNodeConnKey("destTP");
530 InstanceIdentifier<?> destConnID = newNodeConnID(destNodeKey, destNodeConnKey);
532 ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class);
533 CountDownLatch submitLatch = setupStubbedSubmit(mockTx);
534 doReturn(mockTx).when(mockTxChain).newReadWriteTransaction();
536 exporter.onLinkDiscovered(new LinkDiscoveredBuilder().setSource(
537 new NodeConnectorRef(sourceConnID)).setDestination(
538 new NodeConnectorRef(destConnID)).build());
540 waitForSubmit(submitLatch);
542 ArgumentCaptor<Link> mergedNode = ArgumentCaptor.forClass(Link.class);
543 verify(mockTx).merge(eq(LogicalDatastoreType.OPERATIONAL), eq(topologyIID.child(
544 Link.class, new LinkKey(new LinkId(sourceNodeConnKey.getId())))),
545 mergedNode.capture(), eq(true));
546 assertEquals("Source node ID", "sourceNode",
547 mergedNode.getValue().getSource().getSourceNode().getValue());
548 assertEquals("Dest TP ID", "sourceTP",
549 mergedNode.getValue().getSource().getSourceTp().getValue());
550 assertEquals("Dest node ID", "destNode",
551 mergedNode.getValue().getDestination().getDestNode().getValue());
552 assertEquals("Dest TP ID", "destTP",
553 mergedNode.getValue().getDestination().getDestTp().getValue());
557 public void testOnLinkRemoved() {
559 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
560 sourceNodeKey = newInvNodeKey("sourceNode");
561 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey
562 sourceNodeConnKey = newInvNodeConnKey("sourceTP");
563 InstanceIdentifier<?> sourceConnID = newNodeConnID(sourceNodeKey, sourceNodeConnKey);
565 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
566 destNodeKey = newInvNodeKey("destNode");
567 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey
568 destNodeConnKey = newInvNodeConnKey("destTP");
569 InstanceIdentifier<?> destConnID = newNodeConnID(destNodeKey, destNodeConnKey);
571 Link link = newLink(sourceNodeConnKey.getId().getValue(), newSourceTp(sourceNodeConnKey.getId().getValue()),
572 newDestTp(destNodeConnKey.getId().getValue()));
574 ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class);
575 CountDownLatch submitLatch = setupStubbedSubmit(mockTx);
576 doReturn(mockTx).when(mockTxChain).newReadWriteTransaction();
577 doReturn(Futures.immediateCheckedFuture(Optional.of(link))).when(mockTx).read(LogicalDatastoreType.OPERATIONAL, topologyIID.child(
578 Link.class, new LinkKey(new LinkId(sourceNodeConnKey.getId()))));
580 exporter.onLinkRemoved(new LinkRemovedBuilder().setSource(
581 new NodeConnectorRef(sourceConnID)).setDestination(
582 new NodeConnectorRef(destConnID)).build());
584 waitForSubmit(submitLatch);
586 verify(mockTx).delete(LogicalDatastoreType.OPERATIONAL, topologyIID.child(
587 Link.class, new LinkKey(new LinkId(sourceNodeConnKey.getId()))));
591 public void testOnLinkRemovedLinkDoesNotExist() {
593 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
594 sourceNodeKey = newInvNodeKey("sourceNode");
595 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey
596 sourceNodeConnKey = newInvNodeConnKey("sourceTP");
597 InstanceIdentifier<?> sourceConnID = newNodeConnID(sourceNodeKey, sourceNodeConnKey);
599 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
600 destNodeKey = newInvNodeKey("destNode");
601 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey
602 destNodeConnKey = newInvNodeConnKey("destTP");
603 InstanceIdentifier<?> destConnID = newNodeConnID(destNodeKey, destNodeConnKey);
605 ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class);
606 CountDownLatch submitLatch = setupStubbedSubmit(mockTx);
607 doReturn(mockTx).when(mockTxChain).newReadWriteTransaction();
608 doReturn(Futures.immediateCheckedFuture(Optional.<Link>absent())).when(mockTx).read(LogicalDatastoreType.OPERATIONAL, topologyIID.child(
609 Link.class, new LinkKey(new LinkId(sourceNodeConnKey.getId()))));
611 exporter.onLinkRemoved(new LinkRemovedBuilder().setSource(
612 new NodeConnectorRef(sourceConnID)).setDestination(
613 new NodeConnectorRef(destConnID)).build());
615 waitForSubmit(submitLatch);
617 verify(mockTx, never()).delete(LogicalDatastoreType.OPERATIONAL, topologyIID.child(
618 Link.class, new LinkKey(new LinkId(sourceNodeConnKey.getId()))));
621 private void verifyMockTx(ReadWriteTransaction mockTx) {
622 InOrder inOrder = inOrder(mockTx);
623 inOrder.verify(mockTx, atLeast(0)).submit();
624 inOrder.verify(mockTx, never()).delete(eq(LogicalDatastoreType.OPERATIONAL),
625 any(InstanceIdentifier.class));
628 @SuppressWarnings("rawtypes")
629 private void assertDeletedIDs(InstanceIdentifier[] expDeletedIIDs,
630 ArgumentCaptor<InstanceIdentifier> deletedLinkIDs) {
631 Set<InstanceIdentifier> actualIIDs = new HashSet<>(deletedLinkIDs.getAllValues());
632 for(InstanceIdentifier id: expDeletedIIDs) {
633 assertTrue("Missing expected deleted IID " + id, actualIIDs.contains(id));
637 private void setReadFutureAsync(final Topology topology,
638 final SettableFuture<Optional<Topology>> readFuture) {
642 Uninterruptibles.sleepUninterruptibly(50, TimeUnit.MILLISECONDS);
643 readFuture.set(Optional.of(topology));
649 private void waitForSubmit(CountDownLatch latch) {
650 assertEquals("Transaction submitted", true,
651 Uninterruptibles.awaitUninterruptibly(latch, 5, TimeUnit.SECONDS));
654 private void waitForDeletes(int expDeleteCalls, final CountDownLatch latch) {
655 boolean done = Uninterruptibles.awaitUninterruptibly(latch, 5, TimeUnit.SECONDS);
657 fail("Expected " + expDeleteCalls + " delete calls. Actual: " +
658 (expDeleteCalls - latch.getCount()));
662 private CountDownLatch setupStubbedSubmit(ReadWriteTransaction mockTx) {
663 final CountDownLatch latch = new CountDownLatch(1);
664 doAnswer(new Answer<CheckedFuture<Void, TransactionCommitFailedException>>() {
666 public CheckedFuture<Void, TransactionCommitFailedException> answer(
667 InvocationOnMock invocation) {
669 return Futures.immediateCheckedFuture(null);
671 }).when(mockTx).submit();
676 @SuppressWarnings("rawtypes")
677 private void setupStubbedDeletes(ReadWriteTransaction mockTx,
678 ArgumentCaptor<InstanceIdentifier> deletedLinkIDs, final CountDownLatch latch) {
679 doAnswer(new Answer<Void>() {
681 public Void answer(InvocationOnMock invocation) {
685 }).when(mockTx).delete(eq(LogicalDatastoreType.OPERATIONAL), deletedLinkIDs.capture());
688 private org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
689 newInvNodeKey(String id) {
690 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey nodeKey =
691 new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey(
692 new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.
693 rev130819.NodeId(id));
697 private NodeConnectorKey newInvNodeConnKey(String id) {
698 return new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey(
699 new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.
700 NodeConnectorId(id));
703 private KeyedInstanceIdentifier<NodeConnector, NodeConnectorKey> newNodeConnID(
704 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey nodeKey,
705 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey ncKey) {
706 return InstanceIdentifier.create(Nodes.class).child(
707 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
708 nodeKey).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.
709 rev130819.node.NodeConnector.class, ncKey);
712 private Link newLink(String id, Source source, Destination dest) {
713 return new LinkBuilder().setLinkId(new LinkId(id))
714 .setSource(source).setDestination(dest).build();
717 private Destination newDestTp(String id) {
718 return new DestinationBuilder().setDestTp(new TpId(id)).build();
721 private Source newSourceTp(String id) {
722 return new SourceBuilder().setSourceTp(new TpId(id)).build();
725 private Destination newDestNode(String id) {
726 return new DestinationBuilder().setDestNode(new NodeId(id)).build();
729 private Source newSourceNode(String id) {
730 return new SourceBuilder().setSourceNode(new NodeId(id)).build();