Final round of isFoo() migration
[openflowplugin.git] / applications / forwardingrules-sync / src / test / java / org / opendaylight / openflowplugin / applications / frsync / impl / SimplifiedOperationalListenerTest.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.openflowplugin.applications.frsync.impl;
9
10 import com.google.common.util.concurrent.Futures;
11 import java.text.ParseException;
12 import java.text.SimpleDateFormat;
13 import java.util.Collections;
14 import java.util.Map;
15 import java.util.Optional;
16 import org.junit.Assert;
17 import org.junit.Before;
18 import org.junit.Test;
19 import org.junit.runner.RunWith;
20 import org.mockito.ArgumentMatchers;
21 import org.mockito.Mock;
22 import org.mockito.Mockito;
23 import org.mockito.junit.MockitoJUnitRunner;
24 import org.opendaylight.mdsal.binding.api.DataBroker;
25 import org.opendaylight.mdsal.binding.api.DataObjectModification;
26 import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
27 import org.opendaylight.mdsal.binding.api.DataTreeModification;
28 import org.opendaylight.mdsal.binding.api.ReadTransaction;
29 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
30 import org.opendaylight.openflowplugin.applications.frsync.SyncReactor;
31 import org.opendaylight.openflowplugin.applications.frsync.dao.FlowCapableNodeCachedDao;
32 import org.opendaylight.openflowplugin.applications.frsync.dao.FlowCapableNodeDao;
33 import org.opendaylight.openflowplugin.applications.frsync.dao.FlowCapableNodeOdlDao;
34 import org.opendaylight.openflowplugin.applications.frsync.dao.FlowCapableNodeSnapshotDao;
35 import org.opendaylight.openflowplugin.applications.frsync.impl.clustering.DeviceMastershipManager;
36 import org.opendaylight.openflowplugin.applications.frsync.util.ReconciliationRegistry;
37 import org.opendaylight.openflowplugin.applications.frsync.util.SyncupEntry;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DateAndTime;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableStatisticsGatheringStatus;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.snapshot.gathering.status.grouping.SnapshotGatheringStatusEnd;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
48 import org.opendaylight.yangtools.util.concurrent.FluentFutures;
49 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
50
51 /**
52  * Test for {@link SimplifiedOperationalListener}.
53  */
54 @RunWith(MockitoJUnitRunner.class)
55 public class SimplifiedOperationalListenerTest {
56
57     private static final NodeId NODE_ID = new NodeId("testNode");
58     private InstanceIdentifier<FlowCapableNode> fcNodePath;
59     private SimplifiedOperationalListener nodeListenerOperational;
60     private final LogicalDatastoreType configDS = LogicalDatastoreType.CONFIGURATION;
61     private final LogicalDatastoreType operationalDS = LogicalDatastoreType.OPERATIONAL;
62     private final SimpleDateFormat simpleDateFormat =
63             new SimpleDateFormat(SimplifiedOperationalListener.DATE_AND_TIME_FORMAT);
64
65     @Mock
66     private SyncReactor reactor;
67     @Mock
68     private ReadTransaction roTx;
69     @Mock
70     private DataTreeModification<Node> dataTreeModification;
71     @Mock
72     private DataObjectModification<Node> operationalModification;
73     @Mock
74     private FlowCapableNode configNode;
75     @Mock
76     private Node operationalNode;
77     @Mock
78     private FlowCapableNode fcOperationalNode;
79     @Mock
80     private FlowCapableStatisticsGatheringStatus statisticsGatheringStatus;
81     @Mock
82     private SnapshotGatheringStatusEnd snapshotGatheringStatusEnd;
83     @Mock
84     private ReconciliationRegistry reconciliationRegistry;
85     @Mock
86     private DeviceMastershipManager deviceMastershipManager;
87     @Mock
88     private Map<NodeConnectorKey, NodeConnector> nodeConnector;
89     @Mock
90     private Node operationalNodeEmpty;
91
92     @Before
93     public void setUp() {
94         final DataBroker db = Mockito.mock(DataBroker.class);
95         final FlowCapableNodeSnapshotDao configSnapshot = new FlowCapableNodeSnapshotDao();
96         final FlowCapableNodeSnapshotDao operationalSnapshot = new FlowCapableNodeSnapshotDao();
97         final FlowCapableNodeDao configDao = new FlowCapableNodeCachedDao(configSnapshot,
98                 new FlowCapableNodeOdlDao(db, LogicalDatastoreType.CONFIGURATION));
99
100         nodeListenerOperational = new SimplifiedOperationalListener(reactor, operationalSnapshot, configDao,
101                 reconciliationRegistry, deviceMastershipManager);
102         InstanceIdentifier<Node> nodePath = InstanceIdentifier.create(Nodes.class).child(Node.class,
103                 new NodeKey(NODE_ID));
104         fcNodePath = nodePath.augmentation(FlowCapableNode.class);
105
106         final DataTreeIdentifier<Node> dataTreeIdentifier =
107                 DataTreeIdentifier.create(LogicalDatastoreType.OPERATIONAL, nodePath);
108
109         Mockito.when(db.newReadOnlyTransaction()).thenReturn(roTx);
110         Mockito.when(operationalNode.getId()).thenReturn(NODE_ID);
111         Mockito.when(dataTreeModification.getRootPath()).thenReturn(dataTreeIdentifier);
112         Mockito.when(dataTreeModification.getRootNode()).thenReturn(operationalModification);
113         Mockito.when(operationalNode.augmentation(FlowCapableNode.class)).thenReturn(fcOperationalNode);
114     }
115
116     @Test
117     public void testDSLogicalType() {
118         Assert.assertEquals(LogicalDatastoreType.OPERATIONAL, nodeListenerOperational.dsType());
119     }
120
121     @Test
122     public void testOnDataTreeChangedAddPhysical() {
123         operationalAdd();
124         nodeListenerOperational.onDataTreeChanged(Collections.singleton(dataTreeModification));
125         Mockito.verify(deviceMastershipManager).onDeviceConnected(NODE_ID);
126         Mockito.verifyNoMoreInteractions(reactor);
127     }
128
129     @Test
130     public void testOnDataTreeChangedDeletePhysical() {
131         Mockito.when(operationalModification.getDataBefore()).thenReturn(operationalNode);
132         Mockito.when(operationalModification.getDataAfter()).thenReturn(null);
133
134         nodeListenerOperational.onDataTreeChanged(Collections.singleton(dataTreeModification));
135
136         Mockito.verify(deviceMastershipManager).onDeviceDisconnected(NODE_ID);
137         Mockito.verifyNoMoreInteractions(reactor);
138     }
139
140     @Test
141     public void testOnDataTreeChangedDeleteLogical() {
142         Mockito.when(operationalModification.getDataBefore()).thenReturn(operationalNode);
143         Mockito.when(operationalNode.getNodeConnector()).thenReturn(nodeConnector);
144         Mockito.when(operationalNodeEmpty.getId()).thenReturn(NODE_ID);
145         Mockito.when(operationalModification.getDataAfter()).thenReturn(operationalNodeEmpty);
146         Mockito.when(operationalNodeEmpty.getNodeConnector()).thenReturn(null);
147
148         nodeListenerOperational.onDataTreeChanged(Collections.singleton(dataTreeModification));
149
150         Mockito.verify(deviceMastershipManager).onDeviceDisconnected(NODE_ID);
151         Mockito.verifyNoMoreInteractions(reactor);
152     }
153
154     @Test
155     public void testOnDataTreeChangedReconcileNotRegistered() {
156         Mockito.when(reconciliationRegistry.isRegistered(NODE_ID)).thenReturn(false);
157         operationalUpdate();
158
159         nodeListenerOperational.onDataTreeChanged(Collections.singleton(dataTreeModification));
160
161         Mockito.verifyNoMoreInteractions(reactor);
162     }
163
164     @Test
165     public void testOnDataTreeChangedReconcileButStaticsGatheringNotStarted() {
166         Mockito.when(reconciliationRegistry.isRegistered(NODE_ID)).thenReturn(true);
167         operationalUpdate();
168         Mockito.when(operationalNode.augmentation(FlowCapableStatisticsGatheringStatus.class)).thenReturn(null);
169
170         nodeListenerOperational.onDataTreeChanged(Collections.singleton(dataTreeModification));
171
172         Mockito.verifyNoMoreInteractions(reactor);
173     }
174
175     @Test
176     public void testOnDataTreeChangedReconcileButStaticsGatheringNotFinished() {
177         Mockito.when(reconciliationRegistry.isRegistered(NODE_ID)).thenReturn(true);
178         operationalUpdate();
179         Mockito.when(operationalNode.augmentation(FlowCapableStatisticsGatheringStatus.class))
180             .thenReturn(statisticsGatheringStatus);
181         Mockito.when(statisticsGatheringStatus.getSnapshotGatheringStatusEnd()).thenReturn(null);
182
183         nodeListenerOperational.onDataTreeChanged(Collections.singleton(dataTreeModification));
184
185         Mockito.verifyNoMoreInteractions(reactor);
186     }
187
188     @Test
189     public void testOnDataTreeChangedReconcileButStaticsGatheringNotSuccessful() {
190         Mockito.when(reconciliationRegistry.isRegistered(NODE_ID)).thenReturn(true);
191         operationalUpdate();
192         Mockito.when(operationalNode.augmentation(FlowCapableStatisticsGatheringStatus.class))
193             .thenReturn(statisticsGatheringStatus);
194         Mockito.when(statisticsGatheringStatus.getSnapshotGatheringStatusEnd()).thenReturn(snapshotGatheringStatusEnd);
195         Mockito.when(snapshotGatheringStatusEnd.getSucceeded()).thenReturn(false);
196
197         nodeListenerOperational.onDataTreeChanged(Collections.singleton(dataTreeModification));
198
199         Mockito.verifyNoMoreInteractions(reactor);
200     }
201
202     @Test
203     public void testOnDataTreeChangedReconcileAndFreshOperationalNotPresent() throws ParseException {
204         Mockito.when(reconciliationRegistry.isRegistered(NODE_ID)).thenReturn(true);
205         operationalUpdate();
206         prepareFreshOperational(false);
207
208         nodeListenerOperational.onDataTreeChanged(Collections.singleton(dataTreeModification));
209
210         Mockito.verifyNoMoreInteractions(reactor);
211     }
212
213     @Test
214     public void testOnDataTreeChangedReconcileAndFreshOperationalPresent() throws Exception {
215         Mockito.when(reconciliationRegistry.isRegistered(NODE_ID)).thenReturn(true);
216         operationalUpdate();
217         prepareFreshOperational(true);
218         final SyncupEntry syncupEntry = loadConfigDSAndPrepareSyncupEntry(
219                 configNode, configDS, fcOperationalNode, operationalDS);
220
221         nodeListenerOperational.onDataTreeChanged(Collections.singleton(dataTreeModification));
222
223         Mockito.verify(reactor).syncup(fcNodePath, syncupEntry);
224         Mockito.verify(roTx).close();
225     }
226
227
228     @Test
229     public void testOnDataTreeChangedReconcileAndFreshOperationalNotPresentButAdd() throws ParseException {
230         Mockito.when(reconciliationRegistry.isRegistered(NODE_ID)).thenReturn(true);
231         operationalAdd();
232         prepareFreshOperational(false);
233         final SyncupEntry syncupEntry = loadConfigDSAndPrepareSyncupEntry(
234                 configNode, configDS, fcOperationalNode, operationalDS);
235
236         nodeListenerOperational.onDataTreeChanged(Collections.singleton(dataTreeModification));
237
238         Mockito.verify(reactor).syncup(fcNodePath, syncupEntry);
239         Mockito.verify(roTx).close();
240     }
241
242     @Test
243     public void testOnDataTreeChangedReconcileAndConfigNotPresent() throws Exception {
244         // Related to bug 5920 -> https://bugs.opendaylight.org/show_bug.cgi?id=5920
245         Mockito.when(reconciliationRegistry.isRegistered(NODE_ID)).thenReturn(true);
246         operationalUpdate();
247         prepareFreshOperational(true);
248
249         Mockito.doReturn(FluentFutures.immediateFluentFuture(Optional.empty())).when(roTx)
250             .read(LogicalDatastoreType.CONFIGURATION, fcNodePath);
251
252         nodeListenerOperational.onDataTreeChanged(Collections.singleton(dataTreeModification));
253
254         Mockito.verify(reconciliationRegistry).unregisterIfRegistered(NODE_ID);
255         Mockito.verifyNoMoreInteractions(reactor);
256         Mockito.verify(roTx).close();
257     }
258
259     private void prepareFreshOperational(final boolean afterRegistration) throws ParseException {
260         Mockito.when(operationalNode.augmentation(FlowCapableStatisticsGatheringStatus.class))
261              .thenReturn(statisticsGatheringStatus);
262         Mockito.when(statisticsGatheringStatus.getSnapshotGatheringStatusEnd()).thenReturn(snapshotGatheringStatusEnd);
263         Mockito.when(snapshotGatheringStatusEnd.getSucceeded()).thenReturn(true);
264         Mockito.when(snapshotGatheringStatusEnd.getEnd()).thenReturn(Mockito.mock(DateAndTime.class));
265         final String timestampBefore = "0000-12-12T01:01:01.000-07:00";
266         final String timestampAfter = "9999-12-12T01:01:01.000-07:00";
267         if (afterRegistration) {
268             Mockito.when(snapshotGatheringStatusEnd.getEnd().getValue()).thenReturn(timestampAfter);
269             Mockito.when(reconciliationRegistry.getRegistrationTimestamp(NODE_ID))
270                 .thenReturn(simpleDateFormat.parse(timestampBefore));
271         } else {
272             Mockito.when(snapshotGatheringStatusEnd.getEnd().getValue()).thenReturn(timestampBefore);
273             Mockito.when(reconciliationRegistry.getRegistrationTimestamp(NODE_ID))
274                 .thenReturn(simpleDateFormat.parse(timestampAfter));
275         }
276     }
277
278     private void operationalAdd() {
279         Mockito.when(operationalModification.getDataBefore()).thenReturn(null);
280         Mockito.when(operationalModification.getDataAfter()).thenReturn(operationalNode);
281     }
282
283     private void operationalUpdate() {
284         Mockito.when(operationalModification.getDataBefore()).thenReturn(operationalNode);
285         Mockito.when(operationalModification.getDataAfter()).thenReturn(operationalNode);
286     }
287
288     private SyncupEntry loadConfigDSAndPrepareSyncupEntry(final FlowCapableNode after,
289             final LogicalDatastoreType dsTypeAfter, final FlowCapableNode before,
290             final LogicalDatastoreType dsTypeBefore) {
291
292         Mockito.doReturn(FluentFutures.immediateFluentFuture(Optional.of(configNode))).when(roTx)
293             .read(LogicalDatastoreType.CONFIGURATION, fcNodePath);
294         final SyncupEntry syncupEntry = new SyncupEntry(after, dsTypeAfter, before, dsTypeBefore);
295         Mockito.when(reactor.syncup(ArgumentMatchers.any(),
296                 Mockito.eq(syncupEntry))).thenReturn(Futures.immediateFuture(Boolean.TRUE));
297         return syncupEntry;
298     }
299 }