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.md.controller.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;
16 import org.junit.After;
17 import org.junit.Before;
18 import org.junit.Test;
19 import org.mockito.ArgumentCaptor;
20 import org.mockito.InOrder;
21 import org.mockito.Mock;
22 import org.mockito.MockitoAnnotations;
23 import org.mockito.invocation.InvocationOnMock;
24 import org.mockito.stubbing.Answer;
25 import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
26 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
27 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
28 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
29 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
30 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
31 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorUpdated;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorUpdatedBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeUpdated;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeUpdatedBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.LinkDiscoveredBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.LinkRemovedBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortConfig;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.flow.capable.port.StateBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRemovedBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorUpdatedBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRemovedBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeUpdatedBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.topology.inventory.rev131030.InventoryNode;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.topology.inventory.rev131030.InventoryNodeConnector;
51 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.LinkId;
52 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
53 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
54 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
55 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId;
56 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.Destination;
57 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.DestinationBuilder;
58 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.Source;
59 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.SourceBuilder;
60 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
61 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder;
62 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
63 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link;
64 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.LinkBuilder;
65 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.LinkKey;
66 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
67 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
68 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
69 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
70 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
71 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
72 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
74 import java.util.Arrays;
75 import java.util.HashSet;
76 import java.util.List;
78 import java.util.concurrent.CountDownLatch;
79 import java.util.concurrent.ExecutorService;
80 import java.util.concurrent.Executors;
81 import java.util.concurrent.TimeUnit;
83 import static org.junit.Assert.assertEquals;
84 import static org.junit.Assert.assertNotNull;
85 import static org.junit.Assert.assertTrue;
86 import static org.junit.Assert.fail;
87 import static org.mockito.Mockito.any;
88 import static org.mockito.Mockito.atLeast;
89 import static org.mockito.Mockito.doAnswer;
90 import static org.mockito.Mockito.doReturn;
91 import static org.mockito.Mockito.eq;
92 import static org.mockito.Mockito.inOrder;
93 import static org.mockito.Mockito.mock;
94 import static org.mockito.Mockito.never;
95 import static org.mockito.Mockito.verify;
97 public class FlowCapableTopologyExporterTest {
100 private DataBroker mockDataBroker;
103 private BindingTransactionChain mockTxChain;
105 private OperationProcessor processor;
107 private FlowCapableTopologyExporter exporter;
109 private InstanceIdentifier<Topology> topologyIID;
111 private final ExecutorService executor = Executors.newFixedThreadPool(1);
114 public void setUp() {
115 MockitoAnnotations.initMocks(this);
117 doReturn(mockTxChain).when(mockDataBroker)
118 .createTransactionChain(any(TransactionChainListener.class));
120 processor = new OperationProcessor(mockDataBroker);
122 topologyIID = InstanceIdentifier.create(NetworkTopology.class)
123 .child(Topology.class, new TopologyKey(new TopologyId("test")));
124 exporter = new FlowCapableTopologyExporter(processor, topologyIID);
126 executor.execute(processor);
130 public void tearDown() {
131 executor.shutdownNow();
134 @SuppressWarnings({ "rawtypes" })
136 public void testOnNodeRemoved() {
138 NodeKey topoNodeKey = new NodeKey(new NodeId("node1"));
139 InstanceIdentifier<Node> topoNodeII = topologyIID.child(Node.class, topoNodeKey);
140 Node topoNode = new NodeBuilder().setKey(topoNodeKey).build();
142 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
143 nodeKey = newInvNodeKey(topoNodeKey.getNodeId().getValue());
144 InstanceIdentifier<?> invNodeID = InstanceIdentifier.create(Nodes.class).child(
145 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
148 List<Link> linkList = Arrays.asList(
149 newLink("link1", newSourceNode("node1"), newDestNode("dest")),
150 newLink("link2", newSourceNode("source"), newDestNode("node1")),
151 newLink("link2", newSourceNode("source2"), newDestNode("dest2")));
152 final Topology topology = new TopologyBuilder().setLink(linkList).build();
154 InstanceIdentifier[] expDeletedIIDs = {
155 topologyIID.child(Link.class, linkList.get(0).getKey()),
156 topologyIID.child(Link.class, linkList.get(1).getKey()),
157 topologyIID.child(Node.class, new NodeKey(new NodeId("node1")))
160 SettableFuture<Optional<Topology>> readFuture = SettableFuture.create();
161 readFuture.set(Optional.of(topology));
162 ReadWriteTransaction mockTx1 = mock(ReadWriteTransaction.class);
163 doReturn(Futures.makeChecked(readFuture, ReadFailedException.MAPPER)).when(mockTx1)
164 .read(LogicalDatastoreType.OPERATIONAL, topologyIID);
166 SettableFuture<Optional<Node>> readFutureNode = SettableFuture.create();
167 readFutureNode.set(Optional.of(topoNode));
168 doReturn(Futures.makeChecked(readFutureNode, ReadFailedException.MAPPER)).when(mockTx1)
169 .read(LogicalDatastoreType.OPERATIONAL, topoNodeII);
171 CountDownLatch submitLatch1 = setupStubbedSubmit(mockTx1);
173 int expDeleteCalls = expDeletedIIDs.length;
174 CountDownLatch deleteLatch = new CountDownLatch(expDeleteCalls);
175 ArgumentCaptor<InstanceIdentifier> deletedLinkIDs =
176 ArgumentCaptor.forClass(InstanceIdentifier.class);
177 setupStubbedDeletes(mockTx1, deletedLinkIDs, deleteLatch);
179 doReturn(mockTx1).when(mockTxChain).newReadWriteTransaction();
181 exporter.onNodeRemoved(new NodeRemovedBuilder().setNodeRef(new NodeRef(invNodeID)).build());
183 waitForSubmit(submitLatch1);
185 setReadFutureAsync(topology, readFuture);
187 waitForDeletes(expDeleteCalls, deleteLatch);
189 assertDeletedIDs(expDeletedIIDs, deletedLinkIDs);
191 verifyMockTx(mockTx1);
194 @SuppressWarnings({ "rawtypes" })
196 public void testOnNodeRemovedWithNoTopology() {
198 NodeKey topoNodeKey = new NodeKey(new NodeId("node1"));
199 InstanceIdentifier<Node> topoNodeII = topologyIID.child(Node.class, topoNodeKey);
200 Node topoNode = new NodeBuilder().setKey(topoNodeKey).build();
202 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
203 nodeKey = newInvNodeKey(topoNodeKey.getNodeId().getValue());
204 InstanceIdentifier<?> invNodeID = InstanceIdentifier.create(Nodes.class).child(
205 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
208 InstanceIdentifier[] expDeletedIIDs = {
209 topologyIID.child(Node.class, new NodeKey(new NodeId("node1")))
212 ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class);
213 doReturn(Futures.immediateCheckedFuture(Optional.absent())).when(mockTx)
214 .read(LogicalDatastoreType.OPERATIONAL, topologyIID);
215 CountDownLatch submitLatch = setupStubbedSubmit(mockTx);
217 SettableFuture<Optional<Node>> readFutureNode = SettableFuture.create();
218 readFutureNode.set(Optional.of(topoNode));
219 doReturn(Futures.makeChecked(readFutureNode, ReadFailedException.MAPPER)).when(mockTx)
220 .read(LogicalDatastoreType.OPERATIONAL, topoNodeII);
222 CountDownLatch deleteLatch = new CountDownLatch(1);
223 ArgumentCaptor<InstanceIdentifier> deletedLinkIDs =
224 ArgumentCaptor.forClass(InstanceIdentifier.class);
225 setupStubbedDeletes(mockTx, deletedLinkIDs, deleteLatch);
227 doReturn(mockTx).when(mockTxChain).newReadWriteTransaction();
229 exporter.onNodeRemoved(new NodeRemovedBuilder().setNodeRef(new NodeRef(invNodeID)).build());
231 waitForSubmit(submitLatch);
233 waitForDeletes(1, deleteLatch);
235 assertDeletedIDs(expDeletedIIDs, deletedLinkIDs);
238 @SuppressWarnings("rawtypes")
240 public void testOnNodeConnectorRemoved() {
242 NodeKey topoNodeKey = new NodeKey(new NodeId("node1"));
243 TerminationPointKey terminationPointKey = new TerminationPointKey(new TpId("tp1"));
245 InstanceIdentifier<Node> topoNodeII = topologyIID.child(Node.class, topoNodeKey);
246 Node topoNode = new NodeBuilder().setKey(topoNodeKey).build();
248 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
249 nodeKey = newInvNodeKey(topoNodeKey.getNodeId().getValue());
251 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey ncKey =
252 newInvNodeConnKey(terminationPointKey.getTpId().getValue());
254 InstanceIdentifier<?> invNodeConnID = newNodeConnID(nodeKey, ncKey);
256 List<Link> linkList = Arrays.asList(
257 newLink("link1", newSourceTp("tp1"), newDestTp("dest")),
258 newLink("link2", newSourceTp("source"), newDestTp("tp1")),
259 newLink("link3", newSourceTp("source2"), newDestTp("dest2")));
260 final Topology topology = new TopologyBuilder().setLink(linkList).build();
262 InstanceIdentifier[] expDeletedIIDs = {
263 topologyIID.child(Link.class, linkList.get(0).getKey()),
264 topologyIID.child(Link.class, linkList.get(1).getKey()),
265 topologyIID.child(Node.class, new NodeKey(new NodeId("node1")))
266 .child(TerminationPoint.class, new TerminationPointKey(new TpId("tp1")))
269 final SettableFuture<Optional<Topology>> readFuture = SettableFuture.create();
270 readFuture.set(Optional.of(topology));
271 ReadWriteTransaction mockTx1 = mock(ReadWriteTransaction.class);
272 doReturn(Futures.makeChecked(readFuture, ReadFailedException.MAPPER)).when(mockTx1)
273 .read(LogicalDatastoreType.OPERATIONAL, topologyIID);
275 SettableFuture<Optional<Node>> readFutureNode = SettableFuture.create();
276 readFutureNode.set(Optional.of(topoNode));
277 doReturn(Futures.makeChecked(readFutureNode, ReadFailedException.MAPPER)).when(mockTx1)
278 .read(LogicalDatastoreType.OPERATIONAL, topoNodeII);
280 CountDownLatch submitLatch1 = setupStubbedSubmit(mockTx1);
282 int expDeleteCalls = expDeletedIIDs.length;
283 CountDownLatch deleteLatch = new CountDownLatch(expDeleteCalls);
284 ArgumentCaptor<InstanceIdentifier> deletedLinkIDs =
285 ArgumentCaptor.forClass(InstanceIdentifier.class);
286 setupStubbedDeletes(mockTx1, deletedLinkIDs, deleteLatch);
288 doReturn(mockTx1).when(mockTxChain).newReadWriteTransaction();
290 exporter.onNodeConnectorRemoved(new NodeConnectorRemovedBuilder().setNodeConnectorRef(
291 new NodeConnectorRef(invNodeConnID)).build());
293 waitForSubmit(submitLatch1);
295 setReadFutureAsync(topology, readFuture);
297 waitForDeletes(expDeleteCalls, deleteLatch);
299 assertDeletedIDs(expDeletedIIDs, deletedLinkIDs);
301 verifyMockTx(mockTx1);
304 @SuppressWarnings("rawtypes")
306 public void testOnNodeConnectorRemovedWithNoTopology() {
308 NodeKey topoNodeKey = new NodeKey(new NodeId("node1"));
309 TerminationPointKey terminationPointKey = new TerminationPointKey(new TpId("tp1"));
311 InstanceIdentifier<Node> topoNodeII = topologyIID.child(Node.class, topoNodeKey);
312 Node topoNode = new NodeBuilder().setKey(topoNodeKey).build();
314 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
315 nodeKey = newInvNodeKey(topoNodeKey.getNodeId().getValue());
317 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey ncKey =
318 newInvNodeConnKey(terminationPointKey.getTpId().getValue());
320 InstanceIdentifier<?> invNodeConnID = newNodeConnID(nodeKey, ncKey);
322 InstanceIdentifier[] expDeletedIIDs = {
323 topologyIID.child(Node.class, new NodeKey(new NodeId("node1")))
324 .child(TerminationPoint.class, new TerminationPointKey(new TpId("tp1")))
327 ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class);
328 doReturn(Futures.immediateCheckedFuture(Optional.absent())).when(mockTx)
329 .read(LogicalDatastoreType.OPERATIONAL, topologyIID);
330 CountDownLatch submitLatch = setupStubbedSubmit(mockTx);
332 SettableFuture<Optional<Node>> readFutureNode = SettableFuture.create();
333 readFutureNode.set(Optional.of(topoNode));
334 doReturn(Futures.makeChecked(readFutureNode, ReadFailedException.MAPPER)).when(mockTx)
335 .read(LogicalDatastoreType.OPERATIONAL, topoNodeII);
337 CountDownLatch deleteLatch = new CountDownLatch(1);
338 ArgumentCaptor<InstanceIdentifier> deletedLinkIDs =
339 ArgumentCaptor.forClass(InstanceIdentifier.class);
340 setupStubbedDeletes(mockTx, deletedLinkIDs, deleteLatch);
342 doReturn(mockTx).when(mockTxChain).newReadWriteTransaction();
344 exporter.onNodeConnectorRemoved(new NodeConnectorRemovedBuilder().setNodeConnectorRef(
345 new NodeConnectorRef(invNodeConnID)).build());
347 waitForSubmit(submitLatch);
349 waitForDeletes(1, deleteLatch);
351 assertDeletedIDs(expDeletedIIDs, deletedLinkIDs);
355 public void testOnNodeUpdated() {
357 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
358 nodeKey = newInvNodeKey("node1");
359 InstanceIdentifier<?> invNodeID = InstanceIdentifier.create(Nodes.class).child(
360 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
363 ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class);
364 CountDownLatch submitLatch = setupStubbedSubmit(mockTx);
365 doReturn(mockTx).when(mockTxChain).newReadWriteTransaction();
367 exporter.onNodeUpdated(new NodeUpdatedBuilder().setNodeRef(new NodeRef(invNodeID))
368 .setId(nodeKey.getId()).addAugmentation(FlowCapableNodeUpdated.class,
369 new FlowCapableNodeUpdatedBuilder().build()).build());
371 waitForSubmit(submitLatch);
373 ArgumentCaptor<Node> mergedNode = ArgumentCaptor.forClass(Node.class);
374 NodeId expNodeId = new NodeId("node1");
375 verify(mockTx).merge(eq(LogicalDatastoreType.OPERATIONAL), eq(topologyIID.child(Node.class,
376 new NodeKey(expNodeId))), mergedNode.capture(), eq(true));
377 assertEquals("getNodeId", expNodeId, mergedNode.getValue().getNodeId());
378 InventoryNode augmentation = mergedNode.getValue().getAugmentation(InventoryNode.class);
379 assertNotNull("Missing augmentation", augmentation);
380 assertEquals("getInventoryNodeRef", new NodeRef(invNodeID), augmentation.getInventoryNodeRef());
384 public void testOnNodeConnectorUpdated() {
386 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
387 nodeKey = newInvNodeKey("node1");
389 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey ncKey =
390 newInvNodeConnKey("tp1");
392 InstanceIdentifier<?> invNodeConnID = newNodeConnID(nodeKey, ncKey);
394 ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class);
395 CountDownLatch submitLatch = setupStubbedSubmit(mockTx);
396 doReturn(mockTx).when(mockTxChain).newReadWriteTransaction();
398 exporter.onNodeConnectorUpdated(new NodeConnectorUpdatedBuilder().setNodeConnectorRef(
399 new NodeConnectorRef(invNodeConnID)).setId(ncKey.getId()).addAugmentation(
400 FlowCapableNodeConnectorUpdated.class,
401 new FlowCapableNodeConnectorUpdatedBuilder().build()).build());
403 waitForSubmit(submitLatch);
405 ArgumentCaptor<TerminationPoint> mergedNode = ArgumentCaptor.forClass(TerminationPoint.class);
406 NodeId expNodeId = new NodeId("node1");
407 TpId expTpId = new TpId("tp1");
408 InstanceIdentifier<TerminationPoint> expTpPath = topologyIID.child(
409 Node.class, new NodeKey(expNodeId)).child(TerminationPoint.class,
410 new TerminationPointKey(expTpId));
411 verify(mockTx).merge(eq(LogicalDatastoreType.OPERATIONAL), eq(expTpPath),
412 mergedNode.capture(), eq(true));
413 assertEquals("getTpId", expTpId, mergedNode.getValue().getTpId());
414 InventoryNodeConnector augmentation = mergedNode.getValue().getAugmentation(
415 InventoryNodeConnector.class);
416 assertNotNull("Missing augmentation", augmentation);
417 assertEquals("getInventoryNodeConnectorRef", new NodeConnectorRef(invNodeConnID),
418 augmentation.getInventoryNodeConnectorRef());
421 @SuppressWarnings("rawtypes")
423 public void testOnNodeConnectorUpdatedWithLinkStateDown() {
425 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
426 nodeKey = newInvNodeKey("node1");
428 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey ncKey =
429 newInvNodeConnKey("tp1");
431 InstanceIdentifier<?> invNodeConnID = newNodeConnID(nodeKey, ncKey);
433 List<Link> linkList = Arrays.asList(newLink("link1", newSourceTp("tp1"), newDestTp("dest")));
434 Topology topology = new TopologyBuilder().setLink(linkList).build();
436 ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class);
437 doReturn(Futures.immediateCheckedFuture(Optional.of(topology))).when(mockTx)
438 .read(LogicalDatastoreType.OPERATIONAL, topologyIID);
439 setupStubbedSubmit(mockTx);
441 CountDownLatch deleteLatch = new CountDownLatch(1);
442 ArgumentCaptor<InstanceIdentifier> deletedLinkIDs =
443 ArgumentCaptor.forClass(InstanceIdentifier.class);
444 setupStubbedDeletes(mockTx, deletedLinkIDs, deleteLatch);
446 doReturn(mockTx).when(mockTxChain).newReadWriteTransaction();
448 exporter.onNodeConnectorUpdated(new NodeConnectorUpdatedBuilder().setNodeConnectorRef(
449 new NodeConnectorRef(invNodeConnID)).setId(ncKey.getId()).addAugmentation(
450 FlowCapableNodeConnectorUpdated.class,
451 new FlowCapableNodeConnectorUpdatedBuilder().setState(
452 new StateBuilder().setLinkDown(true).build()).build()).build());
454 waitForDeletes(1, deleteLatch);
456 InstanceIdentifier<TerminationPoint> expTpPath = topologyIID.child(
457 Node.class, new NodeKey(new NodeId("node1"))).child(TerminationPoint.class,
458 new TerminationPointKey(new TpId("tp1")));
460 verify(mockTx).merge(eq(LogicalDatastoreType.OPERATIONAL), eq(expTpPath),
461 any(TerminationPoint.class), eq(true));
463 assertDeletedIDs(new InstanceIdentifier[]{topologyIID.child(Link.class,
464 linkList.get(0).getKey())}, deletedLinkIDs);
468 @SuppressWarnings("rawtypes")
470 public void testOnNodeConnectorUpdatedWithPortDown() {
472 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
473 nodeKey = newInvNodeKey("node1");
475 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey ncKey =
476 newInvNodeConnKey("tp1");
478 InstanceIdentifier<?> invNodeConnID = newNodeConnID(nodeKey, ncKey);
480 List<Link> linkList = Arrays.asList(newLink("link1", newSourceTp("tp1"), newDestTp("dest")));
481 Topology topology = new TopologyBuilder().setLink(linkList).build();
483 ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class);
484 doReturn(Futures.immediateCheckedFuture(Optional.of(topology))).when(mockTx)
485 .read(LogicalDatastoreType.OPERATIONAL, topologyIID);
486 setupStubbedSubmit(mockTx);
488 CountDownLatch deleteLatch = new CountDownLatch(1);
489 ArgumentCaptor<InstanceIdentifier> deletedLinkIDs =
490 ArgumentCaptor.forClass(InstanceIdentifier.class);
491 setupStubbedDeletes(mockTx, deletedLinkIDs, deleteLatch);
493 doReturn(mockTx).when(mockTxChain).newReadWriteTransaction();
495 exporter.onNodeConnectorUpdated(new NodeConnectorUpdatedBuilder().setNodeConnectorRef(
496 new NodeConnectorRef(invNodeConnID)).setId(ncKey.getId()).addAugmentation(
497 FlowCapableNodeConnectorUpdated.class,
498 new FlowCapableNodeConnectorUpdatedBuilder().setConfiguration(
499 new PortConfig(true, true, true, true)).build()).build());
501 waitForDeletes(1, deleteLatch);
503 InstanceIdentifier<TerminationPoint> expTpPath = topologyIID.child(
504 Node.class, new NodeKey(new NodeId("node1"))).child(TerminationPoint.class,
505 new TerminationPointKey(new TpId("tp1")));
507 verify(mockTx).merge(eq(LogicalDatastoreType.OPERATIONAL), eq(expTpPath),
508 any(TerminationPoint.class), eq(true));
510 assertDeletedIDs(new InstanceIdentifier[]{topologyIID.child(Link.class,
511 linkList.get(0).getKey())}, deletedLinkIDs);
515 public void testOnLinkDiscovered() {
517 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
518 sourceNodeKey = newInvNodeKey("sourceNode");
519 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey
520 sourceNodeConnKey = newInvNodeConnKey("sourceTP");
521 InstanceIdentifier<?> sourceConnID = newNodeConnID(sourceNodeKey, sourceNodeConnKey);
523 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
524 destNodeKey = newInvNodeKey("destNode");
525 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey
526 destNodeConnKey = newInvNodeConnKey("destTP");
527 InstanceIdentifier<?> destConnID = newNodeConnID(destNodeKey, destNodeConnKey);
529 ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class);
530 CountDownLatch submitLatch = setupStubbedSubmit(mockTx);
531 doReturn(mockTx).when(mockTxChain).newReadWriteTransaction();
533 exporter.onLinkDiscovered(new LinkDiscoveredBuilder().setSource(
534 new NodeConnectorRef(sourceConnID)).setDestination(
535 new NodeConnectorRef(destConnID)).build());
537 waitForSubmit(submitLatch);
539 ArgumentCaptor<Link> mergedNode = ArgumentCaptor.forClass(Link.class);
540 verify(mockTx).merge(eq(LogicalDatastoreType.OPERATIONAL), eq(topologyIID.child(
541 Link.class, new LinkKey(new LinkId(sourceNodeConnKey.getId())))),
542 mergedNode.capture(), eq(true));
543 assertEquals("Source node ID", "sourceNode",
544 mergedNode.getValue().getSource().getSourceNode().getValue());
545 assertEquals("Dest TP ID", "sourceTP",
546 mergedNode.getValue().getSource().getSourceTp().getValue());
547 assertEquals("Dest node ID", "destNode",
548 mergedNode.getValue().getDestination().getDestNode().getValue());
549 assertEquals("Dest TP ID", "destTP",
550 mergedNode.getValue().getDestination().getDestTp().getValue());
554 public void testOnLinkRemoved() {
556 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
557 sourceNodeKey = newInvNodeKey("sourceNode");
558 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey
559 sourceNodeConnKey = newInvNodeConnKey("sourceTP");
560 InstanceIdentifier<?> sourceConnID = newNodeConnID(sourceNodeKey, sourceNodeConnKey);
562 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
563 destNodeKey = newInvNodeKey("destNode");
564 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey
565 destNodeConnKey = newInvNodeConnKey("destTP");
566 InstanceIdentifier<?> destConnID = newNodeConnID(destNodeKey, destNodeConnKey);
568 Link link = newLink(sourceNodeConnKey.getId().getValue(), newSourceTp(sourceNodeConnKey.getId().getValue()),
569 newDestTp(destNodeConnKey.getId().getValue()));
571 ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class);
572 CountDownLatch submitLatch = setupStubbedSubmit(mockTx);
573 doReturn(mockTx).when(mockTxChain).newReadWriteTransaction();
574 doReturn(Futures.immediateCheckedFuture(Optional.of(link))).when(mockTx).read(LogicalDatastoreType.OPERATIONAL, topologyIID.child(
575 Link.class, new LinkKey(new LinkId(sourceNodeConnKey.getId()))));
577 exporter.onLinkRemoved(new LinkRemovedBuilder().setSource(
578 new NodeConnectorRef(sourceConnID)).setDestination(
579 new NodeConnectorRef(destConnID)).build());
581 waitForSubmit(submitLatch);
583 verify(mockTx).delete(LogicalDatastoreType.OPERATIONAL, topologyIID.child(
584 Link.class, new LinkKey(new LinkId(sourceNodeConnKey.getId()))));
588 public void testOnLinkRemovedLinkDoesNotExist() {
590 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
591 sourceNodeKey = newInvNodeKey("sourceNode");
592 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey
593 sourceNodeConnKey = newInvNodeConnKey("sourceTP");
594 InstanceIdentifier<?> sourceConnID = newNodeConnID(sourceNodeKey, sourceNodeConnKey);
596 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
597 destNodeKey = newInvNodeKey("destNode");
598 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey
599 destNodeConnKey = newInvNodeConnKey("destTP");
600 InstanceIdentifier<?> destConnID = newNodeConnID(destNodeKey, destNodeConnKey);
602 ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class);
603 CountDownLatch submitLatch = setupStubbedSubmit(mockTx);
604 doReturn(mockTx).when(mockTxChain).newReadWriteTransaction();
605 doReturn(Futures.immediateCheckedFuture(Optional.<Link>absent())).when(mockTx).read(LogicalDatastoreType.OPERATIONAL, topologyIID.child(
606 Link.class, new LinkKey(new LinkId(sourceNodeConnKey.getId()))));
608 exporter.onLinkRemoved(new LinkRemovedBuilder().setSource(
609 new NodeConnectorRef(sourceConnID)).setDestination(
610 new NodeConnectorRef(destConnID)).build());
612 waitForSubmit(submitLatch);
614 verify(mockTx, never()).delete(LogicalDatastoreType.OPERATIONAL, topologyIID.child(
615 Link.class, new LinkKey(new LinkId(sourceNodeConnKey.getId()))));
618 private void verifyMockTx(ReadWriteTransaction mockTx) {
619 InOrder inOrder = inOrder(mockTx);
620 inOrder.verify(mockTx, atLeast(0)).submit();
621 inOrder.verify(mockTx, never()).delete(eq(LogicalDatastoreType.OPERATIONAL),
622 any(InstanceIdentifier.class));
625 @SuppressWarnings("rawtypes")
626 private void assertDeletedIDs(InstanceIdentifier[] expDeletedIIDs,
627 ArgumentCaptor<InstanceIdentifier> deletedLinkIDs) {
628 Set<InstanceIdentifier> actualIIDs = new HashSet<>(deletedLinkIDs.getAllValues());
629 for(InstanceIdentifier id: expDeletedIIDs) {
630 assertTrue("Missing expected deleted IID " + id, actualIIDs.contains(id));
634 private void setReadFutureAsync(final Topology topology,
635 final SettableFuture<Optional<Topology>> readFuture) {
639 Uninterruptibles.sleepUninterruptibly(50, TimeUnit.MILLISECONDS);
640 readFuture.set(Optional.of(topology));
646 private void waitForSubmit(CountDownLatch latch) {
647 assertEquals("Transaction submitted", true,
648 Uninterruptibles.awaitUninterruptibly(latch, 5, TimeUnit.SECONDS));
651 private void waitForDeletes(int expDeleteCalls, final CountDownLatch latch) {
652 boolean done = Uninterruptibles.awaitUninterruptibly(latch, 5, TimeUnit.SECONDS);
654 fail("Expected " + expDeleteCalls + " delete calls. Actual: " +
655 (expDeleteCalls - latch.getCount()));
659 private CountDownLatch setupStubbedSubmit(ReadWriteTransaction mockTx) {
660 final CountDownLatch latch = new CountDownLatch(1);
661 doAnswer(new Answer<CheckedFuture<Void, TransactionCommitFailedException>>() {
663 public CheckedFuture<Void, TransactionCommitFailedException> answer(
664 InvocationOnMock invocation) {
666 return Futures.immediateCheckedFuture(null);
668 }).when(mockTx).submit();
673 @SuppressWarnings("rawtypes")
674 private void setupStubbedDeletes(ReadWriteTransaction mockTx,
675 ArgumentCaptor<InstanceIdentifier> deletedLinkIDs, final CountDownLatch latch) {
676 doAnswer(new Answer<Void>() {
678 public Void answer(InvocationOnMock invocation) {
682 }).when(mockTx).delete(eq(LogicalDatastoreType.OPERATIONAL), deletedLinkIDs.capture());
685 private org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
686 newInvNodeKey(String id) {
687 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey nodeKey =
688 new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey(
689 new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.
690 rev130819.NodeId(id));
694 private NodeConnectorKey newInvNodeConnKey(String id) {
695 return new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey(
696 new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.
697 NodeConnectorId(id));
700 private KeyedInstanceIdentifier<NodeConnector, NodeConnectorKey> newNodeConnID(
701 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey nodeKey,
702 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey ncKey) {
703 return InstanceIdentifier.create(Nodes.class).child(
704 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
705 nodeKey).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.
706 rev130819.node.NodeConnector.class, ncKey);
709 private Link newLink(String id, Source source, Destination dest) {
710 return new LinkBuilder().setLinkId(new LinkId(id))
711 .setSource(source).setDestination(dest).build();
714 private Destination newDestTp(String id) {
715 return new DestinationBuilder().setDestTp(new TpId(id)).build();
718 private Source newSourceTp(String id) {
719 return new SourceBuilder().setSourceTp(new TpId(id)).build();
722 private Destination newDestNode(String id) {
723 return new DestinationBuilder().setDestNode(new NodeId(id)).build();
726 private Source newSourceNode(String id) {
727 return new SourceBuilder().setSourceNode(new NodeId(id)).build();