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.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentationBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalSwitchAttributes;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitchesKey;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteUcastMacs;
66 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
67 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
68 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
69 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
70 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
71 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
72 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
73 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
74 import org.opendaylight.yangtools.yang.binding.DataObject;
75 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
76 import org.powermock.api.mockito.PowerMockito;
77 import org.slf4j.Logger;
78 import org.slf4j.LoggerFactory;
80 public class DataChangeListenerTestBase extends AbstractDataBrokerTest {
82 static Logger LOG = LoggerFactory.getLogger(DataChangeListenerTestBase.class);
84 static DataBroker dataBroker;
86 EntityOwnershipService entityOwnershipService;
87 OvsdbClient ovsdbClient;
88 DatabaseSchema dbSchema;
89 ListenableFuture<DatabaseSchema> listenableDbSchema = mock(ListenableFuture.class);
90 TransactionInvoker transactionInvoker;
91 OvsdbConnectionInfo connectionInfo;
92 Operations operations;
93 HwvtepDataChangeListener hwvtepDataChangeListener;
94 HwvtepConnectionManager hwvtepConnectionManager;
95 HwvtepConnectionInstance connectionInstance;
97 ArgumentCaptor<TypedBaseTable> insertOpCapture;
98 ArgumentCaptor<List> transactCaptor;
101 InstanceIdentifier<Node> nodeIid;
102 InstanceIdentifier<LogicalSwitches> ls0Iid;
103 InstanceIdentifier<LogicalSwitches> ls1Iid;
106 public void setupTest() throws Exception {
108 * Use the same databroker across tests ,otherwise the following exception is thrown
109 * Caused by: java.lang.RuntimeException: org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.
110 * topology.rev131021.node.attributes.SupportingNode$StreamWriter: frozen class (cannot edit)
112 if (dataBroker == null) {
113 dataBroker = super.getDataBroker();
115 entityOwnershipService = mock(EntityOwnershipService.class);
116 nodeUuid = java.util.UUID.randomUUID().toString();
117 nodeIid = createInstanceIdentifier(nodeUuid);
118 ls0Iid = nodeIid.augmentation(HwvtepGlobalAugmentation.class).child(LogicalSwitches.class,
119 new LogicalSwitchesKey(new HwvtepNodeName("ls0")));
120 ls1Iid = nodeIid.augmentation(HwvtepGlobalAugmentation.class).child(LogicalSwitches.class,
121 new LogicalSwitchesKey(new HwvtepNodeName("ls1")));
123 mockConnectionInstance();
124 mockConnectionManager();
127 addNode(OPERATIONAL);
128 addNode(CONFIGURATION);
129 hwvtepDataChangeListener = new HwvtepDataChangeListener(dataBroker, hwvtepConnectionManager);
133 public void tearDown() throws Exception {
134 hwvtepDataChangeListener.close();
135 deleteNode(OPERATIONAL);
136 deleteNode(CONFIGURATION);
139 void setFinalStatic(Class cls, String fieldName, Object newValue) throws Exception {
140 Field[] fields = FieldUtils.getAllFields(cls);
141 for (Field field : fields) {
142 if (fieldName.equals(field.getName())) {
143 field.setAccessible(true);
144 Field modifiersField = Field.class.getDeclaredField("modifiers");
145 modifiersField.setAccessible(true);
146 modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
147 field.set(null, newValue);
154 try (InputStream resourceAsStream = DataChangeListenerTestBase.class.getResourceAsStream(
155 "hwvtep_schema.json")) {
156 ObjectMapper mapper = new ObjectMapper();
157 JsonNode jsonNode = mapper.readTree(resourceAsStream);
158 dbSchema = DatabaseSchema.fromJson(HwvtepSchemaConstants.HARDWARE_VTEP,
159 jsonNode.get("result"));
160 listenableDbSchema = mock(ListenableFuture.class);
161 doReturn(dbSchema).when(listenableDbSchema).get();
162 } catch (IOException | ExecutionException | InterruptedException e) {
163 LOG.error("Failed to load schema", e);
167 private void mockConnectionManager() throws IllegalAccessException {
168 hwvtepConnectionManager = PowerMockito.mock(HwvtepConnectionManager.class, Mockito.CALLS_REAL_METHODS);
169 field(HwvtepConnectionManager.class, "db").set(hwvtepConnectionManager, dataBroker);
170 field(HwvtepConnectionManager.class, "txInvoker").set(hwvtepConnectionManager, transactionInvoker);
171 field(HwvtepConnectionManager.class, "entityOwnershipService").set(hwvtepConnectionManager,
172 entityOwnershipService);
173 suppress(PowerMockito.method(HwvtepConnectionManager.class, "getConnectionInstance",
174 HwvtepPhysicalSwitchAttributes.class));
175 suppress(PowerMockito.method(HwvtepConnectionManager.class, "getConnectionInstanceFromNodeIid",
176 InstanceIdentifier.class));
177 doReturn(connectionInstance).when(
178 hwvtepConnectionManager).getConnectionInstance(Mockito.any(HwvtepPhysicalSwitchAttributes.class));
179 doReturn(connectionInstance).when(
180 hwvtepConnectionManager).getConnectionInstance(Mockito.any(Node.class));
181 doReturn(connectionInstance).when(
182 hwvtepConnectionManager).getConnectionInstanceFromNodeIid(Mockito.any(InstanceIdentifier.class));
185 void mockConnectionInstance() throws IllegalAccessException {
186 connectionInfo = mock(OvsdbConnectionInfo.class);
187 doReturn(mock(InetAddress.class)).when(connectionInfo).getRemoteAddress();
189 ovsdbClient = mock(OvsdbClient.class);
190 doReturn(true).when(ovsdbClient).isActive();
191 doReturn(connectionInfo).when(ovsdbClient).getConnectionInfo();
193 transactionInvoker = new TransactionInvokerImpl(dataBroker);
195 connectionInstance = PowerMockito.mock(HwvtepConnectionInstance.class, Mockito.CALLS_REAL_METHODS);
196 field(HwvtepConnectionInstance.class, "instanceIdentifier").set(connectionInstance, nodeIid);
197 field(HwvtepConnectionInstance.class, "txInvoker").set(connectionInstance, transactionInvoker);
198 field(HwvtepConnectionInstance.class, "client").set(connectionInstance, ovsdbClient);
199 SettableFuture<Boolean> reconciliationFt = SettableFuture.create();
200 reconciliationFt.set(Boolean.TRUE);
201 field(HwvtepConnectionInstance.class, "reconciliationFt").set(connectionInstance, reconciliationFt);
202 field(HwvtepConnectionInstance.class, "firstUpdateTriggered").set(connectionInstance,
203 new AtomicBoolean(Boolean.TRUE));
204 doReturn(nodeIid).when(connectionInstance).getInstanceIdentifier();
205 doReturn(listenableDbSchema).when(connectionInstance).getSchema(anyString());
206 doReturn(dataBroker).when(connectionInstance).getDataBroker();
207 doReturn(nodeIid).when(connectionInstance).getInstanceIdentifier();
208 field(HwvtepConnectionInstance.class, "deviceInfo").set(connectionInstance,
209 new HwvtepDeviceInfo(connectionInstance));
210 connectionInstance.createTransactInvokers();
213 void mockOperations() {
218 * Resets the captures so that we can validate the captors of the immediate next execution.
220 void resetOperations() {
221 insertOpCapture = ArgumentCaptor.forClass(TypedBaseTable.class);
222 Delete delete = mock(Delete.class);
223 Where where = mock(Where.class);
224 doReturn(where).when(delete).where(any());
225 Insert insert = mock(Insert.class);
226 doReturn(insert).when(insert).withId(any(String.class));
227 Operations.op = PowerMockito.mock(Operations.class);
228 doReturn(insert).when(Operations.op).insert(insertOpCapture.capture());
229 Update update = mock(Update.class);
230 doReturn(update).when(Operations.op).update(insertOpCapture.capture());
231 doReturn(where).when(update).where(any());
232 doReturn(delete).when(Operations.op).delete(any());
233 ListenableFuture<List<OperationResult>> ft = mock(ListenableFuture.class);
234 transactCaptor = ArgumentCaptor.forClass(List.class);
235 doReturn(ft).when(ovsdbClient).transact(any(DatabaseSchema.class), transactCaptor.capture());
238 void addNode(LogicalDatastoreType logicalDatastoreType) throws Exception {
239 NodeBuilder nodeBuilder = prepareNode(nodeIid);
240 HwvtepGlobalAugmentationBuilder builder = new HwvtepGlobalAugmentationBuilder();
241 nodeBuilder.addAugmentation(HwvtepGlobalAugmentation.class, builder.build());
242 WriteTransaction transaction = dataBroker.newWriteOnlyTransaction();
243 transaction.put(logicalDatastoreType, nodeIid, nodeBuilder.build(), WriteTransaction.CREATE_MISSING_PARENTS);
244 transaction.submit();
247 void deleteNode(LogicalDatastoreType logicalDatastoreType) {
248 ReadWriteTransaction tx = dataBroker.newReadWriteTransaction();
249 tx.delete(logicalDatastoreType, nodeIid);
253 Node addData(LogicalDatastoreType logicalDatastoreType, Class<? extends DataObject> dataObject,
255 NodeBuilder nodeBuilder = prepareNode(nodeIid);
256 HwvtepGlobalAugmentationBuilder builder = new HwvtepGlobalAugmentationBuilder();
257 if (LogicalSwitches.class == dataObject) {
258 TestBuilders.addLogicalSwitches(builder, data);
260 if (TerminationPoint.class == dataObject) {
261 TestBuilders.addGlobalTerminationPoints(nodeBuilder, nodeIid, data);
263 if (RemoteUcastMacs.class == dataObject) {
264 TestBuilders.addRemoteUcastMacs(nodeIid, builder, data);
266 if (RemoteMcastMacs.class == dataObject) {
267 TestBuilders.addRemoteMcastMacs(nodeIid, builder, data);
269 nodeBuilder.addAugmentation(HwvtepGlobalAugmentation.class, builder.build());
270 return mergeNode(logicalDatastoreType, nodeIid, nodeBuilder);
273 void deleteData(LogicalDatastoreType logicalDatastoreType, Class<? extends DataObject> dataObject,
275 NodeBuilder nodeBuilder = prepareNode(nodeIid);
276 ReadWriteTransaction tx = dataBroker.newReadWriteTransaction();
277 HwvtepGlobalAugmentationBuilder builder = new HwvtepGlobalAugmentationBuilder();
278 if (LogicalSwitches.class == dataObject) {
279 List<LogicalSwitches> logicalSwitches = TestBuilders.addLogicalSwitches(builder, data);
281 for (LogicalSwitches ls : logicalSwitches) {
282 InstanceIdentifier<LogicalSwitches> key =
283 nodeIid.augmentation(HwvtepGlobalAugmentation.class).child(LogicalSwitches.class, ls.getKey());
284 tx.delete(logicalDatastoreType, key);
287 if (TerminationPoint.class == dataObject) {
288 TestBuilders.addGlobalTerminationPoints(nodeBuilder, nodeIid, data);
290 if (RemoteUcastMacs.class == dataObject) {
291 List<RemoteUcastMacs> macs = TestBuilders.addRemoteUcastMacs(nodeIid, builder, data);
292 for (RemoteUcastMacs mac : macs) {
293 InstanceIdentifier<RemoteUcastMacs> key =
294 nodeIid.augmentation(HwvtepGlobalAugmentation.class).child(RemoteUcastMacs.class, mac.getKey());
295 tx.delete(logicalDatastoreType, key);
298 if (RemoteMcastMacs.class == dataObject) {
299 List<RemoteMcastMacs> macs = TestBuilders.addRemoteMcastMacs(nodeIid, builder, data);
300 for (RemoteMcastMacs mac : macs) {
301 InstanceIdentifier<RemoteMcastMacs> key =
302 nodeIid.augmentation(HwvtepGlobalAugmentation.class).child(RemoteMcastMacs.class, mac.getKey());
303 tx.delete(logicalDatastoreType, key);
309 NodeBuilder prepareNode(InstanceIdentifier<Node> iid) {
310 NodeBuilder nodeBuilder = new NodeBuilder();
311 nodeBuilder.setNodeId(iid.firstKeyOf(Node.class).getNodeId());
315 Node mergeNode(LogicalDatastoreType datastoreType, InstanceIdentifier<Node> id, NodeBuilder nodeBuilder) {
316 Node node = nodeBuilder.build();
317 WriteTransaction transaction = dataBroker.newWriteOnlyTransaction();
318 transaction.merge(datastoreType, id, node, WriteTransaction.CREATE_MISSING_PARENTS);
319 transaction.submit();
323 public InstanceIdentifier<Node> createInstanceIdentifier(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)