bug 6579 added basic unit tests 26/48726/6
authorK.V Suneelu Verma <k.v.suneelu.verma@ericsson.com>
Mon, 28 Nov 2016 07:29:20 +0000 (12:59 +0530)
committerK.V Suneelu Verma <k.v.suneelu.verma@ericsson.com>
Mon, 12 Dec 2016 05:09:51 +0000 (10:39 +0530)
Added unit tests for the following commands
McastMacsRemoteUpdateCommand
UcastMacsRemoteUpdateCommand
LogicalSwitchUpdateCommand

When logical switch is configured ensure that op.insert is fired
same with mcast mac and ucast mac also.

Change-Id: Ie08664faa233776f82fb0a4ea8d6f0522a4b4810
Signed-off-by: K.V Suneelu Verma <k.v.suneelu.verma@ericsson.com>
hwvtepsouthbound/hwvtepsouthbound-impl/pom.xml
hwvtepsouthbound/hwvtepsouthbound-impl/src/test/java/org/opendaylight/ovsdb/hwvtepsouthbound/DataChangeListenerTestBase.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/test/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepDataChangeListenerTest.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/test/java/org/opendaylight/ovsdb/hwvtepsouthbound/TestBuilders.java [new file with mode: 0644]
hwvtepsouthbound/hwvtepsouthbound-impl/src/test/resources/org/opendaylight/ovsdb/hwvtepsouthbound/hwvtep_schema.json [new file with mode: 0644]

index 122e4e00b2616a1b35de100db4884084b92a1bd0..d8d647c34ee5d7ee3b5101260cf77ac88ba10956 100644 (file)
@@ -43,7 +43,24 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <version>${project.version}</version>
     </dependency>
     <!-- Testing Dependencies -->
-    <dependency>
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>sal-binding-broker-impl</artifactId>
+          <scope>test</scope>
+      </dependency>
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>sal-binding-broker-impl</artifactId>
+          <scope>test</scope>
+          <type>test-jar</type>
+      </dependency>
+      <dependency>
+          <groupId>org.slf4j</groupId>
+          <artifactId>slf4j-simple</artifactId>
+          <scope>test</scope>
+      </dependency>
+
+      <dependency>
       <groupId>junit</groupId>
       <artifactId>junit</artifactId>
       <scope>test</scope>
@@ -53,6 +70,16 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <artifactId>mockito-all</artifactId>
       <scope>test</scope>
     </dependency>
