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 static org.junit.Assert.fail;
12 import static org.junit.Assert.assertEquals;
13 import static org.junit.Assert.assertTrue;
14 import static org.junit.Assert.assertNotNull;
15 import static org.mockito.Mockito.doReturn;
16 import static org.mockito.Mockito.doAnswer;
17 import static org.mockito.Mockito.any;
18 import static org.mockito.Mockito.eq;
19 import static org.mockito.Mockito.mock;
20 import static org.mockito.Mockito.inOrder;
21 import static org.mockito.Mockito.atLeast;
22 import static org.mockito.Mockito.never;
23 import static org.mockito.Mockito.verify;
25 import java.util.Arrays;
26 import java.util.HashSet;
27 import java.util.List;
29 import java.util.concurrent.CountDownLatch;
30 import java.util.concurrent.ExecutorService;
31 import java.util.concurrent.Executors;
32 import java.util.concurrent.TimeUnit;
34 import org.junit.After;
35 import org.junit.Before;
36 import org.junit.Test;
37 import org.mockito.ArgumentCaptor;
38 import org.mockito.InOrder;
39 import org.mockito.Mock;
40 import org.mockito.MockitoAnnotations;
41 import org.mockito.invocation.InvocationOnMock;
42 import org.mockito.stubbing.Answer;
43 import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
44 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
45 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
46 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
47 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
48 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
49 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorUpdated;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorUpdatedBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeUpdated;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeUpdatedBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.LinkDiscoveredBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.LinkRemovedBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortConfig;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.flow.capable.port.StateBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRemovedBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorUpdatedBuilder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRemovedBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeUpdatedBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.topology.inventory.rev131030.InventoryNode;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.topology.inventory.rev131030.InventoryNodeConnector;
69 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.LinkId;
70 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
71 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
72 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
73 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId;
74 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.Destination;
75 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.DestinationBuilder;
76 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.Source;
77 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.SourceBuilder;
78 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
79 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder;
80 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
81 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link;
82 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.LinkBuilder;
83 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.LinkKey;
84 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
85 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
86 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
87 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
88 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
89 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
91 import com.google.common.base.Optional;
92 import com.google.common.util.concurrent.CheckedFuture;
93 import com.google.common.util.concurrent.Futures;
94 import com.google.common.util.concurrent.SettableFuture;
95 import com.google.common.util.concurrent.Uninterruptibles;
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 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
139 nodeKey = newInvNodeKey("node1");
140 InstanceIdentifier<?> invNodeID = InstanceIdentifier.create(Nodes.class).child(
141 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
144 List<Link> linkList = Arrays.asList(
145 newLink("link1", newSourceNode("node1"), newDestNode("dest")),
146 newLink("link2", newSourceNode("source"), newDestNode("node1")),
147 newLink("link2", newSourceNode("source2"), newDestNode("dest2")));
148 final Topology topology = new TopologyBuilder().setLink(linkList).build();
150 InstanceIdentifier[] expDeletedIIDs = {
151 topologyIID.child(Link.class, linkList.get(0).getKey()),
152 topologyIID.child(Link.class, linkList.get(1).getKey()),
153 topologyIID.child(Node.class, new NodeKey(new NodeId("node1")))
156 SettableFuture<Optional<Topology>> readFuture = SettableFuture.create();
157 ReadWriteTransaction mockTx1 = mock(ReadWriteTransaction.class);
158 doReturn(Futures.makeChecked(readFuture, ReadFailedException.MAPPER)).when(mockTx1)
159 .read(LogicalDatastoreType.OPERATIONAL, topologyIID);
161 CountDownLatch submitLatch1 = setupStubbedSubmit(mockTx1);
163 int expDeleteCalls = expDeletedIIDs.length;
164 CountDownLatch deleteLatch = new CountDownLatch(expDeleteCalls);
165 ArgumentCaptor<InstanceIdentifier> deletedLinkIDs =
166 ArgumentCaptor.forClass(InstanceIdentifier.class);
167 setupStubbedDeletes(mockTx1, deletedLinkIDs, deleteLatch);
169 ReadWriteTransaction mockTx2 = mock(ReadWriteTransaction.class);
170 setupStubbedDeletes(mockTx2, deletedLinkIDs, deleteLatch);
171 CountDownLatch submitLatch2 = setupStubbedSubmit(mockTx2);
173 doReturn(mockTx1).doReturn(mockTx2).when(mockTxChain).newReadWriteTransaction();
175 exporter.onNodeRemoved(new NodeRemovedBuilder().setNodeRef(new NodeRef(invNodeID)).build());
177 waitForSubmit(submitLatch1);
179 setReadFutureAsync(topology, readFuture);
181 waitForDeletes(expDeleteCalls, deleteLatch);
183 waitForSubmit(submitLatch2);
185 assertDeletedIDs(expDeletedIIDs, deletedLinkIDs);
187 verifyMockTx(mockTx1);
188 verifyMockTx(mockTx2);
191 @SuppressWarnings({ "rawtypes" })
193 public void testOnNodeRemovedWithNoTopology() {
195 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
196 nodeKey = newInvNodeKey("node1");
197 InstanceIdentifier<?> invNodeID = InstanceIdentifier.create(Nodes.class).child(
198 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
201 InstanceIdentifier[] expDeletedIIDs = {
202 topologyIID.child(Node.class, new NodeKey(new NodeId("node1")))
205 ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class);
206 doReturn(Futures.immediateCheckedFuture(Optional.absent())).when(mockTx)
207 .read(LogicalDatastoreType.OPERATIONAL, topologyIID);
208 CountDownLatch submitLatch = setupStubbedSubmit(mockTx);
210 CountDownLatch deleteLatch = new CountDownLatch(1);
211 ArgumentCaptor<InstanceIdentifier> deletedLinkIDs =
212 ArgumentCaptor.forClass(InstanceIdentifier.class);
213 setupStubbedDeletes(mockTx, deletedLinkIDs, deleteLatch);
215 doReturn(mockTx).when(mockTxChain).newReadWriteTransaction();
217 exporter.onNodeRemoved(new NodeRemovedBuilder().setNodeRef(new NodeRef(invNodeID)).build());
219 waitForSubmit(submitLatch);
221 waitForDeletes(1, deleteLatch);
223 assertDeletedIDs(expDeletedIIDs, deletedLinkIDs);
226 @SuppressWarnings("rawtypes")
228 public void testOnNodeConnectorRemoved() {
230 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
231 nodeKey = newInvNodeKey("node1");
233 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey ncKey =
234 newInvNodeConnKey("tp1");
236 InstanceIdentifier<?> invNodeConnID = newNodeConnID(nodeKey, ncKey);
238 List<Link> linkList = Arrays.asList(
239 newLink("link1", newSourceTp("tp1"), newDestTp("dest")),
240 newLink("link2", newSourceTp("source"), newDestTp("tp1")),
241 newLink("link3", newSourceTp("source2"), newDestTp("dest2")));
242 final Topology topology = new TopologyBuilder().setLink(linkList).build();
244 InstanceIdentifier[] expDeletedIIDs = {
245 topologyIID.child(Link.class, linkList.get(0).getKey()),
246 topologyIID.child(Link.class, linkList.get(1).getKey()),
247 topologyIID.child(Node.class, new NodeKey(new NodeId("node1")))
248 .child(TerminationPoint.class, new TerminationPointKey(new TpId("tp1")))
251 final SettableFuture<Optional<Topology>> readFuture = SettableFuture.create();
252 ReadWriteTransaction mockTx1 = mock(ReadWriteTransaction.class);
253 doReturn(Futures.makeChecked(readFuture, ReadFailedException.MAPPER)).when(mockTx1)
254 .read(LogicalDatastoreType.OPERATIONAL, topologyIID);
256 CountDownLatch submitLatch1 = setupStubbedSubmit(mockTx1);
258 int expDeleteCalls = expDeletedIIDs.length;
259 CountDownLatch deleteLatch = new CountDownLatch(expDeleteCalls);
260 ArgumentCaptor<InstanceIdentifier> deletedLinkIDs =
261 ArgumentCaptor.forClass(InstanceIdentifier.class);
262 setupStubbedDeletes(mockTx1, deletedLinkIDs, deleteLatch);
264 ReadWriteTransaction mockTx2 = mock(ReadWriteTransaction.class);
265 setupStubbedDeletes(mockTx2, deletedLinkIDs, deleteLatch);
266 CountDownLatch submitLatch2 = setupStubbedSubmit(mockTx2);
268 doReturn(mockTx1).doReturn(mockTx2).when(mockTxChain).newReadWriteTransaction();
270 exporter.onNodeConnectorRemoved(new NodeConnectorRemovedBuilder().setNodeConnectorRef(
271 new NodeConnectorRef(invNodeConnID)).build());
273 waitForSubmit(submitLatch1);
275 setReadFutureAsync(topology, readFuture);
277 waitForDeletes(expDeleteCalls, deleteLatch);
279 waitForSubmit(submitLatch2);
281 assertDeletedIDs(expDeletedIIDs, deletedLinkIDs);
283 verifyMockTx(mockTx1);
284 verifyMockTx(mockTx2);
287 @SuppressWarnings("rawtypes")
289 public void testOnNodeConnectorRemovedWithNoTopology() {
291 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
292 nodeKey = newInvNodeKey("node1");
294 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey ncKey =
295 newInvNodeConnKey("tp1");
297 InstanceIdentifier<?> invNodeConnID = newNodeConnID(nodeKey, ncKey);
299 InstanceIdentifier[] expDeletedIIDs = {
300 topologyIID.child(Node.class, new NodeKey(new NodeId("node1")))
301 .child(TerminationPoint.class, new TerminationPointKey(new TpId("tp1")))
304 ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class);
305 doReturn(Futures.immediateCheckedFuture(Optional.absent())).when(mockTx)
306 .read(LogicalDatastoreType.OPERATIONAL, topologyIID);
307 CountDownLatch submitLatch = setupStubbedSubmit(mockTx);
309 CountDownLatch deleteLatch = new CountDownLatch(1);
310 ArgumentCaptor<InstanceIdentifier> deletedLinkIDs =
311 ArgumentCaptor.forClass(InstanceIdentifier.class);
312 setupStubbedDeletes(mockTx, deletedLinkIDs, deleteLatch);
314 doReturn(mockTx).when(mockTxChain).newReadWriteTransaction();
316 exporter.onNodeConnectorRemoved(new NodeConnectorRemovedBuilder().setNodeConnectorRef(
317 new NodeConnectorRef(invNodeConnID)).build());
319 waitForSubmit(submitLatch);
321 waitForDeletes(1, deleteLatch);
323 assertDeletedIDs(expDeletedIIDs, deletedLinkIDs);
327 public void testOnNodeUpdated() {
329 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
330 nodeKey = newInvNodeKey("node1");
331 InstanceIdentifier<?> invNodeID = InstanceIdentifier.create(Nodes.class).child(
332 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
335 ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class);
336 CountDownLatch submitLatch = setupStubbedSubmit(mockTx);
337 doReturn(mockTx).when(mockTxChain).newReadWriteTransaction();
339 exporter.onNodeUpdated(new NodeUpdatedBuilder().setNodeRef(new NodeRef(invNodeID))
340 .setId(nodeKey.getId()).addAugmentation(FlowCapableNodeUpdated.class,
341 new FlowCapableNodeUpdatedBuilder().build()).build());
343 waitForSubmit(submitLatch);
345 ArgumentCaptor<Node> mergedNode = ArgumentCaptor.forClass(Node.class);
346 NodeId expNodeId = new NodeId("node1");
347 verify(mockTx).merge(eq(LogicalDatastoreType.OPERATIONAL), eq(topologyIID.child(Node.class,
348 new NodeKey(expNodeId))), mergedNode.capture(), eq(true));
349 assertEquals("getNodeId", expNodeId, mergedNode.getValue().getNodeId());
350 InventoryNode augmentation = mergedNode.getValue().getAugmentation(InventoryNode.class);
351 assertNotNull("Missing augmentation", augmentation);
352 assertEquals("getInventoryNodeRef", new NodeRef(invNodeID), augmentation.getInventoryNodeRef());
355 @SuppressWarnings("rawtypes")
357 public void testOnNodeConnectorUpdated() {
359 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
360 nodeKey = newInvNodeKey("node1");
362 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey ncKey =
363 newInvNodeConnKey("tp1");
365 InstanceIdentifier<?> invNodeConnID = newNodeConnID(nodeKey, ncKey);
367 ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class);
368 CountDownLatch submitLatch = setupStubbedSubmit(mockTx);
369 doReturn(mockTx).when(mockTxChain).newReadWriteTransaction();
371 exporter.onNodeConnectorUpdated(new NodeConnectorUpdatedBuilder().setNodeConnectorRef(
372 new NodeConnectorRef(invNodeConnID)).setId(ncKey.getId()).addAugmentation(
373 FlowCapableNodeConnectorUpdated.class,
374 new FlowCapableNodeConnectorUpdatedBuilder().build()).build());
376 waitForSubmit(submitLatch);
378 ArgumentCaptor<TerminationPoint> mergedNode = ArgumentCaptor.forClass(TerminationPoint.class);
379 NodeId expNodeId = new NodeId("node1");
380 TpId expTpId = new TpId("tp1");
381 InstanceIdentifier<TerminationPoint> expTpPath = topologyIID.child(
382 Node.class, new NodeKey(expNodeId)).child(TerminationPoint.class,
383 new TerminationPointKey(expTpId));
384 verify(mockTx).merge(eq(LogicalDatastoreType.OPERATIONAL), eq(expTpPath),
385 mergedNode.capture(), eq(true));
386 assertEquals("getTpId", expTpId, mergedNode.getValue().getTpId());
387 InventoryNodeConnector augmentation = mergedNode.getValue().getAugmentation(
388 InventoryNodeConnector.class);
389 assertNotNull("Missing augmentation", augmentation);
390 assertEquals("getInventoryNodeConnectorRef", new NodeConnectorRef(invNodeConnID),
391 augmentation.getInventoryNodeConnectorRef());
394 @SuppressWarnings("rawtypes")
396 public void testOnNodeConnectorUpdatedWithLinkStateDown() {
398 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
399 nodeKey = newInvNodeKey("node1");
401 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey ncKey =
402 newInvNodeConnKey("tp1");
404 InstanceIdentifier<?> invNodeConnID = newNodeConnID(nodeKey, ncKey);
406 List<Link> linkList = Arrays.asList(newLink("link1", newSourceTp("tp1"), newDestTp("dest")));
407 Topology topology = new TopologyBuilder().setLink(linkList).build();
409 ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class);
410 doReturn(Futures.immediateCheckedFuture(Optional.of(topology))).when(mockTx)
411 .read(LogicalDatastoreType.OPERATIONAL, topologyIID);
412 setupStubbedSubmit(mockTx);
414 CountDownLatch deleteLatch = new CountDownLatch(1);
415 ArgumentCaptor<InstanceIdentifier> deletedLinkIDs =
416 ArgumentCaptor.forClass(InstanceIdentifier.class);
417 setupStubbedDeletes(mockTx, deletedLinkIDs, deleteLatch);
419 doReturn(mockTx).when(mockTxChain).newReadWriteTransaction();
421 exporter.onNodeConnectorUpdated(new NodeConnectorUpdatedBuilder().setNodeConnectorRef(
422 new NodeConnectorRef(invNodeConnID)).setId(ncKey.getId()).addAugmentation(
423 FlowCapableNodeConnectorUpdated.class,
424 new FlowCapableNodeConnectorUpdatedBuilder().setState(
425 new StateBuilder().setLinkDown(true).build()).build()).build());
427 waitForDeletes(1, deleteLatch);
429 InstanceIdentifier<TerminationPoint> expTpPath = topologyIID.child(
430 Node.class, new NodeKey(new NodeId("node1"))).child(TerminationPoint.class,
431 new TerminationPointKey(new TpId("tp1")));
433 verify(mockTx).merge(eq(LogicalDatastoreType.OPERATIONAL), eq(expTpPath),
434 any(TerminationPoint.class), eq(true));
436 assertDeletedIDs(new InstanceIdentifier[]{topologyIID.child(Link.class,
437 linkList.get(0).getKey())}, deletedLinkIDs);
441 @SuppressWarnings("rawtypes")
443 public void testOnNodeConnectorUpdatedWithPortDown() {
445 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
446 nodeKey = newInvNodeKey("node1");
448 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey ncKey =
449 newInvNodeConnKey("tp1");
451 InstanceIdentifier<?> invNodeConnID = newNodeConnID(nodeKey, ncKey);
453 List<Link> linkList = Arrays.asList(newLink("link1", newSourceTp("tp1"), newDestTp("dest")));
454 Topology topology = new TopologyBuilder().setLink(linkList).build();
456 ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class);
457 doReturn(Futures.immediateCheckedFuture(Optional.of(topology))).when(mockTx)
458 .read(LogicalDatastoreType.OPERATIONAL, topologyIID);
459 setupStubbedSubmit(mockTx);
461 CountDownLatch deleteLatch = new CountDownLatch(1);
462 ArgumentCaptor<InstanceIdentifier> deletedLinkIDs =
463 ArgumentCaptor.forClass(InstanceIdentifier.class);
464 setupStubbedDeletes(mockTx, deletedLinkIDs, deleteLatch);
466 doReturn(mockTx).when(mockTxChain).newReadWriteTransaction();
468 exporter.onNodeConnectorUpdated(new NodeConnectorUpdatedBuilder().setNodeConnectorRef(
469 new NodeConnectorRef(invNodeConnID)).setId(ncKey.getId()).addAugmentation(
470 FlowCapableNodeConnectorUpdated.class,
471 new FlowCapableNodeConnectorUpdatedBuilder().setConfiguration(
472 new PortConfig(true, true, true, true)).build()).build());
474 waitForDeletes(1, deleteLatch);
476 InstanceIdentifier<TerminationPoint> expTpPath = topologyIID.child(
477 Node.class, new NodeKey(new NodeId("node1"))).child(TerminationPoint.class,
478 new TerminationPointKey(new TpId("tp1")));
480 verify(mockTx).merge(eq(LogicalDatastoreType.OPERATIONAL), eq(expTpPath),
481 any(TerminationPoint.class), eq(true));
483 assertDeletedIDs(new InstanceIdentifier[]{topologyIID.child(Link.class,
484 linkList.get(0).getKey())}, deletedLinkIDs);
488 public void testOnLinkDiscovered() {
490 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
491 sourceNodeKey = newInvNodeKey("sourceNode");
492 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey
493 sourceNodeConnKey = newInvNodeConnKey("sourceTP");
494 InstanceIdentifier<?> sourceConnID = newNodeConnID(sourceNodeKey, sourceNodeConnKey);
496 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
497 destNodeKey = newInvNodeKey("destNode");
498 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey
499 destNodeConnKey = newInvNodeConnKey("destTP");
500 InstanceIdentifier<?> destConnID = newNodeConnID(destNodeKey, destNodeConnKey);
502 ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class);
503 CountDownLatch submitLatch = setupStubbedSubmit(mockTx);
504 doReturn(mockTx).when(mockTxChain).newReadWriteTransaction();
506 exporter.onLinkDiscovered(new LinkDiscoveredBuilder().setSource(
507 new NodeConnectorRef(sourceConnID)).setDestination(
508 new NodeConnectorRef(destConnID)).build());
510 waitForSubmit(submitLatch);
512 ArgumentCaptor<Link> mergedNode = ArgumentCaptor.forClass(Link.class);
513 verify(mockTx).merge(eq(LogicalDatastoreType.OPERATIONAL), eq(topologyIID.child(
514 Link.class, new LinkKey(new LinkId(sourceNodeConnKey.getId())))),
515 mergedNode.capture(), eq(true));
516 assertEquals("Source node ID", "sourceNode",
517 mergedNode.getValue().getSource().getSourceNode().getValue());
518 assertEquals("Dest TP ID", "sourceTP",
519 mergedNode.getValue().getSource().getSourceTp().getValue());
520 assertEquals("Dest node ID", "destNode",
521 mergedNode.getValue().getDestination().getDestNode().getValue());
522 assertEquals("Dest TP ID", "destTP",
523 mergedNode.getValue().getDestination().getDestTp().getValue());
527 public void testOnLinkRemoved() {
529 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
530 sourceNodeKey = newInvNodeKey("sourceNode");
531 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey
532 sourceNodeConnKey = newInvNodeConnKey("sourceTP");
533 InstanceIdentifier<?> sourceConnID = newNodeConnID(sourceNodeKey, sourceNodeConnKey);
535 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
536 destNodeKey = newInvNodeKey("destNode");
537 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey
538 destNodeConnKey = newInvNodeConnKey("destTP");
539 InstanceIdentifier<?> destConnID = newNodeConnID(destNodeKey, destNodeConnKey);
541 ReadWriteTransaction mockTx = mock(ReadWriteTransaction.class);
542 CountDownLatch submitLatch = setupStubbedSubmit(mockTx);
543 doReturn(mockTx).when(mockTxChain).newReadWriteTransaction();
545 exporter.onLinkRemoved(new LinkRemovedBuilder().setSource(
546 new NodeConnectorRef(sourceConnID)).setDestination(
547 new NodeConnectorRef(destConnID)).build());
549 waitForSubmit(submitLatch);
551 verify(mockTx).delete(LogicalDatastoreType.OPERATIONAL, topologyIID.child(
552 Link.class, new LinkKey(new LinkId(sourceNodeConnKey.getId()))));
555 private void verifyMockTx(ReadWriteTransaction mockTx) {
556 InOrder inOrder = inOrder(mockTx);
557 inOrder.verify(mockTx, atLeast(0)).submit();
558 inOrder.verify(mockTx, never()).delete(eq(LogicalDatastoreType.OPERATIONAL),
559 any(InstanceIdentifier.class));
562 @SuppressWarnings("rawtypes")
563 private void assertDeletedIDs(InstanceIdentifier[] expDeletedIIDs,
564 ArgumentCaptor<InstanceIdentifier> deletedLinkIDs) {
565 Set<InstanceIdentifier> actualIIDs = new HashSet<>(deletedLinkIDs.getAllValues());
566 for(InstanceIdentifier id: expDeletedIIDs) {
567 assertTrue("Missing expected deleted IID " + id, actualIIDs.contains(id));
571 private void setReadFutureAsync(final Topology topology,
572 final SettableFuture<Optional<Topology>> readFuture) {
576 Uninterruptibles.sleepUninterruptibly(50, TimeUnit.MILLISECONDS);
577 readFuture.set(Optional.of(topology));
583 private void waitForSubmit(CountDownLatch latch) {
584 assertEquals("Transaction submitted", true,
585 Uninterruptibles.awaitUninterruptibly(latch, 5, TimeUnit.SECONDS));
588 private void waitForDeletes(int expDeleteCalls, final CountDownLatch latch) {
589 boolean done = Uninterruptibles.awaitUninterruptibly(latch, 5, TimeUnit.SECONDS);
591 fail("Expected " + expDeleteCalls + " delete calls. Actual: " +
592 (expDeleteCalls - latch.getCount()));
596 private CountDownLatch setupStubbedSubmit(ReadWriteTransaction mockTx) {
597 final CountDownLatch latch = new CountDownLatch(1);
598 doAnswer(new Answer<CheckedFuture<Void, TransactionCommitFailedException>>() {
600 public CheckedFuture<Void, TransactionCommitFailedException> answer(
601 InvocationOnMock invocation) {
603 return Futures.immediateCheckedFuture(null);
605 }).when(mockTx).submit();
610 @SuppressWarnings("rawtypes")
611 private void setupStubbedDeletes(ReadWriteTransaction mockTx,
612 ArgumentCaptor<InstanceIdentifier> deletedLinkIDs, final CountDownLatch latch) {
613 doAnswer(new Answer<Void>() {
615 public Void answer(InvocationOnMock invocation) {
619 }).when(mockTx).delete(eq(LogicalDatastoreType.OPERATIONAL), deletedLinkIDs.capture());
622 private org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
623 newInvNodeKey(String id) {
624 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey nodeKey =
625 new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey(
626 new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.
627 rev130819.NodeId(id));
631 private NodeConnectorKey newInvNodeConnKey(String id) {
632 return new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey(
633 new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.
634 NodeConnectorId(id));
637 private KeyedInstanceIdentifier<NodeConnector, NodeConnectorKey> newNodeConnID(
638 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey nodeKey,
639 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey ncKey) {
640 return InstanceIdentifier.create(Nodes.class).child(
641 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
642 nodeKey).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.
643 rev130819.node.NodeConnector.class, ncKey);
646 private Link newLink(String id, Source source, Destination dest) {
647 return new LinkBuilder().setLinkId(new LinkId(id))
648 .setSource(source).setDestination(dest).build();
651 private Destination newDestTp(String id) {
652 return new DestinationBuilder().setDestTp(new TpId(id)).build();
655 private Source newSourceTp(String id) {
656 return new SourceBuilder().setSourceTp(new TpId(id)).build();
659 private Destination newDestNode(String id) {
660 return new DestinationBuilder().setDestNode(new NodeId(id)).build();
663 private Source newSourceNode(String id) {
664 return new SourceBuilder().setSourceNode(new NodeId(id)).build();