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