/* * Copyright (c) 2016, 2017 Ericsson India Global Services Pvt Ltd. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.ovsdb.hwvtepsouthbound; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.util.concurrent.ListenableFuture; import org.junit.After; import org.junit.Before; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; import org.opendaylight.controller.md.sal.binding.test.AbstractDataBrokerTest; import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md.TransactionInvoker; import org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md.TransactionInvokerImpl; import org.opendaylight.ovsdb.lib.OvsdbClient; import org.opendaylight.ovsdb.lib.OvsdbConnectionInfo; import org.opendaylight.ovsdb.lib.operations.Delete; import org.opendaylight.ovsdb.lib.operations.Insert; import org.opendaylight.ovsdb.lib.operations.OperationResult; import org.opendaylight.ovsdb.lib.operations.Operations; import org.opendaylight.ovsdb.lib.operations.Update; import org.opendaylight.ovsdb.lib.operations.Where; import org.opendaylight.ovsdb.lib.schema.DatabaseSchema; import org.opendaylight.ovsdb.lib.schema.typed.TypedBaseTable; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentationBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalSwitchAttributes; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitchesKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteUcastMacs; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.powermock.api.mockito.PowerMockito; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.InputStream; import java.net.InetAddress; import java.util.List; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.CONFIGURATION; import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.OPERATIONAL; import static org.powermock.api.support.membermodification.MemberMatcher.field; import static org.powermock.api.support.membermodification.MemberModifier.suppress; public class DataChangeListenerTestBase extends AbstractDataBrokerTest { static Logger LOG = LoggerFactory.getLogger(DataChangeListenerTestBase.class); static DataBroker dataBroker; EntityOwnershipService entityOwnershipService; OvsdbClient ovsdbClient; DatabaseSchema dbSchema; ListenableFuture<DatabaseSchema> listenableDbSchema = mock(ListenableFuture.class); TransactionInvoker transactionInvoker; OvsdbConnectionInfo connectionInfo; Operations operations; HwvtepDataChangeListener hwvtepDataChangeListener; HwvtepConnectionManager hwvtepConnectionManager; HwvtepConnectionInstance connectionInstance; ArgumentCaptor<TypedBaseTable> insertOpCapture; ArgumentCaptor<List> transactCaptor; String nodeUuid; InstanceIdentifier<Node> nodeIid; InstanceIdentifier<LogicalSwitches> ls0Iid; InstanceIdentifier<LogicalSwitches> ls1Iid; @Before public void setupTest() throws Exception { /** * Use the same databroker across tests ,otherwise the following exception is thrown * Caused by: java.lang.RuntimeException: org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network. * topology.rev131021.node.attributes.SupportingNode$StreamWriter: frozen class (cannot edit) */ if (dataBroker == null) { dataBroker = super.getDataBroker(); } entityOwnershipService = mock(EntityOwnershipService.class); nodeUuid = java.util.UUID.randomUUID().toString(); nodeIid = createInstanceIdentifier(nodeUuid); ls0Iid = nodeIid.augmentation(HwvtepGlobalAugmentation.class). child(LogicalSwitches.class, new LogicalSwitchesKey(new HwvtepNodeName("ls0"))); ls1Iid = nodeIid.augmentation(HwvtepGlobalAugmentation.class). child(LogicalSwitches.class, new LogicalSwitchesKey(new HwvtepNodeName("ls1"))); loadSchema(); mockConnectionInstance(); mockConnectionManager(); mockOperations(); addNode(OPERATIONAL); addNode(CONFIGURATION); hwvtepDataChangeListener = new HwvtepDataChangeListener(dataBroker, hwvtepConnectionManager); } @After public void tearDown() throws Exception { hwvtepDataChangeListener.close(); deleteNode(OPERATIONAL); deleteNode(CONFIGURATION); } void loadSchema() { try (InputStream resourceAsStream = DataChangeListenerTestBase.class.getResourceAsStream("hwvtep_schema.json")) { ObjectMapper mapper = new ObjectMapper(); JsonNode jsonNode = mapper.readTree(resourceAsStream); dbSchema = DatabaseSchema.fromJson(HwvtepSchemaConstants.HARDWARE_VTEP, jsonNode.get("result")); listenableDbSchema = mock(ListenableFuture.class); when(listenableDbSchema.get()).thenReturn(dbSchema); } catch (Exception e) { LOG.error("Failed to load schema", e); } } private void mockConnectionManager() throws IllegalAccessException { hwvtepConnectionManager = PowerMockito.mock(HwvtepConnectionManager.class, Mockito.CALLS_REAL_METHODS); field(HwvtepConnectionManager.class, "db").set(hwvtepConnectionManager, dataBroker); field(HwvtepConnectionManager.class, "txInvoker").set(hwvtepConnectionManager, transactionInvoker); field(HwvtepConnectionManager.class, "entityOwnershipService").set(hwvtepConnectionManager, entityOwnershipService); suppress(PowerMockito.method(HwvtepConnectionManager.class, "getConnectionInstance", HwvtepPhysicalSwitchAttributes.class)); suppress(PowerMockito.method(HwvtepConnectionManager.class, "getConnectionInstanceFromNodeIid", InstanceIdentifier.class)); when(hwvtepConnectionManager.getConnectionInstance(Mockito.any(HwvtepPhysicalSwitchAttributes.class))). thenReturn(connectionInstance); when(hwvtepConnectionManager.getConnectionInstance(Mockito.any(Node.class))). thenReturn(connectionInstance); when(hwvtepConnectionManager.getConnectionInstanceFromNodeIid(Mockito.any(InstanceIdentifier.class))) .thenReturn(connectionInstance); } void mockConnectionInstance() throws IllegalAccessException { connectionInfo = mock(OvsdbConnectionInfo.class); ovsdbClient = mock(OvsdbClient.class); transactionInvoker = new TransactionInvokerImpl(dataBroker); connectionInstance = PowerMockito.mock(HwvtepConnectionInstance.class, Mockito.CALLS_REAL_METHODS); field(HwvtepConnectionInstance.class, "instanceIdentifier").set(connectionInstance, nodeIid); field(HwvtepConnectionInstance.class, "txInvoker").set(connectionInstance, transactionInvoker); field(HwvtepConnectionInstance.class, "deviceInfo").set(connectionInstance, new HwvtepDeviceInfo(connectionInstance)); field(HwvtepConnectionInstance.class, "client").set(connectionInstance, ovsdbClient); when(connectionInstance.getConnectionInfo()).thenReturn(connectionInfo); when(connectionInstance.getConnectionInfo().getRemoteAddress()).thenReturn(mock(InetAddress.class)); when(connectionInstance.getInstanceIdentifier()).thenReturn(nodeIid); doReturn(listenableDbSchema).when(connectionInstance).getSchema(anyString()); when(connectionInstance.getDataBroker()).thenReturn(dataBroker); when(connectionInstance.getInstanceIdentifier()).thenReturn(nodeIid); connectionInstance.createTransactInvokers(); } void mockOperations() { resetOperations(); } /** * resets the captures so that we can validate the captors of the immediate next execution */ void resetOperations() { insertOpCapture = ArgumentCaptor.forClass(TypedBaseTable.class); Update update = mock(Update.class); Insert insert = mock(Insert.class); Delete delete = mock(Delete.class); Where where = mock(Where.class); when(delete.where(any())).thenReturn(where); when(insert.withId(any(String.class))).thenReturn(insert); Operations.op = PowerMockito.mock(Operations.class); when(Operations.op.insert(insertOpCapture.capture())).thenReturn(insert); when(Operations.op.update(insertOpCapture.capture())).thenReturn(update); when(update.where(any())).thenReturn(where); when(Operations.op.delete(any())).thenReturn(delete); ListenableFuture<List<OperationResult>> ft = mock(ListenableFuture.class); transactCaptor = ArgumentCaptor.forClass(List.class); when(ovsdbClient.transact(any(DatabaseSchema.class), transactCaptor.capture())).thenReturn(ft); } void addNode(LogicalDatastoreType logicalDatastoreType) throws Exception { NodeBuilder nodeBuilder = prepareNode(nodeIid); HwvtepGlobalAugmentationBuilder builder = new HwvtepGlobalAugmentationBuilder(); nodeBuilder.addAugmentation(HwvtepGlobalAugmentation.class, builder.build()); WriteTransaction transaction = dataBroker.newWriteOnlyTransaction(); transaction.put(logicalDatastoreType, nodeIid, nodeBuilder.build(), WriteTransaction.CREATE_MISSING_PARENTS); transaction.submit(); } void deleteNode(LogicalDatastoreType logicalDatastoreType) { ReadWriteTransaction tx = dataBroker.newReadWriteTransaction(); tx.delete(logicalDatastoreType, nodeIid); tx.submit(); } Node addData(LogicalDatastoreType logicalDatastoreType, Class<? extends DataObject> dataObject, String[]... data) { NodeBuilder nodeBuilder = prepareNode(nodeIid); HwvtepGlobalAugmentationBuilder builder = new HwvtepGlobalAugmentationBuilder(); if (LogicalSwitches.class == dataObject) { TestBuilders.addLogicalSwitches(builder, data); } if (TerminationPoint.class == dataObject) { TestBuilders.addGlobalTerminationPoints(nodeBuilder, nodeIid, data); } if (RemoteUcastMacs.class == dataObject) { TestBuilders.addRemoteUcastMacs(nodeIid, builder, data); } if (RemoteMcastMacs.class == dataObject) { TestBuilders.addRemoteMcastMacs(nodeIid, builder, data); } nodeBuilder.addAugmentation(HwvtepGlobalAugmentation.class, builder.build()); return mergeNode(logicalDatastoreType, nodeIid, nodeBuilder); } void deleteData(LogicalDatastoreType logicalDatastoreType, Class<? extends DataObject> dataObject, String[]... data) { NodeBuilder nodeBuilder = prepareNode(nodeIid); ReadWriteTransaction tx = dataBroker.newReadWriteTransaction(); HwvtepGlobalAugmentationBuilder builder = new HwvtepGlobalAugmentationBuilder(); if (LogicalSwitches.class == dataObject) { List<LogicalSwitches> logicalSwitches = TestBuilders.addLogicalSwitches(builder, data); for (LogicalSwitches ls : logicalSwitches) { InstanceIdentifier<LogicalSwitches> key = nodeIid.augmentation(HwvtepGlobalAugmentation.class). child(LogicalSwitches.class, ls.getKey()); tx.delete(logicalDatastoreType, key); } } if (TerminationPoint.class == dataObject) { TestBuilders.addGlobalTerminationPoints(nodeBuilder, nodeIid, data); } if (RemoteUcastMacs.class == dataObject) { List<RemoteUcastMacs> macs = TestBuilders.addRemoteUcastMacs(nodeIid, builder, data); for (RemoteUcastMacs mac : macs) { InstanceIdentifier<RemoteUcastMacs> key = nodeIid.augmentation(HwvtepGlobalAugmentation.class). child(RemoteUcastMacs.class, mac.getKey()); tx.delete(logicalDatastoreType, key); } } if (RemoteMcastMacs.class == dataObject) { List<RemoteMcastMacs> macs = TestBuilders.addRemoteMcastMacs(nodeIid, builder, data); for (RemoteMcastMacs mac : macs) { InstanceIdentifier<RemoteMcastMacs> key = nodeIid.augmentation(HwvtepGlobalAugmentation.class). child(RemoteMcastMacs.class, mac.getKey()); tx.delete(logicalDatastoreType, key); } } tx.submit(); } NodeBuilder prepareNode(InstanceIdentifier<Node> iid) { NodeBuilder nodeBuilder = new NodeBuilder(); nodeBuilder.setNodeId(iid.firstKeyOf(Node.class).getNodeId()); return nodeBuilder; } Node mergeNode(LogicalDatastoreType datastoreType, InstanceIdentifier<Node> id, NodeBuilder nodeBuilder) { Node node = nodeBuilder.build(); WriteTransaction transaction = dataBroker.newWriteOnlyTransaction(); transaction.merge(datastoreType, id, node, WriteTransaction.CREATE_MISSING_PARENTS); transaction.submit(); return node; } public InstanceIdentifier<Node> createInstanceIdentifier(String nodeIdString) { NodeId nodeId = new NodeId(new Uri(nodeIdString)); NodeKey nodeKey = new NodeKey(nodeId); TopologyKey topoKey = new TopologyKey(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID); return InstanceIdentifier.builder(NetworkTopology.class) .child(Topology.class, topoKey) .child(Node.class, nodeKey) .build(); } }