fix unit tests which fail intermittently
[ovsdb.git] / hwvtepsouthbound / hwvtepsouthbound-impl / src / test / java / org / opendaylight / ovsdb / hwvtepsouthbound / DataChangeListenerTestBase.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.fasterxml.jackson.databind.JsonNode;
12 import com.fasterxml.jackson.databind.ObjectMapper;
13 import com.google.common.util.concurrent.ListenableFuture;
14 import org.apache.commons.lang3.reflect.FieldUtils;
15 import org.junit.After;
16 import org.junit.Before;
17 import org.mockito.ArgumentCaptor;
18 import org.mockito.Mockito;
19 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
20 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
21 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
22 import org.opendaylight.controller.md.sal.binding.test.AbstractDataBrokerTest;
23 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
24 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
25 import org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md.TransactionInvoker;
26 import org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md.TransactionInvokerImpl;
27 import org.opendaylight.ovsdb.lib.OvsdbClient;
28 import org.opendaylight.ovsdb.lib.OvsdbConnectionInfo;
29 import org.opendaylight.ovsdb.lib.operations.Delete;
30 import org.opendaylight.ovsdb.lib.operations.Insert;
31 import org.opendaylight.ovsdb.lib.operations.OperationResult;
32 import org.opendaylight.ovsdb.lib.operations.Operations;
33 import org.opendaylight.ovsdb.lib.operations.Update;
34 import org.opendaylight.ovsdb.lib.operations.Where;
35 import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
36 import org.opendaylight.ovsdb.lib.schema.typed.TypedBaseTable;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentationBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalSwitchAttributes;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitchesKey;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteUcastMacs;
46 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
47 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
48 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
49 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
50 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
51 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
52 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
53 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
54 import org.opendaylight.yangtools.yang.binding.DataObject;
55 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
56 import org.powermock.api.mockito.PowerMockito;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
59
60 import java.io.InputStream;
61 import java.lang.reflect.Field;
62 import java.lang.reflect.Modifier;
63 import java.net.InetAddress;
64 import java.util.List;
65
66 import static org.mockito.Matchers.any;
67 import static org.mockito.Matchers.anyString;
68 import static org.mockito.Mockito.doReturn;
69 import static org.mockito.Mockito.mock;
70 import static org.mockito.Mockito.when;
71 import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.CONFIGURATION;
72 import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.OPERATIONAL;
73 import static org.powermock.api.support.membermodification.MemberMatcher.field;
74 import static org.powermock.api.support.membermodification.MemberModifier.suppress;
75
76 public class DataChangeListenerTestBase extends AbstractDataBrokerTest {
77
78     static Logger LOG = LoggerFactory.getLogger(DataChangeListenerTestBase.class);
79
80     static DataBroker dataBroker;
81
82     EntityOwnershipService entityOwnershipService;
83     OvsdbClient ovsdbClient;
84     DatabaseSchema dbSchema;
85     ListenableFuture<DatabaseSchema> listenableDbSchema = mock(ListenableFuture.class);
86     TransactionInvoker transactionInvoker;
87     OvsdbConnectionInfo connectionInfo;
88     Operations operations;
89     HwvtepDataChangeListener hwvtepDataChangeListener;
90     HwvtepConnectionManager hwvtepConnectionManager;
91     HwvtepConnectionInstance connectionInstance;
92
93     ArgumentCaptor<TypedBaseTable> insertOpCapture;
94     ArgumentCaptor<List> transactCaptor;
95
96     String nodeUuid;
97     InstanceIdentifier<Node> nodeIid;
98     InstanceIdentifier<LogicalSwitches> ls0Iid;
99     InstanceIdentifier<LogicalSwitches> ls1Iid;
100
101     @Before
102     public void setupTest() throws Exception {
103         /**
104          *  Use the same databroker across tests ,otherwise the following exception is thrown
105          *  Caused by: java.lang.RuntimeException: org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.
106          *  topology.rev131021.node.attributes.SupportingNode$StreamWriter: frozen class (cannot edit)
107          */
108         if (dataBroker == null) {
109             dataBroker = super.getDataBroker();
110         }
111         entityOwnershipService = mock(EntityOwnershipService.class);
112         nodeUuid = java.util.UUID.randomUUID().toString();
113         nodeIid = createInstanceIdentifier(nodeUuid);
114         ls0Iid = nodeIid.augmentation(HwvtepGlobalAugmentation.class).
115                 child(LogicalSwitches.class, new LogicalSwitchesKey(new HwvtepNodeName("ls0")));
116         ls1Iid = nodeIid.augmentation(HwvtepGlobalAugmentation.class).
117                 child(LogicalSwitches.class, new LogicalSwitchesKey(new HwvtepNodeName("ls1")));
118         loadSchema();
119         mockConnectionInstance();
120         mockConnectionManager();
121         mockOperations();
122
123         addNode(OPERATIONAL);
124         addNode(CONFIGURATION);
125         hwvtepDataChangeListener = new HwvtepDataChangeListener(dataBroker, hwvtepConnectionManager);
126     }
127
128     @After
129     public void tearDown() throws Exception {
130         hwvtepDataChangeListener.close();
131         deleteNode(OPERATIONAL);
132         deleteNode(CONFIGURATION);
133     }
134
135     void setFinalStatic(Class cls, String fieldName, Object newValue) throws Exception {
136         Field fields[] = FieldUtils.getAllFields(cls);
137         for (Field field : fields) {
138             if (fieldName.equals(field.getName())) {
139                 field.setAccessible(true);
140                 Field modifiersField = Field.class.getDeclaredField("modifiers");
141                 modifiersField.setAccessible(true);
142                 modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
143                 field.set(null, newValue);
144                 break;
145             }
146         }
147     }
148
149     void loadSchema() {
150         try (InputStream resourceAsStream = DataChangeListenerTestBase.class.getResourceAsStream("hwvtep_schema.json")) {
151             ObjectMapper mapper = new ObjectMapper();
152             JsonNode jsonNode = mapper.readTree(resourceAsStream);
153             dbSchema = DatabaseSchema.fromJson(HwvtepSchemaConstants.HARDWARE_VTEP,
154                     jsonNode.get("result"));
155             listenableDbSchema = mock(ListenableFuture.class);
156             doReturn(dbSchema).when(listenableDbSchema).get();
157         } catch (Exception e) {
158             LOG.error("Failed to load schema", e);
159         }
160     }
161
162     private void mockConnectionManager() throws IllegalAccessException {
163         hwvtepConnectionManager = PowerMockito.mock(HwvtepConnectionManager.class, Mockito.CALLS_REAL_METHODS);
164         field(HwvtepConnectionManager.class, "db").set(hwvtepConnectionManager, dataBroker);
165         field(HwvtepConnectionManager.class, "txInvoker").set(hwvtepConnectionManager, transactionInvoker);
166         field(HwvtepConnectionManager.class, "entityOwnershipService").set(hwvtepConnectionManager, entityOwnershipService);
167         suppress(PowerMockito.method(HwvtepConnectionManager.class, "getConnectionInstance", HwvtepPhysicalSwitchAttributes.class));
168         suppress(PowerMockito.method(HwvtepConnectionManager.class, "getConnectionInstanceFromNodeIid",
169                 InstanceIdentifier.class));
170         doReturn(connectionInstance).when(
171                 hwvtepConnectionManager).getConnectionInstance(Mockito.any(HwvtepPhysicalSwitchAttributes.class));
172         doReturn(connectionInstance).when(
173                 hwvtepConnectionManager).getConnectionInstance(Mockito.any(Node.class));
174         doReturn(connectionInstance).when(
175                 hwvtepConnectionManager).getConnectionInstanceFromNodeIid(Mockito.any(InstanceIdentifier.class));
176     }
177
178     void mockConnectionInstance() throws IllegalAccessException {
179         connectionInfo = mock(OvsdbConnectionInfo.class);
180         doReturn(mock(InetAddress.class)).when(connectionInfo).getRemoteAddress();
181
182         ovsdbClient = mock(OvsdbClient.class);
183         doReturn(true).when(ovsdbClient).isActive();
184         doReturn(connectionInfo).when(ovsdbClient).getConnectionInfo();
185
186         transactionInvoker =  new TransactionInvokerImpl(dataBroker);
187
188         connectionInstance = PowerMockito.mock(HwvtepConnectionInstance.class, Mockito.CALLS_REAL_METHODS);
189         field(HwvtepConnectionInstance.class, "instanceIdentifier").set(connectionInstance, nodeIid);
190         field(HwvtepConnectionInstance.class, "txInvoker").set(connectionInstance, transactionInvoker);
191         field(HwvtepConnectionInstance.class, "client").set(connectionInstance, ovsdbClient);
192         doReturn(nodeIid).when(connectionInstance).getInstanceIdentifier();
193         doReturn(listenableDbSchema).when(connectionInstance).getSchema(anyString());
194         doReturn(dataBroker).when(connectionInstance).getDataBroker();
195         doReturn(nodeIid).when(connectionInstance).getInstanceIdentifier();
196         field(HwvtepConnectionInstance.class, "deviceInfo").set(connectionInstance, new HwvtepDeviceInfo(connectionInstance));
197         connectionInstance.createTransactInvokers();
198     }
199
200     void mockOperations() {
201         resetOperations();
202     }
203
204     /**
205      * resets the captures so that we can validate the captors of the immediate next execution
206      */
207     void resetOperations() {
208         insertOpCapture = ArgumentCaptor.forClass(TypedBaseTable.class);
209         Update update = mock(Update.class);
210         Insert insert = mock(Insert.class);
211         Delete delete = mock(Delete.class);
212         Where where = mock(Where.class);
213         doReturn(where).when(delete).where(any());
214         doReturn(insert).when(insert).withId(any(String.class));
215         Operations.op = PowerMockito.mock(Operations.class);
216         doReturn(insert).when(Operations.op).insert(insertOpCapture.capture());
217         doReturn(update).when(Operations.op).update(insertOpCapture.capture());
218         doReturn(where).when(update).where(any());
219         doReturn(delete).when(Operations.op).delete(any());
220         ListenableFuture<List<OperationResult>> ft = mock(ListenableFuture.class);
221         transactCaptor = ArgumentCaptor.forClass(List.class);
222         doReturn(ft).when(ovsdbClient).transact(any(DatabaseSchema.class), transactCaptor.capture());
223     }
224
225     void addNode(LogicalDatastoreType logicalDatastoreType) throws Exception {
226         NodeBuilder nodeBuilder = prepareNode(nodeIid);
227         HwvtepGlobalAugmentationBuilder builder = new HwvtepGlobalAugmentationBuilder();
228         nodeBuilder.addAugmentation(HwvtepGlobalAugmentation.class, builder.build());
229         WriteTransaction transaction = dataBroker.newWriteOnlyTransaction();
230         transaction.put(logicalDatastoreType, nodeIid, nodeBuilder.build(), WriteTransaction.CREATE_MISSING_PARENTS);
231         transaction.submit();
232     }
233
234     void deleteNode(LogicalDatastoreType logicalDatastoreType) {
235         ReadWriteTransaction tx = dataBroker.newReadWriteTransaction();
236         tx.delete(logicalDatastoreType, nodeIid);
237         tx.submit();
238     }
239
240     Node addData(LogicalDatastoreType logicalDatastoreType, Class<? extends DataObject> dataObject,
241                  String[]... data) {
242         NodeBuilder nodeBuilder = prepareNode(nodeIid);
243         HwvtepGlobalAugmentationBuilder builder = new HwvtepGlobalAugmentationBuilder();
244         if (LogicalSwitches.class == dataObject) {
245             TestBuilders.addLogicalSwitches(builder, data);
246         }
247         if (TerminationPoint.class == dataObject) {
248             TestBuilders.addGlobalTerminationPoints(nodeBuilder, nodeIid, data);
249         }
250         if (RemoteUcastMacs.class == dataObject) {
251             TestBuilders.addRemoteUcastMacs(nodeIid, builder, data);
252         }
253         if (RemoteMcastMacs.class == dataObject) {
254             TestBuilders.addRemoteMcastMacs(nodeIid, builder, data);
255         }
256         nodeBuilder.addAugmentation(HwvtepGlobalAugmentation.class, builder.build());
257         return mergeNode(logicalDatastoreType, nodeIid, nodeBuilder);
258     }
259
260     void deleteData(LogicalDatastoreType logicalDatastoreType, Class<? extends DataObject> dataObject,
261                  String[]... data) {
262         NodeBuilder nodeBuilder = prepareNode(nodeIid);
263         ReadWriteTransaction tx = dataBroker.newReadWriteTransaction();
264         HwvtepGlobalAugmentationBuilder builder = new HwvtepGlobalAugmentationBuilder();
265         if (LogicalSwitches.class == dataObject) {
266             List<LogicalSwitches> logicalSwitches = TestBuilders.addLogicalSwitches(builder, data);
267
268             for (LogicalSwitches ls : logicalSwitches) {
269                 InstanceIdentifier<LogicalSwitches> key = nodeIid.augmentation(HwvtepGlobalAugmentation.class).
270                         child(LogicalSwitches.class, ls.getKey());
271                 tx.delete(logicalDatastoreType, key);
272             }
273         }
274         if (TerminationPoint.class == dataObject) {
275             TestBuilders.addGlobalTerminationPoints(nodeBuilder, nodeIid, data);
276         }
277         if (RemoteUcastMacs.class == dataObject) {
278             List<RemoteUcastMacs> macs = TestBuilders.addRemoteUcastMacs(nodeIid, builder, data);
279             for (RemoteUcastMacs mac : macs) {
280                 InstanceIdentifier<RemoteUcastMacs> key = nodeIid.augmentation(HwvtepGlobalAugmentation.class).
281                         child(RemoteUcastMacs.class, mac.getKey());
282                 tx.delete(logicalDatastoreType, key);
283             }
284         }
285         if (RemoteMcastMacs.class == dataObject) {
286             List<RemoteMcastMacs> macs = TestBuilders.addRemoteMcastMacs(nodeIid, builder, data);
287             for (RemoteMcastMacs mac : macs) {
288                 InstanceIdentifier<RemoteMcastMacs> key = nodeIid.augmentation(HwvtepGlobalAugmentation.class).
289                         child(RemoteMcastMacs.class, mac.getKey());
290                 tx.delete(logicalDatastoreType, key);
291             }
292         }
293         tx.submit();
294     }
295
296     NodeBuilder prepareNode(InstanceIdentifier<Node> iid) {
297         NodeBuilder nodeBuilder = new NodeBuilder();
298         nodeBuilder.setNodeId(iid.firstKeyOf(Node.class).getNodeId());
299         return nodeBuilder;
300     }
301
302     Node mergeNode(LogicalDatastoreType datastoreType, InstanceIdentifier<Node> id, NodeBuilder nodeBuilder) {
303         Node node = nodeBuilder.build();
304         WriteTransaction transaction = dataBroker.newWriteOnlyTransaction();
305         transaction.merge(datastoreType, id, node, WriteTransaction.CREATE_MISSING_PARENTS);
306         transaction.submit();
307         return node;
308     }
309
310     public InstanceIdentifier<Node> createInstanceIdentifier(String nodeIdString) {
311         NodeId nodeId = new NodeId(new Uri(nodeIdString));
312         NodeKey nodeKey = new NodeKey(nodeId);
313         TopologyKey topoKey = new TopologyKey(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID);
314         return InstanceIdentifier.builder(NetworkTopology.class)
315                 .child(Topology.class, topoKey)
316                 .child(Node.class, nodeKey)
317                 .build();
318     }
319 }