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
8 package org.opendaylight.ovsdb.hwvtepsouthbound;
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;
16 import com.fasterxml.jackson.databind.JsonNode;
17 import com.fasterxml.jackson.databind.ObjectMapper;
18 import com.google.common.util.concurrent.ListenableFuture;
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.lang.reflect.Field;
22 import java.lang.reflect.Modifier;
23 import java.net.InetAddress;
24 import java.util.List;
25 import java.util.concurrent.ExecutionException;
26 import org.apache.commons.lang3.reflect.FieldUtils;
27 import org.junit.After;
28 import org.junit.Before;
29 import org.mockito.ArgumentCaptor;
30 import org.opendaylight.mdsal.binding.api.DataBroker;
31 import org.opendaylight.mdsal.binding.api.ReadWriteTransaction;
32 import org.opendaylight.mdsal.binding.api.WriteTransaction;
33 import org.opendaylight.mdsal.binding.dom.adapter.test.AbstractDataBrokerTest;
34 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
35 import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipService;
36 import org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md.TransactionInvoker;
37 import org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md.TransactionInvokerImpl;
38 import org.opendaylight.ovsdb.lib.OvsdbClient;
39 import org.opendaylight.ovsdb.lib.OvsdbConnection;
40 import org.opendaylight.ovsdb.lib.OvsdbConnectionInfo;
41 import org.opendaylight.ovsdb.lib.operations.Delete;
42 import org.opendaylight.ovsdb.lib.operations.Insert;
43 import org.opendaylight.ovsdb.lib.operations.OperationResult;
44 import org.opendaylight.ovsdb.lib.operations.Operations;
45 import org.opendaylight.ovsdb.lib.operations.Select;
46 import org.opendaylight.ovsdb.lib.operations.Update;
47 import org.opendaylight.ovsdb.lib.operations.Where;
48 import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
49 import org.opendaylight.ovsdb.lib.schema.GenericTableSchema;
50 import org.opendaylight.ovsdb.lib.schema.typed.TypedBaseTable;
51 import org.opendaylight.ovsdb.lib.schema.typed.TypedDatabaseSchema;
52 import org.opendaylight.ovsdb.utils.mdsal.utils.TransactionHistory;
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.RemoteMcastMacsKey;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteUcastMacs;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteUcastMacsKey;
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;
77 public class DataChangeListenerTestBase extends AbstractDataBrokerTest {
79 static Logger LOG = LoggerFactory.getLogger(DataChangeListenerTestBase.class);
81 static DataBroker dataBroker;
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;
94 ArgumentCaptor<TypedBaseTable> insertOpCapture;
95 ArgumentCaptor<List> transactCaptor;
98 InstanceIdentifier<Node> nodeIid;
99 InstanceIdentifier<LogicalSwitches> ls0Iid;
100 InstanceIdentifier<LogicalSwitches> ls1Iid;
103 public void setupTest() throws Exception {
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)
109 if (dataBroker == null) {
110 dataBroker = super.getDataBroker();
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")));
120 mockConnectionInstance();
121 mockConnectionManager();
124 addNode(LogicalDatastoreType.OPERATIONAL);
125 addNode(LogicalDatastoreType.CONFIGURATION);
126 hwvtepDataChangeListener = new HwvtepDataChangeListener(dataBroker, hwvtepConnectionManager);
130 public void tearDown() throws Exception {
131 hwvtepDataChangeListener.close();
132 deleteNode(LogicalDatastoreType.OPERATIONAL);
133 deleteNode(LogicalDatastoreType.CONFIGURATION);
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);
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);
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));
175 void mockConnectionInstance() throws IllegalAccessException {
176 connectionInfo = mock(OvsdbConnectionInfo.class);
177 doReturn(mock(InetAddress.class)).when(connectionInfo).getRemoteAddress();
179 ovsdbClient = mock(OvsdbClient.class);
180 doReturn(true).when(ovsdbClient).isActive();
181 doReturn(connectionInfo).when(ovsdbClient).getConnectionInfo();
182 doReturn(listenableDbSchema).when(ovsdbClient).getSchema(anyString());
184 transactionInvoker = new TransactionInvokerImpl(dataBroker);
186 connectionInstance = new HwvtepConnectionInstance(null, null, ovsdbClient, nodeIid, transactionInvoker,
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();
195 void mockOperations() {
200 * Resets the captures so that we can validate the captors of the immediate next execution.
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());
221 setFinalStatic(Operations.class, "op", mockOp);
222 } catch (SecurityException | ReflectiveOperationException e) {
223 throw new AssertionError("Set of Operations.op field failed", e);
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());
231 void addNode(final LogicalDatastoreType logicalDatastoreType) throws Exception {
232 NodeBuilder nodeBuilder = prepareNode(nodeIid).addAugmentation(new HwvtepGlobalAugmentationBuilder().build());
233 WriteTransaction transaction = dataBroker.newWriteOnlyTransaction();
234 transaction.mergeParentStructurePut(logicalDatastoreType, nodeIid, nodeBuilder.build());
235 transaction.commit();
238 void deleteNode(final LogicalDatastoreType logicalDatastoreType) {
239 ReadWriteTransaction tx = dataBroker.newReadWriteTransaction();
240 tx.delete(logicalDatastoreType, nodeIid);
244 Node addData(final LogicalDatastoreType logicalDatastoreType, final Class<? extends DataObject> dataObject,
245 final String[]... data) {
246 NodeBuilder nodeBuilder = prepareNode(nodeIid);
247 HwvtepGlobalAugmentationBuilder builder = new HwvtepGlobalAugmentationBuilder();
248 if (LogicalSwitches.class == dataObject) {
249 builder.setLogicalSwitches(TestBuilders.logicalSwitches(data));
251 if (TerminationPoint.class == dataObject) {
252 nodeBuilder.setTerminationPoint(TestBuilders.globalTerminationPoints(nodeIid, data));
254 if (RemoteUcastMacs.class == dataObject) {
255 builder.setRemoteUcastMacs(TestBuilders.remoteUcastMacs(nodeIid, data));
257 if (RemoteMcastMacs.class == dataObject) {
258 builder.setRemoteMcastMacs(TestBuilders.remoteMcastMacs(nodeIid, data));
260 nodeBuilder.addAugmentation(builder.build());
261 return mergeNode(logicalDatastoreType, nodeIid, nodeBuilder);
264 void deleteData(final LogicalDatastoreType datastoreType, InstanceIdentifier<?>... iids) {
265 WriteTransaction transaction = dataBroker.newWriteOnlyTransaction();
266 for (InstanceIdentifier<?> id : iids) {
267 transaction.delete(datastoreType, id);
269 transaction.commit();
272 void deleteData(final LogicalDatastoreType logicalDatastoreType, final Class<? extends DataObject> dataObject,
273 final String[]... data) {
274 ReadWriteTransaction tx = dataBroker.newReadWriteTransaction();
275 if (LogicalSwitches.class == dataObject) {
276 for (LogicalSwitchesKey key : TestBuilders.logicalSwitches(data).keySet()) {
277 tx.delete(logicalDatastoreType,
278 nodeIid.augmentation(HwvtepGlobalAugmentation.class).child(LogicalSwitches.class, key));
281 if (TerminationPoint.class == dataObject) {
282 // FIXME: this is a no-op
284 .setTerminationPoint(TestBuilders.globalTerminationPoints(nodeIid, data));
286 if (RemoteUcastMacs.class == dataObject) {
287 for (RemoteUcastMacsKey key : TestBuilders.remoteUcastMacs(nodeIid, data).keySet()) {
288 tx.delete(logicalDatastoreType,
289 nodeIid.augmentation(HwvtepGlobalAugmentation.class).child(RemoteUcastMacs.class, key));
292 if (RemoteMcastMacs.class == dataObject) {
293 for (RemoteMcastMacsKey key : TestBuilders.remoteMcastMacs(nodeIid, data).keySet()) {
294 tx.delete(logicalDatastoreType,
295 nodeIid.augmentation(HwvtepGlobalAugmentation.class).child(RemoteMcastMacs.class, key));
301 NodeBuilder prepareNode(final InstanceIdentifier<Node> iid) {
302 return new NodeBuilder().setNodeId(iid.firstKeyOf(Node.class).getNodeId());
305 Node mergeNode(final LogicalDatastoreType datastoreType, final InstanceIdentifier<Node> id,
306 final NodeBuilder nodeBuilder) {
307 Node node = nodeBuilder.build();
308 WriteTransaction transaction = dataBroker.newWriteOnlyTransaction();
309 transaction.mergeParentStructureMerge(datastoreType, id, node);
310 transaction.commit();
314 public InstanceIdentifier<Node> createInstanceIdentifier(final 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)