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 java.io.IOException;
24 import java.io.InputStream;
25 import java.lang.reflect.Field;
26 import java.lang.reflect.Modifier;
27 import java.net.InetAddress;
28 import java.util.List;
29 import java.util.concurrent.ExecutionException;
30 import org.apache.commons.lang3.reflect.FieldUtils;
31 import org.junit.After;
32 import org.junit.Before;
33 import org.mockito.ArgumentCaptor;
34 import org.mockito.Mockito;
35 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
36 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
37 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
38 import org.opendaylight.controller.md.sal.binding.test.AbstractDataBrokerTest;
39 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
40 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
41 import org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md.TransactionInvoker;
42 import org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md.TransactionInvokerImpl;
43 import org.opendaylight.ovsdb.lib.OvsdbClient;
44 import org.opendaylight.ovsdb.lib.OvsdbConnectionInfo;
45 import org.opendaylight.ovsdb.lib.operations.Delete;
46 import org.opendaylight.ovsdb.lib.operations.Insert;
47 import org.opendaylight.ovsdb.lib.operations.OperationResult;
48 import org.opendaylight.ovsdb.lib.operations.Operations;
49 import org.opendaylight.ovsdb.lib.operations.Update;
50 import org.opendaylight.ovsdb.lib.operations.Where;
51 import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
52 import org.opendaylight.ovsdb.lib.schema.typed.TypedBaseTable;
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.powermock.api.mockito.PowerMockito;
73 import org.slf4j.Logger;
74 import org.slf4j.LoggerFactory;
76 public class DataChangeListenerTestBase extends AbstractDataBrokerTest {
78 static Logger LOG = LoggerFactory.getLogger(DataChangeListenerTestBase.class);
80 static DataBroker dataBroker;
82 EntityOwnershipService entityOwnershipService;
83 OvsdbClient ovsdbClient;
84 DatabaseSchema dbSchema;
85 ListenableFuture<DatabaseSchema> listenableDbSchema = mock(ListenableFuture.class);
86 TransactionInvoker transactionInvoker;
87 OvsdbConnectionInfo connectionInfo;
88 Operations operations;
89 HwvtepDataChangeListener hwvtepDataChangeListener;
90 HwvtepConnectionManager hwvtepConnectionManager;
91 HwvtepConnectionInstance connectionInstance;
93 ArgumentCaptor<TypedBaseTable> insertOpCapture;
94 ArgumentCaptor<List> transactCaptor;
97 InstanceIdentifier<Node> nodeIid;
98 InstanceIdentifier<LogicalSwitches> ls0Iid;
99 InstanceIdentifier<LogicalSwitches> ls1Iid;
102 public void setupTest() throws Exception {
104 * Use the same databroker across tests ,otherwise the following exception is thrown
105 * Caused by: java.lang.RuntimeException: org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.
106 * topology.rev131021.node.attributes.SupportingNode$StreamWriter: frozen class (cannot edit)
108 if (dataBroker == null) {
109 dataBroker = super.getDataBroker();
111 entityOwnershipService = mock(EntityOwnershipService.class);
112 nodeUuid = java.util.UUID.randomUUID().toString();
113 nodeIid = createInstanceIdentifier(nodeUuid);
114 ls0Iid = nodeIid.augmentation(HwvtepGlobalAugmentation.class).child(LogicalSwitches.class,
115 new LogicalSwitchesKey(new HwvtepNodeName("ls0")));
116 ls1Iid = nodeIid.augmentation(HwvtepGlobalAugmentation.class).child(LogicalSwitches.class,
117 new LogicalSwitchesKey(new HwvtepNodeName("ls1")));
119 mockConnectionInstance();
120 mockConnectionManager();
123 addNode(OPERATIONAL);
124 addNode(CONFIGURATION);
125 hwvtepDataChangeListener = new HwvtepDataChangeListener(dataBroker, hwvtepConnectionManager);
129 public void tearDown() throws Exception {
130 hwvtepDataChangeListener.close();
131 deleteNode(OPERATIONAL);
132 deleteNode(CONFIGURATION);
135 void setFinalStatic(Class cls, String fieldName, Object newValue) throws Exception {
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);
150 try (InputStream resourceAsStream = DataChangeListenerTestBase.class.getResourceAsStream(
151 "hwvtep_schema.json")) {
152 ObjectMapper mapper = new ObjectMapper();
153 JsonNode jsonNode = mapper.readTree(resourceAsStream);
154 dbSchema = 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);
163 private void mockConnectionManager() throws IllegalAccessException {
164 hwvtepConnectionManager = PowerMockito.mock(HwvtepConnectionManager.class, Mockito.CALLS_REAL_METHODS);
165 field(HwvtepConnectionManager.class, "db").set(hwvtepConnectionManager, dataBroker);
166 field(HwvtepConnectionManager.class, "txInvoker").set(hwvtepConnectionManager, transactionInvoker);
167 field(HwvtepConnectionManager.class, "entityOwnershipService").set(hwvtepConnectionManager,
168 entityOwnershipService);
169 suppress(PowerMockito.method(HwvtepConnectionManager.class, "getConnectionInstance",
170 HwvtepPhysicalSwitchAttributes.class));
171 suppress(PowerMockito.method(HwvtepConnectionManager.class, "getConnectionInstanceFromNodeIid",
172 InstanceIdentifier.class));
173 doReturn(connectionInstance).when(
174 hwvtepConnectionManager).getConnectionInstance(Mockito.any(HwvtepPhysicalSwitchAttributes.class));
175 doReturn(connectionInstance).when(
176 hwvtepConnectionManager).getConnectionInstance(Mockito.any(Node.class));
177 doReturn(connectionInstance).when(
178 hwvtepConnectionManager).getConnectionInstanceFromNodeIid(Mockito.any(InstanceIdentifier.class));
181 void mockConnectionInstance() throws IllegalAccessException {
182 connectionInfo = mock(OvsdbConnectionInfo.class);
183 doReturn(mock(InetAddress.class)).when(connectionInfo).getRemoteAddress();
185 ovsdbClient = mock(OvsdbClient.class);
186 doReturn(true).when(ovsdbClient).isActive();
187 doReturn(connectionInfo).when(ovsdbClient).getConnectionInfo();
189 transactionInvoker = new TransactionInvokerImpl(dataBroker);
191 connectionInstance = PowerMockito.mock(HwvtepConnectionInstance.class, Mockito.CALLS_REAL_METHODS);
192 field(HwvtepConnectionInstance.class, "instanceIdentifier").set(connectionInstance, nodeIid);
193 field(HwvtepConnectionInstance.class, "txInvoker").set(connectionInstance, transactionInvoker);
194 field(HwvtepConnectionInstance.class, "client").set(connectionInstance, ovsdbClient);
195 doReturn(nodeIid).when(connectionInstance).getInstanceIdentifier();
196 doReturn(listenableDbSchema).when(connectionInstance).getSchema(anyString());
197 doReturn(dataBroker).when(connectionInstance).getDataBroker();
198 doReturn(nodeIid).when(connectionInstance).getInstanceIdentifier();
199 field(HwvtepConnectionInstance.class, "deviceInfo").set(connectionInstance,
200 new HwvtepDeviceInfo(connectionInstance));
201 connectionInstance.createTransactInvokers();
204 void mockOperations() {
209 * Resets the captures so that we can validate the captors of the immediate next execution.
211 void resetOperations() {
212 insertOpCapture = ArgumentCaptor.forClass(TypedBaseTable.class);
213 Delete delete = mock(Delete.class);
214 Where where = mock(Where.class);
215 doReturn(where).when(delete).where(any());
216 Insert insert = mock(Insert.class);
217 doReturn(insert).when(insert).withId(any(String.class));
218 Operations.op = PowerMockito.mock(Operations.class);
219 doReturn(insert).when(Operations.op).insert(insertOpCapture.capture());
220 Update update = mock(Update.class);
221 doReturn(update).when(Operations.op).update(insertOpCapture.capture());
222 doReturn(where).when(update).where(any());
223 doReturn(delete).when(Operations.op).delete(any());
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());
229 void addNode(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.put(logicalDatastoreType, nodeIid, nodeBuilder.build(), WriteTransaction.CREATE_MISSING_PARENTS);
235 transaction.submit();
238 void deleteNode(LogicalDatastoreType logicalDatastoreType) {
239 ReadWriteTransaction tx = dataBroker.newReadWriteTransaction();
240 tx.delete(logicalDatastoreType, nodeIid);
244 Node addData(LogicalDatastoreType logicalDatastoreType, Class<? extends DataObject> dataObject,
246 NodeBuilder nodeBuilder = prepareNode(nodeIid);
247 HwvtepGlobalAugmentationBuilder builder = new HwvtepGlobalAugmentationBuilder();
248 if (LogicalSwitches.class == dataObject) {
249 TestBuilders.addLogicalSwitches(builder, data);
251 if (TerminationPoint.class == dataObject) {
252 TestBuilders.addGlobalTerminationPoints(nodeBuilder, nodeIid, data);
254 if (RemoteUcastMacs.class == dataObject) {
255 TestBuilders.addRemoteUcastMacs(nodeIid, builder, data);
257 if (RemoteMcastMacs.class == dataObject) {
258 TestBuilders.addRemoteMcastMacs(nodeIid, builder, data);
260 nodeBuilder.addAugmentation(HwvtepGlobalAugmentation.class, builder.build());
261 return mergeNode(logicalDatastoreType, nodeIid, nodeBuilder);
264 void deleteData(LogicalDatastoreType logicalDatastoreType, Class<? extends DataObject> dataObject,
266 NodeBuilder nodeBuilder = prepareNode(nodeIid);
267 ReadWriteTransaction tx = dataBroker.newReadWriteTransaction();
268 HwvtepGlobalAugmentationBuilder builder = new HwvtepGlobalAugmentationBuilder();
269 if (LogicalSwitches.class == dataObject) {
270 List<LogicalSwitches> logicalSwitches = TestBuilders.addLogicalSwitches(builder, data);
272 for (LogicalSwitches ls : logicalSwitches) {
273 InstanceIdentifier<LogicalSwitches> key =
274 nodeIid.augmentation(HwvtepGlobalAugmentation.class).child(LogicalSwitches.class, ls.getKey());
275 tx.delete(logicalDatastoreType, key);
278 if (TerminationPoint.class == dataObject) {
279 TestBuilders.addGlobalTerminationPoints(nodeBuilder, nodeIid, data);
281 if (RemoteUcastMacs.class == dataObject) {
282 List<RemoteUcastMacs> macs = TestBuilders.addRemoteUcastMacs(nodeIid, builder, data);
283 for (RemoteUcastMacs mac : macs) {
284 InstanceIdentifier<RemoteUcastMacs> key =
285 nodeIid.augmentation(HwvtepGlobalAugmentation.class).child(RemoteUcastMacs.class, mac.getKey());
286 tx.delete(logicalDatastoreType, key);
289 if (RemoteMcastMacs.class == dataObject) {
290 List<RemoteMcastMacs> macs = TestBuilders.addRemoteMcastMacs(nodeIid, builder, data);
291 for (RemoteMcastMacs mac : macs) {
292 InstanceIdentifier<RemoteMcastMacs> key =
293 nodeIid.augmentation(HwvtepGlobalAugmentation.class).child(RemoteMcastMacs.class, mac.getKey());
294 tx.delete(logicalDatastoreType, key);
300 NodeBuilder prepareNode(InstanceIdentifier<Node> iid) {
301 NodeBuilder nodeBuilder = new NodeBuilder();
302 nodeBuilder.setNodeId(iid.firstKeyOf(Node.class).getNodeId());
306 Node mergeNode(LogicalDatastoreType datastoreType, InstanceIdentifier<Node> id, NodeBuilder nodeBuilder) {
307 Node node = nodeBuilder.build();
308 WriteTransaction transaction = dataBroker.newWriteOnlyTransaction();
309 transaction.merge(datastoreType, id, node, WriteTransaction.CREATE_MISSING_PARENTS);
310 transaction.submit();
314 public InstanceIdentifier<Node> createInstanceIdentifier(String nodeIdString) {
315 NodeId nodeId = new NodeId(new Uri(nodeIdString));
316 NodeKey nodeKey = new NodeKey(nodeId);
317 TopologyKey topoKey = new TopologyKey(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID);
318 return InstanceIdentifier.builder(NetworkTopology.class)
319 .child(Topology.class, topoKey)
320 .child(Node.class, nodeKey)