2 * Copyright (c) 2016, 2017 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
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
9 package org.opendaylight.ovsdb.hwvtepsouthbound;
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;
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;
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;
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;
81 public class DataChangeListenerTestBase extends AbstractDataBrokerTest {
83 static Logger LOG = LoggerFactory.getLogger(DataChangeListenerTestBase.class);
85 static DataBroker dataBroker;
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;
98 ArgumentCaptor<TypedBaseTable> insertOpCapture;
99 ArgumentCaptor<List> transactCaptor;
102 InstanceIdentifier<Node> nodeIid;
103 InstanceIdentifier<LogicalSwitches> ls0Iid;
104 InstanceIdentifier<LogicalSwitches> ls1Iid;
107 public void setupTest() throws Exception {
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)
113 if (dataBroker == null) {
114 dataBroker = super.getDataBroker();
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")));
124 mockConnectionInstance();
125 mockConnectionManager();
128 addNode(OPERATIONAL);
129 addNode(CONFIGURATION);
130 hwvtepDataChangeListener = new HwvtepDataChangeListener(dataBroker, hwvtepConnectionManager);
134 public void tearDown() throws Exception {
135 hwvtepDataChangeListener.close();
136 deleteNode(OPERATIONAL);
137 deleteNode(CONFIGURATION);
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);
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);
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));
186 void mockConnectionInstance() throws IllegalAccessException {
187 connectionInfo = mock(OvsdbConnectionInfo.class);
188 doReturn(mock(InetAddress.class)).when(connectionInfo).getRemoteAddress();
190 ovsdbClient = mock(OvsdbClient.class);
191 doReturn(true).when(ovsdbClient).isActive();
192 doReturn(connectionInfo).when(ovsdbClient).getConnectionInfo();
194 transactionInvoker = new TransactionInvokerImpl(dataBroker);
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();
216 void mockOperations() {
221 * Resets the captures so that we can validate the captors of the immediate next execution.
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());
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();
250 void deleteNode(LogicalDatastoreType logicalDatastoreType) {
251 ReadWriteTransaction tx = dataBroker.newReadWriteTransaction();
252 tx.delete(logicalDatastoreType, nodeIid);
256 Node addData(LogicalDatastoreType logicalDatastoreType, Class<? extends DataObject> dataObject,
258 NodeBuilder nodeBuilder = prepareNode(nodeIid);
259 HwvtepGlobalAugmentationBuilder builder = new HwvtepGlobalAugmentationBuilder();
260 if (LogicalSwitches.class == dataObject) {
261 TestBuilders.addLogicalSwitches(builder, data);
263 if (TerminationPoint.class == dataObject) {
264 TestBuilders.addGlobalTerminationPoints(nodeBuilder, nodeIid, data);
266 if (RemoteUcastMacs.class == dataObject) {
267 TestBuilders.addRemoteUcastMacs(nodeIid, builder, data);
269 if (RemoteMcastMacs.class == dataObject) {
270 TestBuilders.addRemoteMcastMacs(nodeIid, builder, data);
272 nodeBuilder.addAugmentation(HwvtepGlobalAugmentation.class, builder.build());
273 return mergeNode(logicalDatastoreType, nodeIid, nodeBuilder);
276 void deleteData(LogicalDatastoreType logicalDatastoreType, Class<? extends DataObject> dataObject,
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);
284 for (LogicalSwitches ls : logicalSwitches) {
285 InstanceIdentifier<LogicalSwitches> key =
286 nodeIid.augmentation(HwvtepGlobalAugmentation.class).child(LogicalSwitches.class, ls.getKey());
287 tx.delete(logicalDatastoreType, key);
290 if (TerminationPoint.class == dataObject) {
291 TestBuilders.addGlobalTerminationPoints(nodeBuilder, nodeIid, data);
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);
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);
312 NodeBuilder prepareNode(InstanceIdentifier<Node> iid) {
313 NodeBuilder nodeBuilder = new NodeBuilder();
314 nodeBuilder.setNodeId(iid.firstKeyOf(Node.class).getNodeId());
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();
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)