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