Further migration of test code from legacy setters
[bgpcep.git] / bgp / topology-provider / src / test / java / org / opendaylight / bgpcep / bgp / topology / provider / LinkstateTopologyBuilderTest.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.bgpcep.bgp.topology.provider;
9
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertNotEquals;
12 import static org.junit.Assert.assertNotNull;
13 import static org.junit.Assert.assertNull;
14 import static org.junit.Assert.assertTrue;
15 import static org.junit.Assert.fail;
16 import static org.mockito.ArgumentMatchers.any;
17 import static org.mockito.Mockito.RETURNS_SMART_NULLS;
18 import static org.mockito.Mockito.doThrow;
19 import static org.mockito.Mockito.mock;
20 import static org.mockito.Mockito.never;
21 import static org.mockito.Mockito.spy;
22 import static org.mockito.Mockito.timeout;
23 import static org.mockito.Mockito.times;
24 import static org.mockito.Mockito.verify;
25 import static org.opendaylight.protocol.util.CheckUtil.checkNotPresentOperational;
26 import static org.opendaylight.protocol.util.CheckUtil.readDataOperational;
27
28 import com.google.common.collect.Lists;
29 import io.netty.buffer.Unpooled;
30 import java.nio.charset.StandardCharsets;
31 import java.util.ArrayList;
32 import java.util.Collections;
33 import java.util.List;
34 import java.util.concurrent.ExecutionException;
35 import org.junit.After;
36 import org.junit.Before;
37 import org.junit.Test;
38 import org.opendaylight.mdsal.binding.api.DataTreeModification;
39 import org.opendaylight.mdsal.binding.api.WriteTransaction;
40 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
41 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber;
42 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
43 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
44 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
45 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.AdministrativeGroup;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.Identifier;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.Ipv4RouterIdentifier;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.IsisAreaIdentifier;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.LinkstateAddressFamily;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.LinkstateSubsequentAddressFamily;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.ProtocolId;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.TopologyIdentifier;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.bgp.rib.rib.loc.rib.tables.routes.LinkstateRoutesCase;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.linkstate.attribute.UnreservedBandwidthBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.linkstate.attribute.UnreservedBandwidthKey;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.linkstate.object.type.link._case.LinkDescriptorsBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.linkstate.object.type.link._case.LocalNodeDescriptorsBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.linkstate.object.type.link._case.RemoteNodeDescriptorsBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.linkstate.object.type.node._case.NodeDescriptorsBuilder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.linkstate.object.type.prefix._case.AdvertisingNodeDescriptorsBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.linkstate.object.type.prefix._case.PrefixDescriptorsBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.linkstate.path.attribute.link.state.attribute.LinkAttributesCaseBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.linkstate.path.attribute.link.state.attribute.NodeAttributesCaseBuilder;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.linkstate.path.attribute.link.state.attribute.PrefixAttributesCaseBuilder;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.linkstate.path.attribute.link.state.attribute.link.attributes._case.LinkAttributesBuilder;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.linkstate.path.attribute.link.state.attribute.node.attributes._case.NodeAttributesBuilder;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.linkstate.path.attribute.link.state.attribute.prefix.attributes._case.PrefixAttributesBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.linkstate.routes.LinkstateRoutes;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.linkstate.routes.linkstate.routes.LinkstateRoute;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.linkstate.routes.linkstate.routes.LinkstateRouteBuilder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.linkstate.routes.linkstate.routes.LinkstateRouteKey;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.linkstate.routes.linkstate.routes.linkstate.route.Attributes1;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.linkstate.routes.linkstate.routes.linkstate.route.Attributes1Builder;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.node.identifier.c.router.identifier.IsisNodeCaseBuilder;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329.node.identifier.c.router.identifier.isis.node._case.IsisNodeBuilder;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.PathId;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.path.attributes.AttributesBuilder;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.path.attributes.attributes.OriginBuilder;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.rib.LocRib;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.Tables;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.TablesKey;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev180329.BgpOrigin;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network.concepts.rev131125.Bandwidth;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network.concepts.rev131125.IgpMetric;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network.concepts.rev131125.IsoSystemIdentifier;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network.concepts.rev131125.TeMetric;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.rsvp.rev150820.SrlgId;
89 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.isis.topology.rev131021.IgpLinkAttributes1;
90 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.isis.topology.rev131021.IgpNodeAttributes1;
91 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link;
92 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
93 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.Link1;
94 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.Node1;
95 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.igp.link.attributes.IgpLinkAttributes;
96 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.igp.node.attributes.IgpNodeAttributes;
97 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.igp.node.attributes.igp.node.attributes.Prefix;
98 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
99 import org.opendaylight.yangtools.yang.common.Uint16;
100 import org.opendaylight.yangtools.yang.common.Uint32;
101 import org.opendaylight.yangtools.yang.common.Uint64;
102 import org.opendaylight.yangtools.yang.common.Uint8;
103
104 public class LinkstateTopologyBuilderTest extends AbstractTopologyBuilderTest {
105
106     private static final String LINKSTATE_ROUTE_KEY = Unpooled.wrappedBuffer(
107         StandardCharsets.UTF_8.encode("linkstate-route")).array().toString();
108     private static final String ROUTER_1_ID = "127.0.0.1";
109     private static final String ROUTER_2_ID = "127.0.0.2";
110     private static final String NODE_1_PREFIX = "127.0.1.1/32";
111     private static final AsNumber NODE_1_AS = new AsNumber(Uint32.ONE);
112     private static final AsNumber NODE_2_AS = new AsNumber(Uint32.valueOf(2));
113     private static final String NODE_1_ISIS_ID = "bgpls://IsisLevel2:1/type=node&as=1&router=0000.0102.0304";
114     private static final String NODE_2_ISIS_ID = "bgpls://IsisLevel2:1/type=node&as=2";
115     private static final String NODE_1_OSPF_ID = "bgpls://Ospf:1/type=node&as=1&router=0000.0102.0304";
116     private static final String NODE_2_OSPF_ID = "bgpls://Ospf:1/type=node&as=2";
117     private static final Identifier IDENTIFIER = new Identifier(Uint64.ONE);
118     private static final long LISTENER_RESTART_TIME = 20000;
119     private static final int LISTENER_ENFORCE_COUNTER = 2;
120
121     private LinkstateTopologyBuilder linkstateTopoBuilder;
122     private InstanceIdentifier<LinkstateRoute> linkstateRouteIID;
123
124     @Before
125     @Override
126     public void setUp() {
127         super.setUp();
128         this.linkstateTopoBuilder = new LinkstateTopologyBuilder(getDataBroker(), LOC_RIB_REF, TEST_TOPOLOGY_ID,
129             LISTENER_RESTART_TIME, LISTENER_ENFORCE_COUNTER);
130         this.linkstateTopoBuilder.start();
131         final InstanceIdentifier<Tables> path = LOC_RIB_REF.getInstanceIdentifier().builder().child(LocRib.class)
132             .child(Tables.class, new TablesKey(LinkstateAddressFamily.class, LinkstateSubsequentAddressFamily.class))
133             .build();
134         this.linkstateRouteIID = path.builder().child(LinkstateRoutesCase.class, LinkstateRoutes.class)
135             .child(LinkstateRoute.class, new LinkstateRouteKey(new PathId(Uint32.ZERO), LINKSTATE_ROUTE_KEY))
136                 .build();
137
138     }
139
140     @After
141     public void tearDown() throws Exception {
142         this.linkstateTopoBuilder.close();
143         checkNotPresentOperational(getDataBroker(), this.linkstateTopoBuilder.getInstanceIdentifier());
144     }
145
146     @Test
147     public void testLinkstateTopologyBuilderTopologyTypes() throws InterruptedException, ExecutionException {
148         readDataOperational(getDataBroker(), this.linkstateTopoBuilder.getInstanceIdentifier(), topology -> {
149             assertNotNull(topology.getTopologyTypes().augmentation(org.opendaylight.yang.gen.v1.urn.opendaylight
150                     .params.xml.ns.yang.odl.bgp.topology.types.rev160524.TopologyTypes1.class));
151             assertNotNull(topology.getTopologyTypes().augmentation(org.opendaylight.yang.gen.v1.urn.opendaylight
152                     .params.xml.ns.yang.odl.bgp.topology.types.rev160524.TopologyTypes1.class)
153                     .getBgpLinkstateTopology());
154             return topology;
155         });
156     }
157
158     @Test
159     public void testIsisLinkstateTopologyBuilder() throws InterruptedException, ExecutionException {
160         // create node
161         updateLinkstateRoute(createLinkstateNodeRoute(ProtocolId.IsisLevel2, "node1", NODE_1_AS, ROUTER_1_ID));
162         readDataOperational(getDataBroker(), this.linkstateTopoBuilder.getInstanceIdentifier(), topology -> {
163             assertEquals(1, topology.getNode().size());
164             final Node node1 = topology.getNode().get(0);
165             assertEquals(NODE_1_ISIS_ID, node1.getNodeId().getValue());
166             final IgpNodeAttributes igpNode1 = node1.augmentation(Node1.class).getIgpNodeAttributes();
167             assertEquals(ROUTER_1_ID, igpNode1.getRouterId().get(0).getIpv4Address().getValue());
168             assertEquals("node1", igpNode1.getName().getValue());
169             final IgpNodeAttributes1 igpNodeAttributes1 = igpNode1.augmentation(IgpNodeAttributes1.class);
170             assertEquals("0000.0102.0304", igpNodeAttributes1.getIsisNodeAttributes().getIso().getIsoSystemId()
171                     .getValue());
172             assertEquals(ROUTER_1_ID, igpNodeAttributes1.getIsisNodeAttributes().getTed().getTeRouterIdIpv4()
173                     .getValue());
174             assertEquals("47.0000.0000.0000.0000.0102.0304", igpNodeAttributes1.getIsisNodeAttributes()
175                     .getNet().get(0).getValue());
176             assertNull(igpNode1.augmentation(org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.ospf
177                     .topology.rev131021.IgpNodeAttributes1.class));
178             return topology;
179         });
180
181
182         // create link
183         updateLinkstateRoute(createLinkstateLinkRoute(ProtocolId.IsisLevel2, NODE_1_AS, NODE_2_AS, "link1"));
184         readDataOperational(getDataBroker(), this.linkstateTopoBuilder.getInstanceIdentifier(), topology -> {
185             assertEquals(1, topology.getLink().size());
186             final Link link1 = topology.getLink().get(0);
187             assertEquals(2, topology.getNode().size());
188             assertEquals(1, topology.getNode().get(0).getTerminationPoint().size());
189             assertEquals(1, topology.getNode().get(1).getTerminationPoint().size());
190             assertEquals("bgpls://IsisLevel2:1/type=link&local-as=1&local-router=0000.0102.0304&remote-as"
191                     + "=2&mt=1", link1.getLinkId().getValue());
192             assertEquals(NODE_1_ISIS_ID, link1.getSource().getSourceNode().getValue());
193             assertEquals(NODE_2_ISIS_ID, link1.getDestination().getDestNode().getValue());
194             final IgpLinkAttributes igpLink1 = link1.augmentation(Link1.class).getIgpLinkAttributes();
195             assertEquals("link1", igpLink1.getName());
196             assertEquals((short) 1, igpLink1.augmentation(IgpLinkAttributes1.class).getIsisLinkAttributes()
197                     .getMultiTopologyId().shortValue());
198             assertNull(igpLink1.augmentation(org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.ospf
199                     .topology.rev131021.IgpLinkAttributes1.class));
200             return topology;
201         });
202
203
204         // update node
205         updateLinkstateRoute(createLinkstateNodeRoute(ProtocolId.IsisLevel2, "updated-node",
206                 NODE_1_AS, ROUTER_2_ID));
207         readDataOperational(getDataBroker(), this.linkstateTopoBuilder.getInstanceIdentifier(), topology -> {
208             assertEquals(1, topology.getNode().size());
209             final IgpNodeAttributes igpNode2 = topology.getNode().get(0).augmentation(Node1.class)
210                     .getIgpNodeAttributes();
211             assertEquals(ROUTER_2_ID, igpNode2.getRouterId().get(0).getIpv4Address().getValue());
212             assertEquals("updated-node", igpNode2.getName().getValue());
213             return topology;
214         });
215
216         // remove
217         final WriteTransaction wTx = getDataBroker().newWriteOnlyTransaction();
218         wTx.delete(LogicalDatastoreType.OPERATIONAL, this.linkstateRouteIID);
219         wTx.commit();
220         readDataOperational(getDataBroker(), this.linkstateTopoBuilder.getInstanceIdentifier(), topology -> {
221             assertNull(topology.getNode());
222             assertNull(topology.getLink());
223             return topology;
224         });
225     }
226
227     @Test
228     public void testOspfLinkstateTopologyBuilder() throws InterruptedException, ExecutionException {
229         // create node
230         updateLinkstateRoute(createLinkstateNodeRoute(ProtocolId.Ospf, "node1", NODE_1_AS, ROUTER_1_ID));
231         readDataOperational(getDataBroker(), this.linkstateTopoBuilder.getInstanceIdentifier(), topology -> {
232             assertEquals(1, topology.getNode().size());
233             final Node node1 = topology.getNode().get(0);
234             assertEquals(NODE_1_OSPF_ID, node1.getNodeId().getValue());
235             final IgpNodeAttributes igpNode1 = node1.augmentation(Node1.class).getIgpNodeAttributes();
236             assertEquals(ROUTER_1_ID, igpNode1.getRouterId().get(0).getIpv4Address().getValue());
237             assertEquals("node1", igpNode1.getName().getValue());
238             assertNull(igpNode1.augmentation(IgpNodeAttributes1.class));
239             assertEquals(ROUTER_1_ID, igpNode1.augmentation(org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns
240                     .yang.ospf.topology.rev131021.IgpNodeAttributes1.class).getOspfNodeAttributes().getTed()
241                     .getTeRouterIdIpv4().getValue());
242             return topology;
243         });
244
245         // update node with prefix
246         updateLinkstateRoute(createLinkstatePrefixRoute(ProtocolId.Ospf, NODE_1_AS, NODE_1_PREFIX,
247                 500L, ROUTER_1_ID));
248         readDataOperational(getDataBroker(), this.linkstateTopoBuilder.getInstanceIdentifier(), topology -> {
249             final IgpNodeAttributes igpNode2 = topology.getNode().get(0).augmentation(Node1.class)
250                     .getIgpNodeAttributes();
251             assertEquals(1, igpNode2.getPrefix().size());
252             final Prefix prefix = igpNode2.getPrefix().get(0);
253             assertEquals(NODE_1_PREFIX, prefix.getPrefix().getIpv4Prefix().getValue());
254             assertEquals(500L, prefix.getMetric().longValue());
255             return topology;
256         });
257
258
259         // create link
260         updateLinkstateRoute(createLinkstateLinkRoute(ProtocolId.Ospf, NODE_1_AS, NODE_2_AS, "link1"));
261         readDataOperational(getDataBroker(), this.linkstateTopoBuilder.getInstanceIdentifier(), topology -> {
262             assertEquals(1, topology.getLink().size());
263             final Link link1 = topology.getLink().get(0);
264             assertEquals(2, topology.getNode().size());
265             assertEquals(1, topology.getNode().get(0).getTerminationPoint().size());
266             assertEquals(1, topology.getNode().get(1).getTerminationPoint().size());
267             assertEquals("bgpls://Ospf:1/type=link&local-as=1&local-router=0000.0102.0304&remote-as=2&mt=1",
268                     link1.getLinkId().getValue());
269             assertEquals(NODE_1_OSPF_ID, link1.getSource().getSourceNode().getValue());
270             assertEquals(NODE_2_OSPF_ID, link1.getDestination().getDestNode().getValue());
271             final IgpLinkAttributes igpLink1 = link1.augmentation(Link1.class).getIgpLinkAttributes();
272             assertEquals("link1", igpLink1.getName());
273             assertNull(igpLink1.augmentation(IgpLinkAttributes1.class));
274             assertEquals((short) 1, igpLink1.augmentation(org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang
275                     .ospf.topology.rev131021.IgpLinkAttributes1.class).getOspfLinkAttributes().getMultiTopologyId()
276                     .shortValue());
277             assertEquals(2, igpLink1.augmentation(org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns
278                     .yang.ospf.topology.rev131021.IgpLinkAttributes1.class).getOspfLinkAttributes().getTed().getSrlg()
279                     .getSrlgValues().size());
280             return topology;
281         });
282
283
284     }
285
286     /**
287      * This test is to verify if the AbstractTopologyBuilder/LinkstateTopologyBuilder is handling exception correctly.
288      */
289     @Test
290     @SuppressWarnings("checkstyle:IllegalCatch")
291     public void testRouteChangedError() throws Exception {
292         final LinkstateTopologyBuilder spiedLinkstateTopologyBuilder = spy(this.linkstateTopoBuilder);
293         doThrow(RuntimeException.class).when(spiedLinkstateTopologyBuilder).routeChanged(any(), any());
294         try {
295             spiedLinkstateTopologyBuilder.routeChanged(null, null);
296             fail("Mockito failed to spy routeChanged() method");
297         } catch (final Exception e) {
298             assertTrue(e instanceof RuntimeException);
299         }
300         assertEquals(0L, spiedLinkstateTopologyBuilder.listenerScheduledRestartTime);
301         assertEquals(0L, spiedLinkstateTopologyBuilder.listenerScheduledRestartEnforceCounter);
302         // first we examine if the chain is being reset when no exception is thrown
303         spiedLinkstateTopologyBuilder.onDataTreeChanged(new ArrayList<>());
304         verify(spiedLinkstateTopologyBuilder, times(1)).restartTransactionChainOnDemand();
305         verify(spiedLinkstateTopologyBuilder, never()).scheduleListenerRestart();
306         verify(spiedLinkstateTopologyBuilder, never()).resetTransactionChain();
307         assertEquals(0L, spiedLinkstateTopologyBuilder.listenerScheduledRestartTime);
308         assertEquals(0L, spiedLinkstateTopologyBuilder.listenerScheduledRestartEnforceCounter);
309         // now pass some invalid data to cause onDataTreeChanged fail
310         final DataTreeModification<LinkstateRoute> modification = mock(DataTreeModification.class, RETURNS_SMART_NULLS);
311         final List<DataTreeModification<LinkstateRoute>> changes = new ArrayList<>();
312         changes.add(modification);
313         spiedLinkstateTopologyBuilder.onDataTreeChanged(changes);
314         // one restart transaction chain check in onDataTreeChanged()
315         // we are introducing some timeout here as transaction may be executed in a delay manner
316         verify(spiedLinkstateTopologyBuilder, timeout(5000).times(1)).scheduleListenerRestart();
317         verify(spiedLinkstateTopologyBuilder, times(2)).restartTransactionChainOnDemand();
318         assertNotEquals(0L, spiedLinkstateTopologyBuilder.listenerScheduledRestartTime);
319         assertEquals(0, spiedLinkstateTopologyBuilder.listenerScheduledRestartEnforceCounter);
320         final long listenerScheduledRestartTime = spiedLinkstateTopologyBuilder.listenerScheduledRestartTime;
321         // call again with empty change to invoke restartTransactionChainOnDemand()
322         spiedLinkstateTopologyBuilder.onDataTreeChanged(new ArrayList<>());
323         verify(spiedLinkstateTopologyBuilder, times(3)).restartTransactionChainOnDemand();
324         // transaction chain should be reset while listener should not
325         verify(spiedLinkstateTopologyBuilder, times(1)).resetTransactionChain();
326         verify(spiedLinkstateTopologyBuilder, never()).resetListener();
327         // now apply a change with bad modification again
328         spiedLinkstateTopologyBuilder.onDataTreeChanged(changes);
329         verify(spiedLinkstateTopologyBuilder, times(4)).restartTransactionChainOnDemand();
330         // listener scheduled again
331         verify(spiedLinkstateTopologyBuilder, timeout(5000).times(2)).scheduleListenerRestart();
332         // listener timer shouldn't have changed
333         assertEquals(listenerScheduledRestartTime, spiedLinkstateTopologyBuilder.listenerScheduledRestartTime);
334         assertEquals(0, spiedLinkstateTopologyBuilder.listenerScheduledRestartEnforceCounter);
335         verify(spiedLinkstateTopologyBuilder, times(2)).resetTransactionChain();
336         verify(spiedLinkstateTopologyBuilder, never()).resetListener();
337         Thread.sleep(LISTENER_RESTART_TIME);
338         // manually invoke onTransactionChainFailed() to have the listener restart scheduled again
339         spiedLinkstateTopologyBuilder.onTransactionChainFailed(null, null, null);
340         assertEquals(spiedLinkstateTopologyBuilder.listenerScheduledRestartTime, listenerScheduledRestartTime
341                 + LISTENER_RESTART_TIME);
342         verify(spiedLinkstateTopologyBuilder, times(5)).restartTransactionChainOnDemand();
343         verify(spiedLinkstateTopologyBuilder, times(3)).scheduleListenerRestart();
344         // enforce counter get increased
345         assertEquals(1, spiedLinkstateTopologyBuilder.listenerScheduledRestartEnforceCounter);
346         verify(spiedLinkstateTopologyBuilder, times(3)).resetTransactionChain();
347         verify(spiedLinkstateTopologyBuilder, never()).resetListener();
348         // sleep to let the listener restart timer times out
349         Thread.sleep(LISTENER_RESTART_TIME);
350         // apply a good modification (empty change)
351         spiedLinkstateTopologyBuilder.onDataTreeChanged(new ArrayList<>());
352         assertEquals(0, spiedLinkstateTopologyBuilder.listenerScheduledRestartTime);
353         assertEquals(0, spiedLinkstateTopologyBuilder.listenerScheduledRestartEnforceCounter);
354         verify(spiedLinkstateTopologyBuilder, times(6)).restartTransactionChainOnDemand();
355         // listener restarted didn't get rescheduled again
356         verify(spiedLinkstateTopologyBuilder, times(3)).scheduleListenerRestart();
357         verify(spiedLinkstateTopologyBuilder, times(4)).resetTransactionChain();
358         verify(spiedLinkstateTopologyBuilder, times(1)).resetListener();
359     }
360
361     private void updateLinkstateRoute(final LinkstateRoute data) {
362         final WriteTransaction wTx = getDataBroker().newWriteOnlyTransaction();
363         wTx.mergeParentStructurePut(LogicalDatastoreType.OPERATIONAL, this.linkstateRouteIID, data);
364         wTx.commit();
365     }
366
367     private static LinkstateRoute createLinkstateNodeRoute(final ProtocolId protocolId, final String nodeName,
368             final AsNumber asNumber, final String ipv4RouterId) {
369         return createBaseBuilder(protocolId)
370                 .setObjectType(new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate
371                         .rev180329.linkstate.object.type.NodeCaseBuilder()
372                         .setNodeDescriptors(new NodeDescriptorsBuilder()
373                                 .setCRouterIdentifier(new IsisNodeCaseBuilder().setIsisNode(new IsisNodeBuilder()
374                                         .setIsoSystemId(new IsoSystemIdentifier(new byte[]{0, 0, 1, 2, 3, 4})).build())
375                                         .build())
376                                 .setAsNumber(asNumber).build()).build())
377                 .setAttributes(new AttributesBuilder()
378                         .setOrigin(new OriginBuilder().setValue(BgpOrigin.Igp).build())
379                         .addAugmentation(Attributes1.class, new Attributes1Builder()
380                                 .setLinkStateAttribute(new NodeAttributesCaseBuilder()
381                                         .setNodeAttributes(new NodeAttributesBuilder()
382                                                 .setDynamicHostname(nodeName)
383                                                 .setIpv4RouterId(new Ipv4RouterIdentifier(ipv4RouterId))
384                                                 .setIsisAreaId(Collections.singletonList(
385                                                         new IsisAreaIdentifier(new byte[]{0x47})))
386                                                 .build()).build()).build()).build()).build();
387     }
388
389     private static LinkstateRoute createLinkstatePrefixRoute(final ProtocolId protocolId, final AsNumber asNumber,
390             final String ipv4Prefix, final long igpMetric, final String ospfFwdAddress) {
391         return createBaseBuilder(protocolId)
392             .setObjectType(new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev180329
393                     .linkstate.object.type.PrefixCaseBuilder()
394                 .setAdvertisingNodeDescriptors(new AdvertisingNodeDescriptorsBuilder().setAsNumber(asNumber).build())
395                 .setPrefixDescriptors(new PrefixDescriptorsBuilder()
396                         .setIpReachabilityInformation(new IpPrefix(new Ipv4Prefix(ipv4Prefix))).build()).build())
397             .setAttributes(new AttributesBuilder()
398                 .setOrigin(new OriginBuilder().setValue(BgpOrigin.Igp).build())
399                 .addAugmentation(Attributes1.class, new Attributes1Builder()
400                         .setLinkStateAttribute(new PrefixAttributesCaseBuilder()
401                             .setPrefixAttributes(new PrefixAttributesBuilder()
402                                 .setOspfForwardingAddress(new IpAddress(new Ipv4Address(ospfFwdAddress)))
403                                 .setPrefixMetric(new IgpMetric(Uint32.valueOf(igpMetric)))
404                                 .build())
405                             .build())
406                         .build())
407                 .build())
408             .build();
409     }
410
411     private static LinkstateRoute createLinkstateLinkRoute(final ProtocolId protocolId, final AsNumber localAs,
412             final AsNumber remoteAs, final String linkName) {
413         return createBaseBuilder(protocolId)
414                 .setObjectType(new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate
415                         .rev180329.linkstate.object.type.LinkCaseBuilder()
416                         .setLocalNodeDescriptors(new LocalNodeDescriptorsBuilder().setAsNumber(localAs)
417                                 .setCRouterIdentifier(new IsisNodeCaseBuilder().setIsisNode(new IsisNodeBuilder()
418                                         .setIsoSystemId(new IsoSystemIdentifier(new byte[]{0, 0, 1, 2, 3, 4}))
419                                         .build()).build()).build())
420                         .setRemoteNodeDescriptors(new RemoteNodeDescriptorsBuilder().setAsNumber(remoteAs).build())
421                         .setLinkDescriptors(new LinkDescriptorsBuilder()
422                                 .setMultiTopologyId(new TopologyIdentifier(Uint16.ONE)).build()).build())
423                 .setAttributes(new AttributesBuilder()
424                         .setOrigin(new OriginBuilder().setValue(BgpOrigin.Igp).build())
425                         .addAugmentation(Attributes1.class, new Attributes1Builder()
426                                 .setLinkStateAttribute(new LinkAttributesCaseBuilder()
427                                     .setLinkAttributes(new LinkAttributesBuilder()
428                                         .setSharedRiskLinkGroups(Lists.newArrayList(
429                                             new SrlgId(Uint32.valueOf(5)), new SrlgId(Uint32.valueOf(15))))
430                                         .setAdminGroup(new AdministrativeGroup(Uint32.ZERO))
431                                         .setMaxLinkBandwidth(
432                                                 new Bandwidth(new byte[]{0x00, 0x00, (byte) 0xff, (byte) 0xff}))
433                                         .setMaxReservableBandwidth(
434                                                 new Bandwidth(new byte[]{0x00, 0x00, (byte) 0xff, (byte) 0x1f}))
435                                         .setUnreservedBandwidth(Lists.newArrayList(new UnreservedBandwidthBuilder()
436                                                 .withKey(new UnreservedBandwidthKey(Uint8.ONE))
437                                                 .setBandwidth(new Bandwidth(new byte[]{0x00, 0x00, 0x00, (byte) 0xff}))
438                                                 .build()))
439                                         .setTeMetric(new TeMetric(Uint32.valueOf(100)))
440                                         .setLinkName(linkName)
441                                         .build())
442                                     .build())
443                                 .build())
444                         .build())
445                 .build();
446     }
447
448     private static LinkstateRouteBuilder createBaseBuilder(final ProtocolId protocolId) {
449         return new LinkstateRouteBuilder()
450             .setIdentifier(IDENTIFIER)
451             .withKey(new LinkstateRouteKey(new PathId(Uint32.ZERO), LINKSTATE_ROUTE_KEY))
452             .setRouteKey(LINKSTATE_ROUTE_KEY)
453             .setProtocolId(protocolId);
454     }
455 }