+      <dependency>
+          <groupId>org.powermock</groupId>
+          <artifactId>powermock-api-mockito</artifactId>
+          <scope>test</scope>
+      </dependency>
+      <dependency>
+          <groupId>org.powermock</groupId>
+          <artifactId>powermock-module-junit4</artifactId>
+          <scope>test</scope>
+      </dependency>
   </dependencies>
 
   <build>
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/test/java/org/opendaylight/ovsdb/hwvtepsouthbound/DataChangeListenerTestBase.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/test/java/org/opendaylight/ovsdb/hwvtepsouthbound/DataChangeListenerTestBase.java
new file mode 100644 (file)
index 0000000..ae0a87c
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2016 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.Comment;
+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.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.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.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;
+
+    @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 = getDataBroker();
+        }
+        entityOwnershipService = mock(EntityOwnershipService.class);
+        loadSchema();
+        mockConnectionInstance();
+        mockConnectionManager();
+        mockOperations();
+
+        nodeUuid = java.util.UUID.randomUUID().toString();
+        nodeIid = createInstanceIdentifier(nodeUuid);
+        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));
+        when(hwvtepConnectionManager.getConnectionInstance(Mockito.any(HwvtepPhysicalSwitchAttributes.class))).
+                thenReturn(connectionInstance);
+        when(hwvtepConnectionManager.getConnectionInstance(Mockito.any(Node.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());
+        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());
+        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);
+        Insert insert = mock(Insert.class);
+        when(insert.withId(any(String.class))).thenReturn(insert);
+        Operations.op = PowerMockito.mock(Operations.class);
+        when(Operations.op.comment(any(String.class))).thenReturn(mock(Comment.class));
+        when(Operations.op.insert(insertOpCapture.capture())).thenReturn(insert);
+
+        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();
+    }
+
+    void 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());
+        mergeNode(logicalDatastoreType, nodeIid, nodeBuilder);
+    }
+
+    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();
+    }
+}
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/test/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepDataChangeListenerTest.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/test/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepDataChangeListenerTest.java
new file mode 100644 (file)
index 0000000..4517c84
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2016 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.google.common.collect.Lists;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Matchers;
+import org.opendaylight.ovsdb.lib.operations.Operations;
+import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
+import org.opendaylight.ovsdb.lib.schema.typed.TypedBaseTable;
+import org.opendaylight.ovsdb.schema.hardwarevtep.LogicalSwitch;
+import org.opendaylight.ovsdb.schema.hardwarevtep.McastMacsRemote;
+import org.opendaylight.ovsdb.schema.hardwarevtep.UcastMacsRemote;
+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.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.network.topology.topology.node.TerminationPoint;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Iterator;
+import java.util.List;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.CONFIGURATION;
+import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.OPERATIONAL;
+
+/**
+ * Unit tests for the data-tree change listener.
+ */
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({HwvtepConnectionInstance.class, HwvtepConnectionManager.class, Operations.class})
+public class HwvtepDataChangeListenerTest extends DataChangeListenerTestBase {
+
+    static Logger LOG = LoggerFactory.getLogger(HwvtepDataChangeListenerTest.class);
+
+    String[][] ucastMacs = new String[][]{
+            {"20:00:00:00:00:01", "11.10.10.1", "192.168.122.20", "ls0"},
+            {"20:00:00:00:00:02", "11.10.10.2", "192.168.122.20", "ls0"},
+            {"20:00:00:00:00:03", "11.10.10.3", "192.168.122.30", "ls1"},
+            {"20:00:00:00:00:04", "11.10.10.4", "192.168.122.30", "ls1"}
+    };
+
+    String[][] logicalSwitches = new String[][]{
+            {"ls0", "100"},
+            {"ls1", "200"},
+    };
+
+    String[][] terminationPoints = new String[][]{
+            {"192.168.122.10"},
+            {"192.168.122.20"},
+            {"192.168.122.30"},
+            {"192.168.122.40"}
+    };
+
+    String[][] mcastMacs = new String[][]{
+            {"FF:FF:FF:FF:FF:FF", "ls0", "192.168.122.20", "192.168.122.30"},
+            {"FF:FF:FF:FF:FF:FF", "ls1", "192.168.122.10", "192.168.122.30"}
+    };
+
+    @Test
+    public <T extends DataObject> void testLogicalSwitchAdd() throws Exception {
+        addData(CONFIGURATION, LogicalSwitches.class, logicalSwitches);
+        verifyThatLogicalSwitchCreated();
+    }
+
+    @Test
+    public <T extends DataObject> void testUcastMacAdd() throws Exception {
+        addData(CONFIGURATION, LogicalSwitches.class, logicalSwitches);
+        addData(OPERATIONAL, LogicalSwitches.class, logicalSwitches);
+        resetOperations();
+        addData(CONFIGURATION, TerminationPoint.class, terminationPoints);
+        addData(CONFIGURATION, RemoteUcastMacs.class, ucastMacs);
+        //4 ucast macs + 2 termination points
+        verify(Operations.op,  times(6)).insert(any(UcastMacsRemote.class));
+        //TODO add finer grained validation
+    }
+
+    @Test
+    public <T extends DataObject> void testMcastMacAdd() throws Exception {
+        addData(CONFIGURATION, LogicalSwitches.class, logicalSwitches);
+        addData(OPERATIONAL, LogicalSwitches.class, logicalSwitches);
+        resetOperations();
+        addData(CONFIGURATION, TerminationPoint.class, terminationPoints);
+        addData(CONFIGURATION, RemoteMcastMacs.class, mcastMacs);
+        //2 mcast macs + 2 locator sets + 3 termination points
+        verify(Operations.op,  times(7)).insert(Matchers.<McastMacsRemote>any());
+    }
+
+    @Test
+    public <T extends DataObject> void testAddMacs() throws Exception {
+        addData(CONFIGURATION, LogicalSwitches.class, logicalSwitches);
+        addData(OPERATIONAL, LogicalSwitches.class, logicalSwitches);
+        resetOperations();
+        addData(CONFIGURATION, TerminationPoint.class, terminationPoints);
+        addData(CONFIGURATION, RemoteUcastMacs.class, ucastMacs);
+        verify(Operations.op,  times(6)).insert(any(UcastMacsRemote.class));
+
+        addData(OPERATIONAL, TerminationPoint.class, terminationPoints);
+        addData(OPERATIONAL, RemoteUcastMacs.class, ucastMacs);
+
+        resetOperations();
+        addData(CONFIGURATION, RemoteMcastMacs.class, mcastMacs);
+        //2 mcast mac + 2 locator sets ( termination point already added )
+        verify(Operations.op,  times(4)).insert(Matchers.<McastMacsRemote>any());
+    }
+
+    private void verifyThatLogicalSwitchCreated() {
+        verify(ovsdbClient, times(1)).transact(any(DatabaseSchema.class), any(List.class));
+        verify(Operations.op, times(2)).insert(any(LogicalSwitch.class));
+
+        assertNotNull(insertOpCapture.getAllValues());
+        assertTrue(insertOpCapture.getAllValues().size() == 2);
+
+        List<String> expected = Lists.newArrayList("ls0", "ls1");
+        Iterator<TypedBaseTable> it = insertOpCapture.getAllValues().iterator();
+        while (it.hasNext()) {
+            TypedBaseTable table = it.next();
+            assertTrue(table instanceof LogicalSwitch);
+            LogicalSwitch ls = (LogicalSwitch)table;
+            assertTrue(expected.contains(ls.getName()));
+            expected.remove(ls.getName());
+            it.next();
+        }
+    }
+}
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/test/java/org/opendaylight/ovsdb/hwvtepsouthbound/TestBuilders.java b/hwvtepsouthbound/hwvtepsouthbound-impl/src/test/java/org/opendaylight/ovsdb/hwvtepsouthbound/TestBuilders.java
new file mode 100644 (file)
index 0000000..2562854
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2016 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.google.common.collect.Lists;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+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.HwvtepLogicalSwitchRef;
+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.HwvtepPhysicalLocatorAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorRef;
+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.LogicalSwitchesBuilder;
+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.RemoteMcastMacsBuilder;
+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.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteUcastMacsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSet;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSetBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId;
+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.node.TerminationPoint;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.UUID;
+
+public class TestBuilders {
+
+    public static final String VXLAN_OVER_IPV4 = "vxlan_over_ipv4";
+
+    public static void addLogicalSwitches(HwvtepGlobalAugmentationBuilder augmentationBuilder, String[]... data) {
+        List<LogicalSwitches> logicalSwitcheses = Lists.newArrayList();
+        for (String row[] : data) {
+            logicalSwitcheses.add(TestBuilders.buildLogicalSwitch(row));
+        }
+        augmentationBuilder.setLogicalSwitches(logicalSwitcheses);
+    }
+
+    public static void addRemoteMcastMacs(InstanceIdentifier<Node> iid,
+                                          HwvtepGlobalAugmentationBuilder augmentationBuilder, String[]... data) {
+        List<RemoteMcastMacs> remoteMcastMacses = Lists.newArrayList();
+        for (String row[] : data) {
+            String teps[] = Arrays.copyOfRange(row, 2, row.length);
+            remoteMcastMacses.add(TestBuilders.buildRemoteMcastMacs(iid, row[0], row[1], teps));
+        }
+        augmentationBuilder.setRemoteMcastMacs(remoteMcastMacses);
+    }
+
+    public static List<RemoteUcastMacs> addRemoteUcastMacs(InstanceIdentifier<Node> iid,
+                                                           HwvtepGlobalAugmentationBuilder augmentationBuilder,
+                                                           String[]... data) {
+        List<RemoteUcastMacs> remoteUcastMacses = Lists.newArrayList();
+        for (String row[] : data) {
+            remoteUcastMacses.add(TestBuilders.buildRemoteUcastMacs(iid, row[0], row[1], row[2], row[3]));
+        }
+        augmentationBuilder.setRemoteUcastMacs(remoteUcastMacses);
+        return remoteUcastMacses;
+    }
+
+    public static void addGlobalTerminationPoints(NodeBuilder nodeBuilder, InstanceIdentifier<Node> nodeIid,
+                                                  String[]... data) {
+        List<TerminationPoint> terminationPoints = Lists.newArrayList();
+        for (String row[] : data) {
+            terminationPoints.add(TestBuilders.buildTerminationPoint(nodeIid, row[0]));
+        }
+        nodeBuilder.setTerminationPoint(terminationPoints);
+    }
+
+    public static HwvtepLogicalSwitchRef buildLogicalSwitchesRef(InstanceIdentifier<Node> nodeIid,
+                                                                 String logicalSwitchName ) {
+        InstanceIdentifier<LogicalSwitches> lSwitchIid = nodeIid.augmentation(HwvtepGlobalAugmentation.class)
+                .child(LogicalSwitches.class, new LogicalSwitchesKey(new HwvtepNodeName(logicalSwitchName)));
+        return new HwvtepLogicalSwitchRef(lSwitchIid);
+    }
+
+    public static RemoteUcastMacs buildRemoteUcastMacs(InstanceIdentifier<Node> nodeIid, String vmMac,
+                                                       String vmip, String tepIp, String logicalSwitchName) {
+        RemoteUcastMacsBuilder ucmlBuilder = new RemoteUcastMacsBuilder();
+        ucmlBuilder.setIpaddr(new IpAddress(vmip.toCharArray()));
+        ucmlBuilder.setMacEntryKey(new MacAddress(vmMac));
+        ucmlBuilder.setMacEntryUuid(getUUid(vmMac));
+        ucmlBuilder.setLocatorRef(buildLocatorRef(nodeIid, tepIp));
+        ucmlBuilder.setLogicalSwitchRef(buildLogicalSwitchesRef(nodeIid, logicalSwitchName));
+        return ucmlBuilder.build();
+    }
+
+    public static TerminationPoint buildTerminationPoint(InstanceIdentifier<Node> nodeIid, String ip) {
+        TerminationPointKey tpKey = new TerminationPointKey(new TpId("vxlan_over_ipv4:"+ip));
+        TerminationPointBuilder tpBuilder = new TerminationPointBuilder();
+        if (nodeIid != null) {
+            tpBuilder.setKey(tpKey);
+            tpBuilder.setTpId(tpKey.getTpId());
+            HwvtepPhysicalLocatorAugmentationBuilder tpAugmentationBuilder =
+                    new HwvtepPhysicalLocatorAugmentationBuilder();
+            tpAugmentationBuilder.setPhysicalLocatorUuid(getUUid(ip));
+            tpAugmentationBuilder.setEncapsulationType(HwvtepSouthboundMapper.createEncapsulationType(VXLAN_OVER_IPV4));
+            tpAugmentationBuilder.setDstIp(new IpAddress(ip.toCharArray()));
+            tpBuilder.addAugmentation(HwvtepPhysicalLocatorAugmentation.class, tpAugmentationBuilder.build());
+        }
+        return tpBuilder.build();
+    }
+
+    public static LogicalSwitches buildLogicalSwitch(String... keys) {
+        String logicalSwitch = keys[0];
+        String tunnelKey = keys[1];
+        LogicalSwitchesBuilder logicalSwitchesBuilder = new LogicalSwitchesBuilder();
+        logicalSwitchesBuilder.setKey(new LogicalSwitchesKey(new HwvtepNodeName(logicalSwitch)));
+        logicalSwitchesBuilder.setHwvtepNodeName(new HwvtepNodeName(logicalSwitch));
+        logicalSwitchesBuilder.setTunnelKey(tunnelKey);
+        Uuid uuid = getUUid(logicalSwitch);
+        logicalSwitchesBuilder.setLogicalSwitchUuid(uuid);
+        return logicalSwitchesBuilder.build();
+    }
+
+    public static RemoteMcastMacs buildRemoteMcastMacs(InstanceIdentifier<Node> iid, String mac,
+                                                       String logicalSwitchName,String tepIps[]) {
+
+        RemoteMcastMacsBuilder mMacLocalBuilder = new RemoteMcastMacsBuilder();
+        if (mac.equals(HwvtepSouthboundConstants.UNKNOWN_DST_STRING)) {
+            mMacLocalBuilder.setMacEntryKey(HwvtepSouthboundConstants.UNKNOWN_DST_MAC);
+        } else {
+            mMacLocalBuilder.setMacEntryKey(new MacAddress(mac));
+        }
+        mMacLocalBuilder.setMacEntryUuid(getUUid(mac));
+        mMacLocalBuilder.setLogicalSwitchRef(buildLogicalSwitchesRef(iid, logicalSwitchName));
+        List<LocatorSet> locatorSets = Lists.newArrayList();
+        for (String tepIp : tepIps) {
+            locatorSets.add(new LocatorSetBuilder().setLocatorRef(
+                    buildLocatorRef(iid, tepIp)).build());
+        }
+        mMacLocalBuilder.setLocatorSet(locatorSets);
+        return mMacLocalBuilder.build();
+    }
+
+    public static HwvtepPhysicalLocatorRef buildLocatorRef(InstanceIdentifier<Node> nodeIid,String tepIp) {
+        InstanceIdentifier<TerminationPoint> tepId = buildTpId(nodeIid, tepIp);
+        return new HwvtepPhysicalLocatorRef(tepId);
+    }
+
+    public static Uuid getUUid(String key) {
+        return new Uuid(UUID.nameUUIDFromBytes(key.getBytes()).toString());
+    }
+
+    public static InstanceIdentifier<TerminationPoint> buildTpId(InstanceIdentifier<Node> nodeIid,String tepIp) {
+        String tpKeyStr = VXLAN_OVER_IPV4 +':'+tepIp;
+        TerminationPointKey tpKey = new TerminationPointKey(new TpId(tpKeyStr));
+        return nodeIid.child(TerminationPoint.class, tpKey);
+    }
+}
diff --git a/hwvtepsouthbound/hwvtepsouthbound-impl/src/test/resources/org/opendaylight/ovsdb/hwvtepsouthbound/hwvtep_schema.json b/hwvtepsouthbound/hwvtepsouthbound-impl/src/test/resources/org/opendaylight/ovsdb/hwvtepsouthbound/hwvtep_schema.json
new file mode 100644 (file)
index 0000000..3d34523
--- /dev/null
@@ -0,0 +1,495 @@
+{
+  "error": null,
+  "id": "0",
+  "result": {
+    "cksum": "58544667 7319",
+    "name": "hardware_vtep",
+    "tables": {
+      "Arp_Sources_Local": {
+        "columns": {
+          "locator": {
+            "type": {
+              "key": {
+                "refTable": "Physical_Locator",
+                "type": "uuid"
+              }
+            }
+          },
+          "src_mac": {
+            "type": "string"
+          }
+        },
+        "isRoot": true
+      },
+      "Arp_Sources_Remote": {
+        "columns": {
+          "locator": {
+            "type": {
+              "key": {
+                "refTable": "Physical_Locator",
+                "type": "uuid"
+              }
+            }
+          },
+          "src_mac": {
+            "type": "string"
+          }
+        },
+        "isRoot": true
+      },
+      "Global": {
+        "columns": {
+          "managers": {
+            "type": {
+              "key": {
+                "refTable": "Manager",
+                "type": "uuid"
+              },
+              "max": "unlimited",
+              "min": 0
+            }
+          },
+          "switches": {
+            "type": {
+              "key": {
+                "refTable": "Physical_Switch",
+                "type": "uuid"
+              },
+              "max": "unlimited",
+              "min": 0
+            }
+          }
+        },
+        "isRoot": true,
+        "maxRows": 1
+      },
+      "Logical_Binding_Stats": {
+        "columns": {
+          "bytes_from_local": {
+            "type": "integer"
+          },
+          "bytes_to_local": {
+            "type": "integer"
+          },
+          "packets_from_local": {
+            "type": "integer"
+          },
+          "packets_to_local": {
+            "type": "integer"
+          }
+        }
+      },
+      "Logical_Router": {
+        "columns": {
+          "description": {
+            "type": "string"
+          },
+          "name": {
+            "type": "string"
+          },
+          "static_routes": {
+            "type": {
+              "key": "string",
+              "max": "unlimited",
+              "min": 0,
+              "value": "string"
+            }
+          },
+          "switch_binding": {
+            "type": {
+              "key": "string",
+              "max": "unlimited",
+              "min": 0,
+              "value": {
+                "refTable": "Logical_Switch",
+                "type": "uuid"
+              }
+            }
+          }
+        },
+        "indexes": [
+          [
+            "name"
+          ]
+        ],
+        "isRoot": true
+      },
+      "Logical_Switch": {
+        "columns": {
+          "description": {
+            "type": "string"
+          },
+          "name": {
+            "type": "string"
+          },
+          "_uuid": {
+            "type": "string"
+          },
+          "tunnel_key": {
+            "type": {
+              "key": "integer",
+              "min": 0
+            }
+          }
+        },
+        "indexes": [
+          [
+            "name"
+          ]
+        ],
+        "isRoot": true
+      },
+      "Manager": {
+        "columns": {
+          "inactivity_probe": {
+            "type": {
+              "key": "integer",
+              "min": 0
+            }
+          },
+          "is_connected": {
+            "ephemeral": true,
+            "type": "boolean"
+          },
+          "max_backoff": {
+            "type": {
+              "key": {
+                "minInteger": 1000,
+                "type": "integer"
+              },
+              "min": 0
+            }
+          },
+          "other_config": {
+            "type": {
+              "key": "string",
+              "max": "unlimited",
+              "min": 0,
+              "value": "string"
+            }
+          },
+          "status": {
+            "ephemeral": true,
+            "type": {
+              "key": "string",
+              "max": "unlimited",
+              "min": 0,
+              "value": "string"
+            }
+          },
+          "target": {
+            "type": "string"
+          }
+        },
+        "indexes": [
+          [
+            "target"
+          ]
+        ]
+      },
+      "Mcast_Macs_Local": {
+        "columns": {
+          "MAC": {
+            "type": "string"
+          },
+          "ipaddr": {
+            "type": "string"
+          },
+          "locator_set": {
+            "type": {
+              "key": {
+                "refTable": "Physical_Locator_Set",
+                "type": "uuid"
+              }
+            }
+          },
+          "logical_switch": {
+            "type": {
+              "key": {
+                "refTable": "Logical_Switch",
+                "type": "uuid"
+              }
+            }
+          }
+        },
+        "isRoot": true
+      },
+      "Mcast_Macs_Remote": {
+        "columns": {
+          "MAC": {
+            "type": "string"
+          },
+          "ipaddr": {
+            "type": "string"
+          },
+          "locator_set": {
+            "type": {
+              "key": {
+                "refTable": "Physical_Locator_Set",
+                "type": "uuid"
+              }
+            }
+          },
+          "logical_switch": {
+            "type": {
+              "key": {
+                "refTable": "Logical_Switch",
+                "type": "uuid"
+              }
+            }
+          }
+        },
+        "isRoot": true
+      },
+      "Physical_Locator": {
+        "columns": {
+          "dst_ip": {
+            "mutable": false,
+            "type": "string"
+          },
+          "encapsulation_type": {
+            "mutable": false,
+            "type": {
+              "key": {
+                "enum": "vxlan_over_ipv4",
+                "type": "string"
+              }
+            }
+          }
+        },
+        "indexes": [
+          [
+            "encapsulation_type",
+            "dst_ip"
+          ]
+        ]
+      },
+      "Physical_Locator_Set": {
+        "columns": {
+          "locators": {
+            "mutable": false,
+            "type": {
+              "key": {
+                "refTable": "Physical_Locator",
+                "type": "uuid"
+              },
+              "max": "unlimited"
+            }
+          }
+        }
+      },
+      "Physical_Port": {
+        "columns": {
+          "description": {
+            "type": "string"
+          },
+          "name": {
+            "type": "string"
+          },
+          "port_fault_status": {
+            "ephemeral": true,
+            "type": {
+              "key": "string",
+              "max": "unlimited",
+              "min": 0
+            }
+          },
+          "vlan_bindings": {
+            "type": {
+              "key": {
+                "maxInteger": 4095,
+                "minInteger": 0,
+                "type": "integer"
+              },
+              "max": "unlimited",
+              "min": 0,
+              "value": {
+                "refTable": "Logical_Switch",
+                "type": "uuid"
+              }
+            }
+          },
+          "vlan_stats": {
+            "type": {
+              "key": {
+                "maxInteger": 4095,
+                "minInteger": 0,
+                "type": "integer"
+              },
+              "max": "unlimited",
+              "min": 0,
+              "value": {
+                "refTable": "Logical_Binding_Stats",
+                "type": "uuid"
+              }
+            }
+          }
+        }
+      },
+      "Physical_Switch": {
+        "columns": {
+          "description": {
+            "type": "string"
+          },
+          "management_ips": {
+            "type": {
+              "key": "string",
+              "max": "unlimited",
+              "min": 0
+            }
+          },
+          "name": {
+            "type": "string"
+          },
+          "ports": {
+            "type": {
+              "key": {
+                "refTable": "Physical_Port",
+                "type": "uuid"
+              },
+              "max": "unlimited",
+              "min": 0
+            }
+          },
+          "switch_fault_status": {
+            "ephemeral": true,
+            "type": {
+              "key": "string",
+              "max": "unlimited",
+              "min": 0
+            }
+          },
+          "tunnel_ips": {
+            "type": {
+              "key": "string",
+              "max": "unlimited",
+              "min": 0
+            }
+          },
+          "tunnels": {
+            "type": {
+              "key": {
+                "refTable": "Tunnel",
+                "type": "uuid"
+              },
+              "max": "unlimited",
+              "min": 0
+            }
+          }
+        },
+        "indexes": [
+          [
+            "name"
+          ]
+        ]
+      },
+      "Tunnel": {
+        "columns": {
+          "bfd_config_local": {
+            "type": {
+              "key": "string",
+              "max": "unlimited",
+              "min": 0,
+              "value": "string"
+            }
+          },
+          "bfd_config_remote": {
+            "type": {
+              "key": "string",
+              "max": "unlimited",
+              "min": 0,
+              "value": "string"
+            }
+          },
+          "bfd_params": {
+            "type": {
+              "key": "string",
+              "max": "unlimited",
+              "min": 0,
+              "value": "string"
+            }
+          },
+          "bfd_status": {
+            "type": {
+              "key": "string",
+              "max": "unlimited",
+              "min": 0,
+              "value": "string"
+            }
+          },
+          "local": {
+            "type": {
+              "key": {
+                "refTable": "Physical_Locator",
+                "type": "uuid"
+              }
+            }
+          },
+          "remote": {
+            "type": {
+              "key": {
+                "refTable": "Physical_Locator",
+                "type": "uuid"
+              }
+            }
+          }
+        }
+      },
+      "Ucast_Macs_Local": {
+        "columns": {
+          "MAC": {
+            "type": "string"
+          },
+          "ipaddr": {
+            "type": "string"
+          },
+          "locator": {
+            "type": {
+              "key": {
+                "refTable": "Physical_Locator",
+                "type": "uuid"
+              }
+            }
+          },
+          "logical_switch": {
+            "type": {
+              "key": {
+                "refTable": "Logical_Switch",
+                "type": "uuid"
+              }
+            }
+          }
+        },
+        "isRoot": true
+      },
+      "Ucast_Macs_Remote": {
+        "columns": {
+          "MAC": {
+            "type": "string"
+          },
+          "ipaddr": {
+            "type": "string"
+          },
+          "locator": {
+            "type": {
+              "key": {
+                "refTable": "Physical_Locator",
+                "type": "uuid"
+              }
+            }
+          },
+          "logical_switch": {
+            "type": {
+              "key": {
+                "refTable": "Logical_Switch",
+                "type": "uuid"
+              }
+            }
+          }
+        },
+        "isRoot": true
+      }
+    },
+    "version": "1.3.0"
+  }
+}