bug 8029 handle expired in transit entries
[ovsdb.git] / hwvtepsouthbound / hwvtepsouthbound-impl / src / test / java / org / opendaylight / ovsdb / hwvtepsouthbound / HwvtepDataChangeListenerTest.java
1 /*
2  * Copyright (c) 2016, 2017 Ericsson India Global Services Pvt Ltd. 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
9 package org.opendaylight.ovsdb.hwvtepsouthbound;
10
11 import com.google.common.collect.Lists;
12 import org.apache.commons.lang3.reflect.FieldUtils;
13 import org.junit.After;
14 import org.junit.Before;
15 import org.junit.Test;
16 import org.junit.runner.RunWith;
17 import org.mockito.Matchers;
18 import org.mockito.Mockito;
19 import org.opendaylight.ovsdb.hwvtepsouthbound.transact.DependencyQueue;
20 import org.opendaylight.ovsdb.lib.operations.Operations;
21 import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
22 import org.opendaylight.ovsdb.lib.schema.typed.TypedBaseTable;
23 import org.opendaylight.ovsdb.schema.hardwarevtep.LogicalSwitch;
24 import org.opendaylight.ovsdb.schema.hardwarevtep.McastMacsRemote;
25 import org.opendaylight.ovsdb.schema.hardwarevtep.UcastMacsRemote;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteUcastMacs;
29 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
30 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
31 import org.opendaylight.yangtools.yang.binding.DataObject;
32 import org.powermock.api.mockito.PowerMockito;
33 import org.powermock.core.classloader.annotations.PrepareForTest;
34 import org.powermock.modules.junit4.PowerMockRunner;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38 import java.lang.reflect.Field;
39 import java.lang.reflect.Modifier;
40 import java.util.Iterator;
41 import java.util.List;
42
43 import static org.junit.Assert.assertNotNull;
44 import static org.junit.Assert.assertTrue;
45 import static org.mockito.Matchers.any;
46 import static org.mockito.Mockito.times;
47 import static org.mockito.Mockito.verify;
48 import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.CONFIGURATION;
49 import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.OPERATIONAL;
50
51 /**
52  * Unit tests for the data-tree change listener.
53  */
54 @RunWith(PowerMockRunner.class)
55 @PrepareForTest({HwvtepConnectionInstance.class, HwvtepConnectionManager.class, Operations.class})
56 public class HwvtepDataChangeListenerTest extends DataChangeListenerTestBase {
57
58     static Logger LOG = LoggerFactory.getLogger(HwvtepDataChangeListenerTest.class);
59
60     String[][] ucastMacs = new String[][]{
61             {"20:00:00:00:00:01", "11.10.10.1", "192.168.122.20", "ls0"},
62             {"20:00:00:00:00:02", "11.10.10.2", "192.168.122.20", "ls0"},
63             {"20:00:00:00:00:03", "11.10.10.3", "192.168.122.30", "ls1"},
64             {"20:00:00:00:00:04", "11.10.10.4", "192.168.122.30", "ls1"}
65     };
66
67     String[][] logicalSwitches = new String[][]{
68             {"ls0", "100"},
69             {"ls1", "200"},
70     };
71
72     String[][] terminationPoints = new String[][]{
73             {"192.168.122.10"},
74             {"192.168.122.20"},
75             {"192.168.122.30"},
76             {"192.168.122.40"}
77     };
78
79     String[][] mcastMacs = new String[][]{
80             {"FF:FF:FF:FF:FF:FF", "ls0", "192.168.122.20", "192.168.122.30"},
81             {"FF:FF:FF:FF:FF:FF", "ls1", "192.168.122.10", "192.168.122.30"}
82     };
83
84     String[][] mcastMac2 = new String[][]{
85             {"FF:FF:FF:FF:FF:FF", "ls0", "192.168.122.20", "192.168.122.10"},
86             {"FF:FF:FF:FF:FF:FF", "ls1", "192.168.122.10", "192.168.122.20"}
87     };
88
89     String[][] mcastMac3WithZeroLocators = new String[][]{
90             {"FF:FF:FF:FF:FF:FF", "ls0"},
91             {"FF:FF:FF:FF:FF:FF", "ls1"}
92     };
93
94     HwvtepOperationalDataChangeListener opDataChangeListener;
95
96     @Before
97     public void setupListener() throws Exception {
98         setFinalStatic(DependencyQueue.class, "executorService", PowerMockito.mock(SameThreadScheduledExecutor.class, Mockito.CALLS_REAL_METHODS));
99         opDataChangeListener = new HwvtepOperationalDataChangeListener(dataBroker, hwvtepConnectionManager, connectionInstance);
100     }
101
102     @After
103     public void cleanupListener() {
104         try {
105             opDataChangeListener.close();
106         } catch (Exception e) {
107         }
108     }
109
110     void setFinalStatic(Class cls, String fieldName, Object newValue) throws Exception {
111         Field fields[] = FieldUtils.getAllFields(cls);
112         for (Field field : fields) {
113             if (fieldName.equals(field.getName())) {
114                 field.setAccessible(true);
115                 Field modifiersField = Field.class.getDeclaredField("modifiers");
116                 modifiersField.setAccessible(true);
117                 modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
118                 field.set(null, newValue);
119                 break;
120             }
121         }
122     }
123
124     @Test
125     public <T extends DataObject> void testLogicalSwitchAdd() throws Exception {
126         addData(CONFIGURATION, LogicalSwitches.class, logicalSwitches);
127         verifyThatLogicalSwitchCreated();
128     }
129
130     @Test
131     public <T extends DataObject> void testLogicalSwitchDelete() throws Exception {
132         addData(CONFIGURATION, LogicalSwitches.class, logicalSwitches);
133         addData(OPERATIONAL, LogicalSwitches.class, logicalSwitches);
134         resetOperations();
135         deleteData(CONFIGURATION, LogicalSwitches.class, logicalSwitches);
136         verify(Operations.op,  times(10)).delete(any());
137     }
138
139     @Test
140     public <T extends DataObject> void testUcastMacAdd() throws Exception {
141         addData(CONFIGURATION, LogicalSwitches.class, logicalSwitches);
142         addData(OPERATIONAL, LogicalSwitches.class, logicalSwitches);
143         resetOperations();
144         addData(CONFIGURATION, TerminationPoint.class, terminationPoints);
145         addData(CONFIGURATION, RemoteUcastMacs.class, ucastMacs);
146         //4 ucast macs + 2 termination points
147         verify(Operations.op,  times(6)).insert(any(UcastMacsRemote.class));
148         //TODO add finer grained validation
149     }
150
151     @Test
152     public <T extends DataObject> void testUcastMacAddWithoutConfigTep() throws Exception {
153         addData(CONFIGURATION, LogicalSwitches.class, logicalSwitches);
154         addData(OPERATIONAL, LogicalSwitches.class, logicalSwitches);
155         resetOperations();
156         addData(CONFIGURATION, RemoteUcastMacs.class, ucastMacs);
157         //4 ucast macs + 2 termination points
158         verify(Operations.op,  times(6)).insert(any(UcastMacsRemote.class));
159         //TODO add finer grained validation
160     }
161
162     @Test
163     public <T extends DataObject> void testUcastMacDelete() throws Exception {
164         addData(CONFIGURATION, LogicalSwitches.class, logicalSwitches);
165         addData(OPERATIONAL, LogicalSwitches.class, logicalSwitches);
166         addData(CONFIGURATION, TerminationPoint.class, terminationPoints);
167         addData(CONFIGURATION, RemoteUcastMacs.class, ucastMacs);
168         addData(OPERATIONAL, RemoteUcastMacs.class, ucastMacs);
169         addData(OPERATIONAL, TerminationPoint.class, terminationPoints);
170
171         resetOperations();
172         deleteData(CONFIGURATION, RemoteUcastMacs.class, ucastMacs);
173         verify(Operations.op,  times(4)).delete(any());
174         //TODO add finer grained validation
175     }
176
177     @Test
178     public <T extends DataObject> void testMcastMacAdd() throws Exception {
179         addData(CONFIGURATION, LogicalSwitches.class, logicalSwitches);
180         addData(OPERATIONAL, LogicalSwitches.class, logicalSwitches);
181         resetOperations();
182         addData(CONFIGURATION, TerminationPoint.class, terminationPoints);
183         addData(CONFIGURATION, RemoteMcastMacs.class, mcastMacs);
184         //2 mcast macs + 2 locator sets + 3 termination points
185         verify(Operations.op,  times(7)).insert(Matchers.<McastMacsRemote>any());
186     }
187
188     @Test
189     public <T extends DataObject> void testMcastMacAddWithoutConfigTep() throws Exception {
190         addData(CONFIGURATION, LogicalSwitches.class, logicalSwitches);
191         addData(OPERATIONAL, LogicalSwitches.class, logicalSwitches);
192         resetOperations();
193         addData(CONFIGURATION, RemoteMcastMacs.class, mcastMacs);
194         //2 mcast macs + 2 locator sets + 3 termination points
195         verify(Operations.op,  times(7)).insert(Matchers.<McastMacsRemote>any());
196     }
197
198     @Test
199     public <T extends DataObject> void testMcastMacDelete() throws Exception {
200         addData(CONFIGURATION, LogicalSwitches.class, logicalSwitches);
201         addData(OPERATIONAL, LogicalSwitches.class, logicalSwitches);
202         addData(CONFIGURATION, TerminationPoint.class, terminationPoints);
203         addData(CONFIGURATION, RemoteMcastMacs.class, mcastMacs);
204         addData(OPERATIONAL, TerminationPoint.class, terminationPoints);
205         addData(OPERATIONAL, RemoteMcastMacs.class, mcastMacs);
206
207         resetOperations();
208         deleteData(CONFIGURATION, RemoteMcastMacs.class, mcastMacs);
209         verify(Operations.op,  times(2)).delete(Matchers.any());
210     }
211
212     @Test
213     public <T extends DataObject> void testAddMacs() throws Exception {
214         Node node = addData(CONFIGURATION, LogicalSwitches.class, logicalSwitches);
215         addData(OPERATIONAL, LogicalSwitches.class, logicalSwitches);
216         resetOperations();
217         addData(CONFIGURATION, TerminationPoint.class, terminationPoints);
218         addData(CONFIGURATION, RemoteUcastMacs.class, ucastMacs);
219         verify(Operations.op,  times(6)).insert(any(UcastMacsRemote.class));
220
221         addData(OPERATIONAL, TerminationPoint.class, terminationPoints);
222         addData(OPERATIONAL, RemoteUcastMacs.class, ucastMacs);
223         resetOperations();
224         addData(CONFIGURATION, RemoteMcastMacs.class, mcastMacs);
225         //2 mcast mac + 2 locator sets ( termination point already added )
226         verify(Operations.op,  times(4)).insert(Matchers.<McastMacsRemote>any());
227     }
228
229     @Test
230     public <T extends DataObject> void testUpdateMacs() throws Exception {
231         Node node = addData(CONFIGURATION, LogicalSwitches.class, logicalSwitches);
232         addData(OPERATIONAL, LogicalSwitches.class, logicalSwitches);
233         resetOperations();
234         addData(CONFIGURATION, TerminationPoint.class, terminationPoints);
235         addData(CONFIGURATION, RemoteUcastMacs.class, ucastMacs);
236         verify(Operations.op,  times(6)).insert(any(UcastMacsRemote.class));
237
238         addData(OPERATIONAL, TerminationPoint.class, terminationPoints);
239         addData(OPERATIONAL, RemoteUcastMacs.class, ucastMacs);
240         resetOperations();
241         addData(CONFIGURATION, RemoteMcastMacs.class, mcastMacs);
242         verify(Operations.op,  times(4)).insert(Matchers.<McastMacsRemote>any());
243         addData(OPERATIONAL, RemoteMcastMacs.class, mcastMacs);
244
245         resetOperations();
246         addData(CONFIGURATION, RemoteMcastMacs.class, mcastMac2);
247         verify(Operations.op,  times(2)).insert(Matchers.<McastMacsRemote>any());
248         verify(Operations.op,  times(2)).update(Matchers.<McastMacsRemote>any());
249         verify(Operations.op,  times(0)).delete(Matchers.any());
250     }
251
252     @Test
253     public <T extends DataObject> void testUpdateMacsWithZeroLocators() throws Exception {
254         Node node = addData(CONFIGURATION, LogicalSwitches.class, logicalSwitches);
255         addData(OPERATIONAL, LogicalSwitches.class, logicalSwitches);
256         resetOperations();
257         addData(CONFIGURATION, TerminationPoint.class, terminationPoints);
258         addData(CONFIGURATION, RemoteUcastMacs.class, ucastMacs);
259         verify(Operations.op,  times(6)).insert(any(UcastMacsRemote.class));
260
261         addData(OPERATIONAL, TerminationPoint.class, terminationPoints);
262         addData(OPERATIONAL, RemoteUcastMacs.class, ucastMacs);
263         resetOperations();
264         addData(CONFIGURATION, RemoteMcastMacs.class, mcastMacs);
265         verify(Operations.op,  times(4)).insert(Matchers.<McastMacsRemote>any());
266         addData(OPERATIONAL, RemoteMcastMacs.class, mcastMacs);
267
268         resetOperations();
269         addData(CONFIGURATION, RemoteMcastMacs.class, mcastMac3WithZeroLocators);
270         verify(Operations.op,  times(2)).delete(Matchers.any());
271     }
272
273     @Test
274     public <T extends DataObject> void testBackToBackMacsUpdate() throws Exception {
275         Node node = addData(CONFIGURATION, LogicalSwitches.class, logicalSwitches);
276         addData(OPERATIONAL, LogicalSwitches.class, logicalSwitches);
277         resetOperations();
278         addData(CONFIGURATION, TerminationPoint.class, terminationPoints);
279         addData(CONFIGURATION, RemoteUcastMacs.class, ucastMacs);
280         verify(Operations.op,  times(6)).insert(any(UcastMacsRemote.class));
281
282         resetOperations();
283         addData(CONFIGURATION, RemoteMcastMacs.class, mcastMacs);
284         //2 mcast mac + 2 locator sets ( termination point already added )
285         verify(Operations.op,  times(0)).insert(Matchers.<McastMacsRemote>any());
286         resetOperations();
287         addData(OPERATIONAL, TerminationPoint.class, terminationPoints);
288         addData(OPERATIONAL, RemoteUcastMacs.class, ucastMacs);
289         connectionInstance.getDeviceInfo().onOperDataAvailable();
290         //2 mcast mac + 2 locator sets ( termination point already added )
291         verify(Operations.op,  times(4)).insert(Matchers.<McastMacsRemote>any());
292
293         resetOperations();
294         addData(CONFIGURATION, RemoteMcastMacs.class, mcastMac2);
295         verify(Operations.op,  times(0)).insert(Matchers.<McastMacsRemote>any());
296         addData(OPERATIONAL, RemoteMcastMacs.class, mcastMacs);
297         connectionInstance.getDeviceInfo().onOperDataAvailable();
298         verify(Operations.op,  times(2)).insert(Matchers.<McastMacsRemote>any());
299         verify(Operations.op,  times(2)).update(Matchers.<McastMacsRemote>any());
300     }
301
302     private void verifyThatLogicalSwitchCreated() {
303         verify(ovsdbClient, times(1)).transact(any(DatabaseSchema.class), any(List.class));
304         verify(Operations.op, times(2)).insert(any(LogicalSwitch.class));
305
306         assertNotNull(insertOpCapture.getAllValues());
307         assertTrue(insertOpCapture.getAllValues().size() == 2);
308
309         List<String> expected = Lists.newArrayList("ls0", "ls1");
310         Iterator<TypedBaseTable> it = insertOpCapture.getAllValues().iterator();
311         while (it.hasNext()) {
312             TypedBaseTable table = it.next();
313             assertTrue(table instanceof LogicalSwitch);
314             LogicalSwitch ls = (LogicalSwitch)table;
315             assertTrue(expected.contains(ls.getName()));
316             expected.remove(ls.getName());
317             it.next();
318         }
319     }
320 }