+ updateLinkstateRoute(linkstateLinkRouteIID,
+ createLinkstateLinkRoute(ProtocolId.Ospf, NODE_1_AS, NODE_2_AS, "link1"));
+ readDataOperational(getDataBroker(), linkstateTopoBuilder.getInstanceIdentifier(), topology -> {
+ assertEquals(1, topology.nonnullLink().size());
+ final Link link1 = topology.nonnullLink().values().iterator().next();
+ assertEquals(2, topology.getNode().size());
+ assertEquals(1, Iterables.get(topology.getNode().values(), 0).getTerminationPoint().size());
+ assertEquals(1, Iterables.get(topology.getNode().values(), 1).getTerminationPoint().size());
+ assertEquals("bgpls://Ospf:1/type=link&local-as=1&local-router=0000.0102.0304&remote-as=2&mt=1",
+ link1.getLinkId().getValue());
+ assertEquals(NODE_1_OSPF_ID, link1.getSource().getSourceNode().getValue());
+ assertEquals(NODE_2_OSPF_ID, link1.getDestination().getDestNode().getValue());
+ final IgpLinkAttributes igpLink1 = link1.augmentation(Link1.class).getIgpLinkAttributes();
+ assertEquals("link1", igpLink1.getName());
+ assertNull(igpLink1.augmentation(IgpLinkAttributes1.class));
+ assertEquals((short) 1, igpLink1.augmentation(org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang
+ .ospf.topology.rev131021.IgpLinkAttributes1.class).getOspfLinkAttributes().getMultiTopologyId()
+ .shortValue());
+ assertEquals(2, igpLink1.augmentation(org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns
+ .yang.ospf.topology.rev131021.IgpLinkAttributes1.class).getOspfLinkAttributes().getTed().getSrlg()
+ .getSrlgValues().size());
+ assertEquals(LinkstateTopologyBuilder.SR_AWARE_LINKSTATE_TOPOLOGY_TYPE, topology.getTopologyTypes());
+ assertEquals(2, topology.getNode().size());
+ final Node srcNode;
+ if (topology.getNode().values().iterator().next().getNodeId().getValue().contains("0000.0102.0304")) {
+ srcNode = topology.getNode().values().iterator().next();
+ } else {
+ srcNode = Iterables.get(topology.getNode().values(), 1);
+ }
+ assertEquals(2, srcNode.augmentation(
+ org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819.Node1.class)
+ .getSegments().size());
+ assertEquals(ADJ_SID, link1.augmentation(
+ org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819.Link1.class)
+ .getSegment().getValue().intValue());
+ return topology;
+ });
+ }
+
+ /**
+ * This test is to verify if the AbstractTopologyBuilder/LinkstateTopologyBuilder is handling exception correctly.
+ */
+ @Test
+ @SuppressWarnings("checkstyle:IllegalCatch")
+ public void testRouteChangedError() throws Exception {
+ final LinkstateTopologyBuilder spiedLinkstateTopologyBuilder = spy(linkstateTopoBuilder);
+ doThrow(RuntimeException.class).when(spiedLinkstateTopologyBuilder).routeChanged(any(), any());
+ try {
+ spiedLinkstateTopologyBuilder.routeChanged(null, null);
+ fail("Mockito failed to spy routeChanged() method");
+ } catch (final Exception e) {
+ assertTrue(e instanceof RuntimeException);
+ }
+ assertEquals(0L, spiedLinkstateTopologyBuilder.listenerScheduledRestartTime);
+ assertEquals(0L, spiedLinkstateTopologyBuilder.listenerScheduledRestartEnforceCounter);
+ // first we examine if the chain is being reset when no exception is thrown
+ spiedLinkstateTopologyBuilder.onDataTreeChanged(new ArrayList<>());
+ verify(spiedLinkstateTopologyBuilder, times(1)).restartTransactionChainOnDemand();
+ verify(spiedLinkstateTopologyBuilder, never()).scheduleListenerRestart();
+ verify(spiedLinkstateTopologyBuilder, never()).resetTransactionChain();
+ assertEquals(0L, spiedLinkstateTopologyBuilder.listenerScheduledRestartTime);
+ assertEquals(0L, spiedLinkstateTopologyBuilder.listenerScheduledRestartEnforceCounter);
+ // now pass some invalid data to cause onDataTreeChanged fail
+ final DataTreeModification<LinkstateRoute> modification = mock(DataTreeModification.class, RETURNS_SMART_NULLS);
+ final List<DataTreeModification<LinkstateRoute>> changes = new ArrayList<>();
+ changes.add(modification);
+ spiedLinkstateTopologyBuilder.onDataTreeChanged(changes);
+ // one restart transaction chain check in onDataTreeChanged()
+ // we are introducing some timeout here as transaction may be executed in a delay manner
+ verify(spiedLinkstateTopologyBuilder, timeout(5000).times(1)).scheduleListenerRestart();
+ verify(spiedLinkstateTopologyBuilder, times(2)).restartTransactionChainOnDemand();
+ assertNotEquals(0L, spiedLinkstateTopologyBuilder.listenerScheduledRestartTime);
+ assertEquals(0, spiedLinkstateTopologyBuilder.listenerScheduledRestartEnforceCounter);
+ final long listenerScheduledRestartTime = spiedLinkstateTopologyBuilder.listenerScheduledRestartTime;
+ // call again with empty change to invoke restartTransactionChainOnDemand()
+ spiedLinkstateTopologyBuilder.onDataTreeChanged(new ArrayList<>());
+ verify(spiedLinkstateTopologyBuilder, times(3)).restartTransactionChainOnDemand();
+ // transaction chain should be reset while listener should not
+ verify(spiedLinkstateTopologyBuilder, times(1)).resetTransactionChain();
+ verify(spiedLinkstateTopologyBuilder, never()).resetListener();
+ // now apply a change with bad modification again
+ spiedLinkstateTopologyBuilder.onDataTreeChanged(changes);
+ verify(spiedLinkstateTopologyBuilder, times(4)).restartTransactionChainOnDemand();
+ // listener scheduled again
+ verify(spiedLinkstateTopologyBuilder, timeout(5000).times(2)).scheduleListenerRestart();
+ // listener timer shouldn't have changed
+ assertEquals(listenerScheduledRestartTime, spiedLinkstateTopologyBuilder.listenerScheduledRestartTime);
+ assertEquals(0, spiedLinkstateTopologyBuilder.listenerScheduledRestartEnforceCounter);
+ verify(spiedLinkstateTopologyBuilder, times(2)).resetTransactionChain();
+ verify(spiedLinkstateTopologyBuilder, never()).resetListener();
+ Thread.sleep(LISTENER_RESTART_TIME);
+ // manually invoke onTransactionChainFailed() to have the listener restart scheduled again
+ spiedLinkstateTopologyBuilder.onTransactionChainFailed(null, null, null);
+ assertEquals(spiedLinkstateTopologyBuilder.listenerScheduledRestartTime, listenerScheduledRestartTime
+ + LISTENER_RESTART_TIME);
+ verify(spiedLinkstateTopologyBuilder, times(5)).restartTransactionChainOnDemand();
+ verify(spiedLinkstateTopologyBuilder, times(3)).scheduleListenerRestart();
+ // enforce counter get increased
+ assertEquals(1, spiedLinkstateTopologyBuilder.listenerScheduledRestartEnforceCounter);
+ verify(spiedLinkstateTopologyBuilder, times(3)).resetTransactionChain();
+ verify(spiedLinkstateTopologyBuilder, never()).resetListener();
+ // sleep to let the listener restart timer times out
+ Thread.sleep(LISTENER_RESTART_TIME);
+ // apply a good modification (empty change)
+ spiedLinkstateTopologyBuilder.onDataTreeChanged(new ArrayList<>());
+ assertEquals(0, spiedLinkstateTopologyBuilder.listenerScheduledRestartTime);
+ assertEquals(0, spiedLinkstateTopologyBuilder.listenerScheduledRestartEnforceCounter);
+ verify(spiedLinkstateTopologyBuilder, times(6)).restartTransactionChainOnDemand();
+ // listener restarted didn't get rescheduled again
+ verify(spiedLinkstateTopologyBuilder, times(3)).scheduleListenerRestart();
+ verify(spiedLinkstateTopologyBuilder, times(4)).resetTransactionChain();
+ verify(spiedLinkstateTopologyBuilder, times(1)).resetListener();
+ }