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());
383 @SuppressWarnings("rawtypes")
385 public void testOnNodeConnectorUpdated() {
387 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
388 nodeKey = newInvNodeKey("node1");
390 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey ncKey =
391 newInvNodeConnKey("tp1");
393 InstanceIdentifier<?> invNodeConnID = newNodeConnID(nodeKey, ncKey);
395 ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class);
396 CountDownLatch submitLatch = setupStubbedSubmit(mockTx);
397 doReturn(mockTx).when(mockTxChain).newReadWriteTransaction();
399 exporter.onNodeConnectorUpdated(new NodeConnectorUpdatedBuilder().setNodeConnectorRef(
400 new NodeConnectorRef(invNodeConnID)).setId(ncKey.getId()).addAugmentation(
401 FlowCapableNodeConnectorUpdated.class,
402 new FlowCapableNodeConnectorUpdatedBuilder().build()).build());
404 waitForSubmit(submitLatch);
406 ArgumentCaptor<TerminationPoint> mergedNode = ArgumentCaptor.forClass(TerminationPoint.class);
407 NodeId expNodeId = new NodeId("node1");
408 TpId expTpId = new TpId("tp1");
409 InstanceIdentifier<TerminationPoint> expTpPath = topologyIID.child(
410 Node.class, new NodeKey(expNodeId)).child(TerminationPoint.class,
411 new TerminationPointKey(expTpId));
412 verify(mockTx).merge(eq(LogicalDatastoreType.OPERATIONAL), eq(expTpPath),
413 mergedNode.capture(), eq(true));
414 assertEquals("getTpId", expTpId, mergedNode.getValue().getTpId());
415 InventoryNodeConnector augmentation = mergedNode.getValue().getAugmentation(
416 InventoryNodeConnector.class);
417 assertNotNull("Missing augmentation", augmentation);
418 assertEquals("getInventoryNodeConnectorRef", new NodeConnectorRef(invNodeConnID),
419 augmentation.getInventoryNodeConnectorRef());
422 @SuppressWarnings("rawtypes")
424 public void testOnNodeConnectorUpdatedWithLinkStateDown() {
426 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
427 nodeKey = newInvNodeKey("node1");
429 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey ncKey =
430 newInvNodeConnKey("tp1");
432 InstanceIdentifier<?> invNodeConnID = newNodeConnID(nodeKey, ncKey);
434 List<Link> linkList = Arrays.asList(newLink("link1", newSourceTp("tp1"), newDestTp("dest")));
435 Topology topology = new TopologyBuilder().setLink(linkList).build();
437 ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class);
438 doReturn(Futures.immediateCheckedFuture(Optional.of(topology))).when(mockTx)
439 .read(LogicalDatastoreType.OPERATIONAL, topologyIID);
440 setupStubbedSubmit(mockTx);
442 CountDownLatch deleteLatch = new CountDownLatch(1);
443 ArgumentCaptor<InstanceIdentifier> deletedLinkIDs =
444 ArgumentCaptor.forClass(InstanceIdentifier.class);
445 setupStubbedDeletes(mockTx, deletedLinkIDs, deleteLatch);
447 doReturn(mockTx).when(mockTxChain).newReadWriteTransaction();
449 exporter.onNodeConnectorUpdated(new NodeConnectorUpdatedBuilder().setNodeConnectorRef(
450 new NodeConnectorRef(invNodeConnID)).setId(ncKey.getId()).addAugmentation(
451 FlowCapableNodeConnectorUpdated.class,
452 new FlowCapableNodeConnectorUpdatedBuilder().setState(
453 new StateBuilder().setLinkDown(true).build()).build()).build());
455 waitForDeletes(1, deleteLatch);
457 InstanceIdentifier<TerminationPoint> expTpPath = topologyIID.child(
458 Node.class, new NodeKey(new NodeId("node1"))).child(TerminationPoint.class,
459 new TerminationPointKey(new TpId("tp1")));
461 verify(mockTx).merge(eq(LogicalDatastoreType.OPERATIONAL), eq(expTpPath),
462 any(TerminationPoint.class), eq(true));
464 assertDeletedIDs(new InstanceIdentifier[]{topologyIID.child(Link.class,
465 linkList.get(0).getKey())}, deletedLinkIDs);
469 @SuppressWarnings("rawtypes")
471 public void testOnNodeConnectorUpdatedWithPortDown() {
473 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
474 nodeKey = newInvNodeKey("node1");
476 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey ncKey =
477 newInvNodeConnKey("tp1");
479 InstanceIdentifier<?> invNodeConnID = newNodeConnID(nodeKey, ncKey);
481 List<Link> linkList = Arrays.asList(newLink("link1", newSourceTp("tp1"), newDestTp("dest")));
482 Topology topology = new TopologyBuilder().setLink(linkList).build();
484 ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class);
485 doReturn(Futures.immediateCheckedFuture(Optional.of(topology))).when(mockTx)
486 .read(LogicalDatastoreType.OPERATIONAL, topologyIID);
487 setupStubbedSubmit(mockTx);
489 CountDownLatch deleteLatch = new CountDownLatch(1);
490 ArgumentCaptor<InstanceIdentifier> deletedLinkIDs =
491 ArgumentCaptor.forClass(InstanceIdentifier.class);
492 setupStubbedDeletes(mockTx, deletedLinkIDs, deleteLatch);
494 doReturn(mockTx).when(mockTxChain).newReadWriteTransaction();
496 exporter.onNodeConnectorUpdated(new NodeConnectorUpdatedBuilder().setNodeConnectorRef(
497 new NodeConnectorRef(invNodeConnID)).setId(ncKey.getId()).addAugmentation(
498 FlowCapableNodeConnectorUpdated.class,
499 new FlowCapableNodeConnectorUpdatedBuilder().setConfiguration(
500 new PortConfig(true, true, true, true)).build()).build());
502 waitForDeletes(1, deleteLatch);
504 InstanceIdentifier<TerminationPoint> expTpPath = topologyIID.child(
505 Node.class, new NodeKey(new NodeId("node1"))).child(TerminationPoint.class,
506 new TerminationPointKey(new TpId("tp1")));
508 verify(mockTx).merge(eq(LogicalDatastoreType.OPERATIONAL), eq(expTpPath),
509 any(TerminationPoint.class), eq(true));
511 assertDeletedIDs(new InstanceIdentifier[]{topologyIID.child(Link.class,
512 linkList.get(0).getKey())}, deletedLinkIDs);
516 public void testOnLinkDiscovered() {
518 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
519 sourceNodeKey = newInvNodeKey("sourceNode");
520 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey
521 sourceNodeConnKey = newInvNodeConnKey("sourceTP");
522 InstanceIdentifier<?> sourceConnID = newNodeConnID(sourceNodeKey, sourceNodeConnKey);
524 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
525 destNodeKey = newInvNodeKey("destNode");
526 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey
527 destNodeConnKey = newInvNodeConnKey("destTP");
528 InstanceIdentifier<?> destConnID = newNodeConnID(destNodeKey, destNodeConnKey);
530 ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class);
531 CountDownLatch submitLatch = setupStubbedSubmit(mockTx);
532 doReturn(mockTx).when(mockTxChain).newReadWriteTransaction();
534 exporter.onLinkDiscovered(new LinkDiscoveredBuilder().setSource(
535 new NodeConnectorRef(sourceConnID)).setDestination(
536 new NodeConnectorRef(destConnID)).build());
538 waitForSubmit(submitLatch);
540 ArgumentCaptor<Link> mergedNode = ArgumentCaptor.forClass(Link.class);
541 verify(mockTx).put(eq(LogicalDatastoreType.OPERATIONAL), eq(topologyIID.child(
542 Link.class, new LinkKey(new LinkId(sourceNodeConnKey.getId())))),
543 mergedNode.capture(), eq(true));
544 assertEquals("Source node ID", "sourceNode",
545 mergedNode.getValue().getSource().getSourceNode().getValue());
546 assertEquals("Dest TP ID", "sourceTP",
547 mergedNode.getValue().getSource().getSourceTp().getValue());
548 assertEquals("Dest node ID", "destNode",
549 mergedNode.getValue().getDestination().getDestNode().getValue());
550 assertEquals("Dest TP ID", "destTP",
551 mergedNode.getValue().getDestination().getDestTp().getValue());
555 public void testOnLinkRemoved() {
557 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
558 sourceNodeKey = newInvNodeKey("sourceNode");
559 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey
560 sourceNodeConnKey = newInvNodeConnKey("sourceTP");
561 InstanceIdentifier<?> sourceConnID = newNodeConnID(sourceNodeKey, sourceNodeConnKey);
563 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
564 destNodeKey = newInvNodeKey("destNode");
565 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey
566 destNodeConnKey = newInvNodeConnKey("destTP");
567 InstanceIdentifier<?> destConnID = newNodeConnID(destNodeKey, destNodeConnKey);
569 Link link = newLink(sourceNodeConnKey.getId().getValue(), newSourceTp(sourceNodeConnKey.getId().getValue()),
570 newDestTp(destNodeConnKey.getId().getValue()));
572 ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class);
573 CountDownLatch submitLatch = setupStubbedSubmit(mockTx);
574 doReturn(mockTx).when(mockTxChain).newReadWriteTransaction();
575 doReturn(Futures.immediateCheckedFuture(Optional.of(link))).when(mockTx).read(LogicalDatastoreType.OPERATIONAL, topologyIID.child(
576 Link.class, new LinkKey(new LinkId(sourceNodeConnKey.getId()))));
578 exporter.onLinkRemoved(new LinkRemovedBuilder().setSource(
579 new NodeConnectorRef(sourceConnID)).setDestination(
580 new NodeConnectorRef(destConnID)).build());
582 waitForSubmit(submitLatch);
584 verify(mockTx).delete(LogicalDatastoreType.OPERATIONAL, topologyIID.child(
585 Link.class, new LinkKey(new LinkId(sourceNodeConnKey.getId()))));
589 public void testOnLinkRemovedLinkDoesNotExist() {
591 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
592 sourceNodeKey = newInvNodeKey("sourceNode");
593 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey
594 sourceNodeConnKey = newInvNodeConnKey("sourceTP");
595 InstanceIdentifier<?> sourceConnID = newNodeConnID(sourceNodeKey, sourceNodeConnKey);
597 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
598 destNodeKey = newInvNodeKey("destNode");
599 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey
600 destNodeConnKey = newInvNodeConnKey("destTP");
601 InstanceIdentifier<?> destConnID = newNodeConnID(destNodeKey, destNodeConnKey);
603 ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class);
604 CountDownLatch submitLatch = setupStubbedSubmit(mockTx);
605 doReturn(mockTx).when(mockTxChain).newReadWriteTransaction();
606 doReturn(Futures.immediateCheckedFuture(Optional.<Link>absent())).when(mockTx).read(LogicalDatastoreType.OPERATIONAL, topologyIID.child(
607 Link.class, new LinkKey(new LinkId(sourceNodeConnKey.getId()))));
609 exporter.onLinkRemoved(new LinkRemovedBuilder().setSource(
610 new NodeConnectorRef(sourceConnID)).setDestination(
611 new NodeConnectorRef(destConnID)).build());
613 waitForSubmit(submitLatch);
615 verify(mockTx, never()).delete(LogicalDatastoreType.OPERATIONAL, topologyIID.child(
616 Link.class, new LinkKey(new LinkId(sourceNodeConnKey.getId()))));
619 private void verifyMockTx(ReadWriteTransaction mockTx) {
620 InOrder inOrder = inOrder(mockTx);
621 inOrder.verify(mockTx, atLeast(0)).submit();
622 inOrder.verify(mockTx, never()).delete(eq(LogicalDatastoreType.OPERATIONAL),
623 any(InstanceIdentifier.class));
626 @SuppressWarnings("rawtypes")
627 private void assertDeletedIDs(InstanceIdentifier[] expDeletedIIDs,
628 ArgumentCaptor<InstanceIdentifier> deletedLinkIDs) {
629 Set<InstanceIdentifier> actualIIDs = new HashSet<>(deletedLinkIDs.getAllValues());
630 for(InstanceIdentifier id: expDeletedIIDs) {
631 assertTrue("Missing expected deleted IID " + id, actualIIDs.contains(id));
635 private void setReadFutureAsync(final Topology topology,
636 final SettableFuture<Optional<Topology>> readFuture) {
640 Uninterruptibles.sleepUninterruptibly(50, TimeUnit.MILLISECONDS);
641 readFuture.set(Optional.of(topology));
647 private void waitForSubmit(CountDownLatch latch) {
648 assertEquals("Transaction submitted", true,
649 Uninterruptibles.awaitUninterruptibly(latch, 5, TimeUnit.SECONDS));
652 private void waitForDeletes(int expDeleteCalls, final CountDownLatch latch) {
653 boolean done = Uninterruptibles.awaitUninterruptibly(latch, 5, TimeUnit.SECONDS);
655 fail("Expected " + expDeleteCalls + " delete calls. Actual: " +
656 (expDeleteCalls - latch.getCount()));
660 private CountDownLatch setupStubbedSubmit(ReadWriteTransaction mockTx) {
661 final CountDownLatch latch = new CountDownLatch(1);
662 doAnswer(new Answer<CheckedFuture<Void, TransactionCommitFailedException>>() {
664 public CheckedFuture<Void, TransactionCommitFailedException> answer(
665 InvocationOnMock invocation) {
667 return Futures.immediateCheckedFuture(null);
669 }).when(mockTx).submit();
674 @SuppressWarnings("rawtypes")
675 private void setupStubbedDeletes(ReadWriteTransaction mockTx,
676 ArgumentCaptor<InstanceIdentifier> deletedLinkIDs, final CountDownLatch latch) {
677 doAnswer(new Answer<Void>() {
679 public Void answer(InvocationOnMock invocation) {
683 }).when(mockTx).delete(eq(LogicalDatastoreType.OPERATIONAL), deletedLinkIDs.capture());
686 private org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
687 newInvNodeKey(String id) {
688 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey nodeKey =
689 new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey(
690 new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.
691 rev130819.NodeId(id));
695 private NodeConnectorKey newInvNodeConnKey(String id) {
696 return new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey(
697 new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.
698 NodeConnectorId(id));
701 private KeyedInstanceIdentifier<NodeConnector, NodeConnectorKey> newNodeConnID(
702 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey nodeKey,
703 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey ncKey) {
704 return InstanceIdentifier.create(Nodes.class).child(
705 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
706 nodeKey).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.
707 rev130819.node.NodeConnector.class, ncKey);
710 private Link newLink(String id, Source source, Destination dest) {
711 return new LinkBuilder().setLinkId(new LinkId(id))
712 .setSource(source).setDestination(dest).build();
715 private Destination newDestTp(String id) {
716 return new DestinationBuilder().setDestTp(new TpId(id)).build();
719 private Source newSourceTp(String id) {
720 return new SourceBuilder().setSourceTp(new TpId(id)).build();
723 private Destination newDestNode(String id) {
724 return new DestinationBuilder().setDestNode(new NodeId(id)).build();
727 private Source newSourceNode(String id) {
728 return new SourceBuilder().setSourceNode(new NodeId(id)).build();