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