Fix BGP operational state
[bgpcep.git] / bgp / openconfig-state / src / test / java / org / opendaylight / protocol / bgp / state / StateProviderImplTest.java
1 /*
2  * Copyright (c) 2016 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.protocol.bgp.state;
9
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertNotNull;
12 import static org.junit.Assert.assertNull;
13 import static org.junit.Assert.assertTrue;
14 import static org.mockito.ArgumentMatchers.any;
15 import static org.mockito.ArgumentMatchers.anyBoolean;
16 import static org.mockito.ArgumentMatchers.anyLong;
17 import static org.mockito.ArgumentMatchers.eq;
18 import static org.mockito.Mockito.doAnswer;
19 import static org.mockito.Mockito.doNothing;
20 import static org.mockito.Mockito.doReturn;
21 import static org.mockito.Mockito.mock;
22 import static org.mockito.Mockito.spy;
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.util.concurrent.Futures;
29 import com.google.common.util.concurrent.ListeningExecutorService;
30 import com.google.common.util.concurrent.MoreExecutors;
31 import com.google.common.util.concurrent.Uninterruptibles;
32 import java.math.BigDecimal;
33 import java.util.ArrayList;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.Set;
37 import java.util.concurrent.Executors;
38 import java.util.concurrent.ScheduledExecutorService;
39 import java.util.concurrent.ScheduledFuture;
40 import java.util.concurrent.TimeUnit;
41 import java.util.concurrent.atomic.LongAdder;
42 import org.junit.Before;
43 import org.junit.Test;
44 import org.junit.runner.RunWith;
45 import org.mockito.ArgumentCaptor;
46 import org.mockito.Mock;
47 import org.mockito.junit.MockitoJUnitRunner;
48 import org.opendaylight.infrautils.testutils.LogCapture;
49 import org.opendaylight.infrautils.testutils.internal.RememberingLogger;
50 import org.opendaylight.mdsal.binding.dom.adapter.test.AbstractDataBrokerTest;
51 import org.opendaylight.mdsal.binding.dom.adapter.test.AbstractDataBrokerTestCustomizer;
52 import org.opendaylight.mdsal.binding.dom.adapter.test.ConcurrentDataBrokerTestCustomizer;
53 import org.opendaylight.mdsal.dom.spi.store.DOMStore;
54 import org.opendaylight.mdsal.dom.spi.store.DOMStoreReadWriteTransaction;
55 import org.opendaylight.mdsal.dom.spi.store.DOMStoreThreePhaseCommitCohort;
56 import org.opendaylight.mdsal.dom.spi.store.DOMStoreTransactionChain;
57 import org.opendaylight.mdsal.dom.spi.store.DOMStoreWriteTransaction;
58 import org.opendaylight.mdsal.dom.store.inmemory.InMemoryDOMDataStore;
59 import org.opendaylight.protocol.bgp.openconfig.spi.BGPTableTypeRegistryConsumer;
60 import org.opendaylight.protocol.bgp.rib.spi.State;
61 import org.opendaylight.protocol.bgp.rib.spi.state.BGPAfiSafiState;
62 import org.opendaylight.protocol.bgp.rib.spi.state.BGPErrorHandlingState;
63 import org.opendaylight.protocol.bgp.rib.spi.state.BGPGracelfulRestartState;
64 import org.opendaylight.protocol.bgp.rib.spi.state.BGPPeerMessagesState;
65 import org.opendaylight.protocol.bgp.rib.spi.state.BGPPeerState;
66 import org.opendaylight.protocol.bgp.rib.spi.state.BGPRibState;
67 import org.opendaylight.protocol.bgp.rib.spi.state.BGPSessionState;
68 import org.opendaylight.protocol.bgp.rib.spi.state.BGPStateProvider;
69 import org.opendaylight.protocol.bgp.rib.spi.state.BGPTimersState;
70 import org.opendaylight.protocol.bgp.rib.spi.state.BGPTransportState;
71 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.multiprotocol.rev151009.bgp.common.afi.safi.list.AfiSafi;
72 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.multiprotocol.rev151009.bgp.common.afi.safi.list.AfiSafiBuilder;
73 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.multiprotocol.rev151009.bgp.common.afi.safi.list.afi.safi.GracefulRestartBuilder;
74 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.multiprotocol.rev151009.bgp.common.afi.safi.list.afi.safi.graceful.restart.StateBuilder;
75 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.operational.rev151009.BgpAfiSafiGracefulRestartState;
76 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.operational.rev151009.BgpNeighborState;
77 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.operational.rev151009.bgp.neighbor.prefix.counters_state.PrefixesBuilder;
78 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.graceful.restart.GracefulRestart;
79 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.AfiSafis;
80 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.AfiSafisBuilder;
81 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.ErrorHandling;
82 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.ErrorHandlingBuilder;
83 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.Timers;
84 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.TimersBuilder;
85 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.Transport;
86 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.TransportBuilder;
87 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbors.Neighbor;
88 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.peer.group.PeerGroup;
89 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.peer.group.PeerGroupBuilder;
90 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.Bgp;
91 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.bgp.Global;
92 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.bgp.GlobalBuilder;
93 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.bgp.Neighbors;
94 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.types.rev151009.ADDPATHS;
95 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.types.rev151009.ASN32;
96 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.types.rev151009.BgpCapability;
97 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.types.rev151009.CommunityType;
98 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.types.rev151009.GRACEFULRESTART;
99 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.types.rev151009.IPV4UNICAST;
100 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.types.rev151009.MPBGP;
101 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.types.rev151009.ROUTEREFRESH;
102 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.NetworkInstances;
103 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.NetworkInstance;
104 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.NetworkInstanceKey;
105 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.network.instance.Protocols;
106 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.network.instance.protocols.Protocol;
107 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.network.instance.protocols.ProtocolKey;
108 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.policy.types.rev151009.BGP;
109 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber;
110 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
111 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressNoZone;
112 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
113 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone;
114 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
115 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Timeticks;
116 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.NetworkInstanceProtocol;
117 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.network.instance.protocol.BgpNeighborStateAugmentation;
118 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.network.instance.protocol.BgpNeighborStateAugmentationBuilder;
119 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.network.instance.protocol.GlobalAfiSafiStateAugmentationBuilder;
120 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.network.instance.protocol.NeighborAfiSafiGracefulRestartStateAugmentationBuilder;
121 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.network.instance.protocol.NeighborAfiSafiStateAugmentationBuilder;
122 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.network.instance.protocol.NeighborErrorHandlingStateAugmentationBuilder;
123 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.network.instance.protocol.NeighborGracefulRestartStateAugmentationBuilder;
124 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.network.instance.protocol.NeighborStateAugmentation;
125 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.network.instance.protocol.NeighborTimersStateAugmentationBuilder;
126 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.network.instance.protocol.NeighborTransportStateAugmentationBuilder;
127 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.network.instance.protocol.PeerGroupStateAugmentationBuilder;
128 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.network.instance.protocol.bgp.neighbor_state.augmentation.MessagesBuilder;
129 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.network.instance.protocol.bgp.neighbor_state.augmentation.messages.ReceivedBuilder;
130 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.network.instance.protocol.bgp.neighbor_state.augmentation.messages.SentBuilder;
131 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.BgpRib;
132 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.RibId;
133 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.Rib;
134 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.RibKey;
135 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.TablesKey;
136 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev200120.BgpId;
137 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev200120.Ipv4AddressFamily;
138 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev200120.UnicastSubsequentAddressFamily;
139 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
140 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
141 import org.opendaylight.yangtools.yang.binding.util.BindingMap;
142 import org.opendaylight.yangtools.yang.common.Uint16;
143 import org.opendaylight.yangtools.yang.common.Uint32;
144 import org.opendaylight.yangtools.yang.common.Uint64;
145 import org.slf4j.LoggerFactory;
146
147 @RunWith(MockitoJUnitRunner.StrictStubs.class)
148 public class StateProviderImplTest extends AbstractDataBrokerTest {
149     private final LongAdder totalPathsCounter = new LongAdder();
150     private final LongAdder totalPrefixesCounter = new LongAdder();
151     private final PortNumber localPort = new PortNumber(Uint16.valueOf(1790));
152     private final PortNumber remotePort = new PortNumber(Uint16.valueOf(179));
153     private final Uint16 restartTime = Uint16.valueOf(15);
154     private final String ribId = "identifier-test";
155     private final InstanceIdentifier<Bgp> bgpInstanceIdentifier = InstanceIdentifier.create(NetworkInstances.class)
156         .child(NetworkInstance.class, new NetworkInstanceKey("global-bgp")).child(Protocols.class)
157         .child(Protocol.class, new ProtocolKey(BGP.class, this.ribId)).augmentation(NetworkInstanceProtocol.class)
158             .child(Bgp.class);
159     static final TablesKey TABLES_KEY = new TablesKey(Ipv4AddressFamily.class, UnicastSubsequentAddressFamily.class);
160     private final AsNumber as = new AsNumber(Uint32.valueOf(72));
161     private final BgpId bgpId = new BgpId("127.0.0.1");
162     private final IpAddressNoZone neighborAddress = new IpAddressNoZone(new Ipv4AddressNoZone("127.0.0.2"));
163     private final List<Class<? extends BgpCapability>> supportedCap = List.of(ASN32.class, ROUTEREFRESH.class,
164             MPBGP.class, ADDPATHS.class, GRACEFULRESTART.class);
165     @Mock
166     private BGPStateProvider stateProvider;
167     @Mock
168     private BGPTableTypeRegistryConsumer tableTypeRegistry;
169     @Mock
170     private BGPRibState bgpRibState;
171     @Mock
172     private BGPPeerState bgpPeerState;
173     @Mock
174     private BGPSessionState bgpSessionState;
175     @Mock
176     private BGPPeerMessagesState bgpPeerMessagesState;
177     @Mock
178     private BGPTimersState timersState;
179     @Mock
180     private BGPTransportState bgpTransportState;
181     @Mock
182     private BGPErrorHandlingState bgpErrorHandlingState;
183     @Mock
184     private BGPGracelfulRestartState bgpGracelfulRestartState;
185     @Mock
186     private BGPAfiSafiState bgpAfiSafiState;
187
188     private final List<BGPPeerState> bgpPeerStates = new ArrayList<>();
189     private final List<BGPRibState> bgpRibStates = new ArrayList<>();
190
191     private InMemoryDOMDataStore realOperStore;
192     private InMemoryDOMDataStore spiedOperStore;
193
194     @Before
195     public void setUp() {
196         doReturn(IPV4UNICAST.class).when(this.tableTypeRegistry).getAfiSafiType(eq(TABLES_KEY));
197
198         doReturn(this.bgpRibStates).when(this.stateProvider).getRibStats();
199         doReturn(this.bgpPeerStates).when(this.stateProvider).getPeerStats();
200
201         final KeyedInstanceIdentifier<Rib, RibKey> iid = InstanceIdentifier.create(BgpRib.class)
202             .child(Rib.class, new RibKey(new RibId(this.ribId)));
203         doReturn(iid).when(this.bgpRibState).getInstanceIdentifier();
204         doReturn(this.as).when(this.bgpRibState).getAs();
205         doReturn(this.bgpId).when(this.bgpRibState).getRouteId();
206
207         doAnswer(invocation -> this.totalPathsCounter.longValue())
208                 .when(this.bgpRibState).getTotalPathsCount();
209         doAnswer(invocation -> this.totalPrefixesCounter.longValue())
210                 .when(this.bgpRibState).getTotalPrefixesCount();
211         doAnswer(invocation -> this.totalPathsCounter.longValue())
212                 .when(this.bgpRibState).getPathCount(eq(TABLES_KEY));
213         doAnswer(invocation -> this.totalPrefixesCounter.longValue())
214                 .when(this.bgpRibState).getPrefixesCount(eq(TABLES_KEY));
215         doAnswer(invocation -> Map.of(TABLES_KEY,
216             this.totalPathsCounter.longValue())).when(this.bgpRibState).getPathsCount();
217
218         // Mock Peer
219         doReturn("test-group").when(this.bgpPeerState).getGroupId();
220         doReturn(iid).when(this.bgpPeerState).getInstanceIdentifier();
221         doAnswer(invocation -> this.totalPrefixesCounter.longValue()).when(this.bgpPeerState).getTotalPrefixes();
222         doAnswer(invocation -> this.totalPathsCounter.longValue()).when(this.bgpPeerState).getTotalPathsCount();
223         doReturn(this.neighborAddress).when(this.bgpPeerState).getNeighborAddress();
224         doReturn(this.bgpSessionState).when(this.bgpPeerState).getBGPSessionState();
225         doReturn(this.bgpPeerMessagesState).when(this.bgpPeerState).getBGPPeerMessagesState();
226
227         doReturn(1L).when(this.bgpPeerMessagesState).getNotificationMessagesReceivedCount();
228         doReturn(1L).when(this.bgpPeerMessagesState).getNotificationMessagesSentCount();
229         doReturn(1L).when(this.bgpPeerMessagesState).getUpdateMessagesReceivedCount();
230         doReturn(1L).when(this.bgpPeerMessagesState).getUpdateMessagesSentCount();
231         doReturn(State.UP).when(this.bgpSessionState).getSessionState();
232         doReturn(true).when(this.bgpSessionState).isAddPathCapabilitySupported();
233         doReturn(true).when(this.bgpSessionState).isAsn32CapabilitySupported();
234         doReturn(true).when(this.bgpSessionState).isGracefulRestartCapabilitySupported();
235         doReturn(true).when(this.bgpSessionState).isMultiProtocolCapabilitySupported();
236         doReturn(true).when(this.bgpSessionState).isRouterRefreshCapabilitySupported();
237
238         doReturn(this.timersState).when(this.bgpPeerState).getBGPTimersState();
239         doReturn(10L).when(this.timersState).getNegotiatedHoldTime();
240         doReturn(10L).when(this.timersState).getUpTime();
241
242         doReturn(this.bgpTransportState).when(this.bgpPeerState).getBGPTransportState();
243         doReturn(this.localPort).when(this.bgpTransportState).getLocalPort();
244         doReturn(this.neighborAddress).when(this.bgpTransportState).getRemoteAddress();
245         doReturn(this.remotePort).when(this.bgpTransportState).getRemotePort();
246
247         doReturn(this.bgpErrorHandlingState).when(this.bgpPeerState).getBGPErrorHandlingState();
248         doReturn(1L).when(this.bgpErrorHandlingState).getErroneousUpdateReceivedCount();
249
250         doReturn(this.bgpGracelfulRestartState).when(this.bgpPeerState).getBGPGracelfulRestart();
251         doReturn(true).when(this.bgpGracelfulRestartState).isLocalRestarting();
252         doReturn(true).when(this.bgpGracelfulRestartState).isPeerRestarting();
253         doReturn(this.restartTime.toJava()).when(this.bgpGracelfulRestartState).getPeerRestartTime();
254         doReturn(BgpAfiSafiGracefulRestartState.Mode.BILATERAL).when(this.bgpGracelfulRestartState).getMode();
255
256         doReturn(this.bgpAfiSafiState).when(this.bgpPeerState).getBGPAfiSafiState();
257         doReturn(Set.of(TABLES_KEY)).when(this.bgpAfiSafiState).getAfiSafisAdvertized();
258         doReturn(Set.of(TABLES_KEY)).when(this.bgpAfiSafiState).getAfiSafisReceived();
259         doReturn(1L).when(this.bgpAfiSafiState).getPrefixesInstalledCount(any());
260         doReturn(2L).when(this.bgpAfiSafiState).getPrefixesReceivedCount(any());
261         doReturn(1L).when(this.bgpAfiSafiState).getPrefixesSentCount(any());
262         doReturn(true).when(this.bgpAfiSafiState).isAfiSafiSupported(any());
263         doReturn(true).when(this.bgpAfiSafiState).isGracefulRestartAdvertized(any());
264         doReturn(true).when(this.bgpAfiSafiState).isGracefulRestartReceived(any());
265         doReturn(true).when(this.bgpAfiSafiState).isLlGracefulRestartAdvertised(any());
266         doReturn(true).when(this.bgpAfiSafiState).isLlGracefulRestartReceived(any());
267         doReturn(60).when(this.bgpAfiSafiState).getLlGracefulRestartTimer(any());
268     }
269
270     @Override
271     protected AbstractDataBrokerTestCustomizer createDataBrokerTestCustomizer() {
272         return new ConcurrentDataBrokerTestCustomizer(true) {
273             @Override
274             public DOMStore createOperationalDatastore() {
275                 realOperStore = new InMemoryDOMDataStore("OPER", getDataTreeChangeListenerExecutor());
276                 spiedOperStore = spy(realOperStore);
277                 getSchemaService().registerSchemaContextListener(spiedOperStore);
278                 return spiedOperStore;
279             }
280
281             @Override
282             public ListeningExecutorService getCommitCoordinatorExecutor() {
283                 return MoreExecutors.newDirectExecutorService();
284             }
285         };
286     }
287
288     @Test
289     public void testActiveStateProvider() throws Exception {
290         doReturn(true).when(this.bgpRibState).isActive();
291         doReturn(true).when(this.bgpPeerState).isActive();
292
293         try (StateProviderImpl stateProvider =
294                 // FIXME: use a properly-controlled executor service
295                 new StateProviderImpl(getDataBroker(), 1, tableTypeRegistry, this.stateProvider, "global-bgp")) {
296
297             final Global globalExpected = buildGlobalExpected(0);
298             this.bgpRibStates.add(this.bgpRibState);
299             readDataOperational(getDataBroker(), this.bgpInstanceIdentifier, bgpRib -> {
300                 final Global global = bgpRib.getGlobal();
301                 assertEquals(globalExpected, global);
302                 return bgpRib;
303             });
304
305             this.totalPathsCounter.increment();
306             this.totalPrefixesCounter.increment();
307
308             final Global globalExpected2 = buildGlobalExpected(1);
309             readDataOperational(getDataBroker(), this.bgpInstanceIdentifier, bgpRib -> {
310                 final Global global = bgpRib.getGlobal();
311                 assertEquals(globalExpected2, global);
312                 return bgpRib;
313             });
314
315             this.totalPathsCounter.decrement();
316             this.totalPrefixesCounter.decrement();
317
318             final Global globalExpected3 = buildGlobalExpected(0);
319             readDataOperational(getDataBroker(), this.bgpInstanceIdentifier, bgpRib -> {
320                 final Global global = bgpRib.getGlobal();
321                 assertEquals(globalExpected3, global);
322                 assertNull(bgpRib.getNeighbors());
323                 assertNull(bgpRib.getPeerGroups());
324                 return bgpRib;
325             });
326
327             this.bgpPeerStates.add(this.bgpPeerState);
328             final PeerGroup peerGroupExpected = buildGroupExpected();
329
330             this.totalPathsCounter.increment();
331             this.totalPrefixesCounter.increment();
332
333             final AfiSafis expectedAfiSafis = buildAfiSafis();
334             final ErrorHandling expectedErrorHandling = buildErrorHandling();
335             final GracefulRestart expectedGracefulRestart = buildGracefulRestart();
336             final Transport expectedTransport = buildTransport();
337             final Timers expectedTimers = buildTimers();
338             final BgpNeighborStateAugmentation expectedBgpNeighborState = buildBgpNeighborStateAugmentation();
339
340             readDataOperational(getDataBroker(), bgpInstanceIdentifier, bgpRib -> {
341                 final Neighbors neighbors = bgpRib.getNeighbors();
342                 assertNotNull(neighbors);
343                 assertEquals(peerGroupExpected, bgpRib.getPeerGroups().nonnullPeerGroup().values().iterator().next());
344                 final Neighbor neighborResult = neighbors.nonnullNeighbor().values().iterator().next();
345                 assertEquals(new IpAddress(neighborAddress.getIpv4AddressNoZone()),
346                     neighborResult.getNeighborAddress());
347                 assertEquals(expectedAfiSafis, neighborResult.getAfiSafis());
348                 assertEquals(expectedErrorHandling, neighborResult.getErrorHandling());
349                 assertEquals(expectedGracefulRestart, neighborResult.getGracefulRestart());
350                 assertEquals(expectedTransport, neighborResult.getTransport());
351                 assertEquals(expectedTimers, neighborResult.getTimers());
352                 final org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group
353                     .State stateResult = neighborResult.getState();
354                 assertEquals(expectedBgpNeighborState, stateResult.augmentation(BgpNeighborStateAugmentation.class));
355                 assertEquals(BgpNeighborState.SessionState.ESTABLISHED, stateResult
356                     .augmentation(NeighborStateAugmentation.class).getSessionState());
357                 final List<Class<? extends BgpCapability>> supportedCapabilitiesResult = stateResult
358                     .augmentation(NeighborStateAugmentation.class).getSupportedCapabilities();
359                 assertTrue(supportedCapabilitiesResult.containsAll(this.supportedCap));
360                 return bgpRib;
361             });
362
363             this.bgpRibStates.clear();
364             checkNotPresentOperational(getDataBroker(), this.bgpInstanceIdentifier);
365         }
366     }
367
368     @Test
369     public void testInactiveStateProvider() throws Exception {
370         doReturn(false).when(this.bgpRibState).isActive();
371
372         try (StateProviderImpl stateProvider =
373                 new StateProviderImpl(getDataBroker(), 100, TimeUnit.MILLISECONDS, tableTypeRegistry,
374                         this.stateProvider,
375                     // FIXME: use a properly-controlled executor service ...
376                     "global-bgp", Executors.newScheduledThreadPool(1))) {
377
378             bgpRibStates.add(this.bgpRibState);
379             /// ... and trigger here
380             Uninterruptibles.sleepUninterruptibly(500, TimeUnit.MILLISECONDS);
381             checkNotPresentOperational(getDataBroker(), this.bgpInstanceIdentifier);
382
383             bgpPeerStates.add(this.bgpPeerState);
384             /// ... and trigger here
385             Uninterruptibles.sleepUninterruptibly(500, TimeUnit.MILLISECONDS);
386             checkNotPresentOperational(getDataBroker(), this.bgpInstanceIdentifier);
387
388             bgpRibStates.clear();
389             /// ... and trigger here
390             Uninterruptibles.sleepUninterruptibly(500, TimeUnit.MILLISECONDS);
391             checkNotPresentOperational(getDataBroker(), this.bgpInstanceIdentifier);
392         }
393     }
394
395     @Test
396     public void testTransactionChainFailure() throws Exception {
397         if (!(LoggerFactory.getLogger(StateProviderImpl.class) instanceof RememberingLogger)) {
398             throw new IllegalStateException("infrautils-testutils must be on the classpath BEFORE other logger impls"
399                 + LoggerFactory.getLogger(StateProviderImpl.class).getClass());
400         }
401
402         doReturn(true).when(this.bgpRibState).isActive();
403
404         this.bgpRibStates.add(this.bgpRibState);
405
406         ScheduledFuture<?> mockScheduledFuture = mock(ScheduledFuture.class);
407         doReturn(true).when(mockScheduledFuture).cancel(anyBoolean());
408
409         ScheduledExecutorService mockScheduler = mock(ScheduledExecutorService.class);
410         doReturn(mockScheduledFuture).when(mockScheduler).scheduleAtFixedRate(any(Runnable.class), anyLong(),
411                 anyLong(), any(TimeUnit.class));
412         doNothing().when(mockScheduler).shutdown();
413
414         DOMStoreTransactionChain mockTxChain = mock(DOMStoreTransactionChain.class);
415
416         Throwable mockCommitEx = new Exception("mock commit failure");
417         doAnswer(invocation -> {
418             DOMStoreThreePhaseCommitCohort mockCohort = mock(DOMStoreThreePhaseCommitCohort.class);
419             doReturn(Futures.immediateFailedFuture(mockCommitEx)).when(mockCohort).canCommit();
420             doReturn(Futures.immediateFuture(null)).when(mockCohort).abort();
421
422             doAnswer(notused -> {
423                 DOMStoreWriteTransaction mockWriteTx = mock(DOMStoreReadWriteTransaction .class);
424                 doNothing().when(mockWriteTx).write(any(), any());
425                 doNothing().when(mockWriteTx).merge(any(), any());
426                 doReturn(mockCohort).when(mockWriteTx).ready();
427                 return mockWriteTx;
428             }).when(mockTxChain).newReadWriteTransaction();
429
430             return mockTxChain;
431         }).doAnswer(invocation -> realOperStore.createTransactionChain()).when(spiedOperStore).createTransactionChain();
432
433         final int period = 100;
434         final TimeUnit unit = TimeUnit.MILLISECONDS;
435         try (StateProviderImpl stateProvider = new StateProviderImpl(getDataBroker(), period, unit, tableTypeRegistry,
436                 this.stateProvider, "global-bgp", mockScheduler)) {
437
438             ArgumentCaptor<Runnable> timerTask = ArgumentCaptor.forClass(Runnable.class);
439             verify(mockScheduler).scheduleAtFixedRate(timerTask.capture(), eq(0L), eq((long)period), eq(unit));
440
441             timerTask.getValue().run();
442
443             String lastError = RememberingLogger.getLastErrorThrowable().orElseThrow(
444                 () -> new AssertionError("Expected logged ERROR")).toString();
445             assertTrue("Last logged ERROR didn't contain expected string: " + lastError,
446                     lastError.contains(mockCommitEx.getMessage()));
447
448             RememberingLogger.resetLastError();
449
450             timerTask.getValue().run();
451
452             List<LogCapture> loggedErrors = RememberingLogger.getErrorLogCaptures();
453             assertTrue("Expected no logged ERRORs: " + loggedErrors, loggedErrors.isEmpty());
454
455             verify(spiedOperStore, times(2)).createTransactionChain();
456         }
457     }
458
459     private static BgpNeighborStateAugmentation buildBgpNeighborStateAugmentation() {
460         final BgpNeighborStateAugmentation augmentation = new BgpNeighborStateAugmentationBuilder()
461                 .setMessages(new MessagesBuilder().setReceived(new ReceivedBuilder()
462                         .setNOTIFICATION(Uint64.ONE).setUPDATE(Uint64.ONE).build())
463                         .setSent(new SentBuilder().setNOTIFICATION(Uint64.ONE).setUPDATE(Uint64.ONE).build())
464                         .build()).build();
465         return augmentation;
466     }
467
468     private static AfiSafis buildAfiSafis() {
469         final NeighborAfiSafiStateAugmentationBuilder neighborAfiSafiStateAugmentation =
470                 new NeighborAfiSafiStateAugmentationBuilder()
471                 .setActive(true)
472                 .setPrefixes(new PrefixesBuilder()
473                     .setSent(Uint32.ONE)
474                     .setReceived(Uint32.TWO)
475                     .setInstalled(Uint32.ONE)
476                     .build());
477         final AfiSafi afiSafi = new AfiSafiBuilder()
478                 .setAfiSafiName(IPV4UNICAST.class)
479                 .setGracefulRestart(new GracefulRestartBuilder()
480                     .setState(new StateBuilder().setEnabled(false)
481                         .addAugmentation(new NeighborAfiSafiGracefulRestartStateAugmentationBuilder()
482                             .setAdvertised(true)
483                             .setReceived(true)
484                             .setLlStaleTimer(Uint32.valueOf(60))
485                             .setLlAdvertised(true)
486                             .setLlReceived(true)
487                             .build())
488                         .build())
489                     .build())
490                 .setState(new org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.multiprotocol.rev151009.bgp
491                         .common.afi.safi.list.afi.safi.StateBuilder()
492                             .setEnabled(false)
493                             .addAugmentation(neighborAfiSafiStateAugmentation.build())
494                         .build())
495                 .build();
496
497         return new AfiSafisBuilder().setAfiSafi(Map.of(afiSafi.key(), afiSafi)).build();
498     }
499
500     private static ErrorHandling buildErrorHandling() {
501         final ErrorHandling errorHandling = new ErrorHandlingBuilder().setState(
502                 new org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.error
503                         .handling.StateBuilder().setTreatAsWithdraw(false)
504                         .addAugmentation(new NeighborErrorHandlingStateAugmentationBuilder()
505                                         .setErroneousUpdateMessages(Uint32.ONE).build()).build()).build();
506         return errorHandling;
507     }
508
509     private static Timers buildTimers() {
510         return new TimersBuilder()
511                 .setState(new org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group
512                     .timers.StateBuilder()
513                         .setConnectRetry(BigDecimal.valueOf(30))
514                         .setHoldTime(BigDecimal.valueOf(90))
515                         .setKeepaliveInterval(BigDecimal.valueOf(30))
516                         .setMinimumAdvertisementInterval(BigDecimal.valueOf(30))
517                         .addAugmentation(new NeighborTimersStateAugmentationBuilder()
518                             .setNegotiatedHoldTime(BigDecimal.TEN)
519                             .setUptime(new Timeticks(Uint32.ONE)).build())
520                         .build())
521                 .build();
522     }
523
524     private Transport buildTransport() {
525         return new TransportBuilder()
526                 .setState(new org.opendaylight.yang.gen.v1.http.openconfig
527                 .net.yang.bgp.rev151009.bgp.neighbor.group.transport.StateBuilder()
528                     .setMtuDiscovery(false)
529                 .setPassiveMode(false)
530                 .addAugmentation(new NeighborTransportStateAugmentationBuilder()
531                     .setLocalPort(this.localPort)
532                                 .setRemotePort(this.remotePort)
533                                 .setRemoteAddress(new IpAddress(neighborAddress.getIpv4AddressNoZone())).build())
534                 .build()).build();
535     }
536
537     private GracefulRestart buildGracefulRestart() {
538         final NeighborGracefulRestartStateAugmentationBuilder gracefulAugmentation
539                 = new NeighborGracefulRestartStateAugmentationBuilder()
540                 .setPeerRestarting(false)
541                 .setLocalRestarting(false)
542                 .setPeerRestartTime(Uint16.ZERO)
543                 .setLocalRestarting(true)
544                 .setPeerRestarting(true)
545                 .setPeerRestartTime(this.restartTime)
546                 .setMode(BgpAfiSafiGracefulRestartState.Mode.BILATERAL);
547         final GracefulRestart gracefulRestart = new org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp
548                 .rev151009.bgp.graceful.restart.GracefulRestartBuilder().setState(new org.opendaylight.yang.gen.v1.http
549                 .openconfig.net.yang.bgp.rev151009.bgp.graceful.restart.graceful.restart.StateBuilder()
550                 .addAugmentation(gracefulAugmentation.build()).build()).build();
551         return gracefulRestart;
552     }
553
554     private Global buildGlobalExpected(final long prefixesAndPaths) {
555         return new GlobalBuilder()
556                 .setState(new org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.global.base
557                         .StateBuilder()
558                             .setRouterId(new Ipv4Address(this.bgpId.getValue()))
559                             .setTotalPrefixes(Uint32.valueOf(prefixesAndPaths))
560                             .setTotalPaths(Uint32.valueOf(prefixesAndPaths))
561                             .setAs(this.as)
562                             .build())
563                 .setAfiSafis(new org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.global.base
564                         .AfiSafisBuilder()
565                             .setAfiSafi(BindingMap.of(new AfiSafiBuilder()
566                                 .setAfiSafiName(IPV4UNICAST.class)
567                                 .setState(new org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.multiprotocol
568                                     .rev151009.bgp.common.afi.safi.list.afi.safi.StateBuilder()
569                                         .setEnabled(false)
570                                         .addAugmentation(new GlobalAfiSafiStateAugmentationBuilder()
571                                             .setTotalPaths(Uint32.valueOf(prefixesAndPaths))
572                                             .setTotalPrefixes(Uint32.valueOf(prefixesAndPaths))
573                                             .build())
574                                         .build())
575                                 .build()))
576                         .build())
577                 .build();
578     }
579
580     private static PeerGroup buildGroupExpected() {
581         return new PeerGroupBuilder()
582                 .setPeerGroupName("test-group")
583                 .setState(new org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group
584                     .StateBuilder()
585                     .setSendCommunity(CommunityType.NONE)
586                     .setRouteFlapDamping(false)
587                     .addAugmentation(new PeerGroupStateAugmentationBuilder()
588                         .setTotalPaths(Uint32.ONE)
589                         .setTotalPrefixes(Uint32.ONE)
590                         .build())
591                     .build())
592                 .build();
593     }
594 }