Add support for setting the db schema version
[ovsdb.git] / southbound / southbound-it / src / test / java / org / opendaylight / ovsdb / southbound / it / SouthboundIT.java
index 9a2848c28402a8bee0812b8a316eb974848cb6ff..612e32abdf0c58925f188f6ddba2eb687bab96e2 100644 (file)
@@ -8,17 +8,19 @@
 package org.opendaylight.ovsdb.southbound.it;
 
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.ops4j.pax.exam.CoreOptions.composite;
 import static org.ops4j.pax.exam.CoreOptions.maven;
+import static org.ops4j.pax.exam.CoreOptions.propagateSystemProperties;
 import static org.ops4j.pax.exam.CoreOptions.vmOption;
 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.editConfigurationFilePut;
 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.keepRuntimeFolder;
 
 import com.google.common.collect.ImmutableBiMap;
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
-
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Method;
 import java.net.InetAddress;
@@ -29,15 +31,15 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Properties;
 import java.util.Set;
-
 import javax.annotation.Nullable;
 import javax.inject.Inject;
-
 import org.junit.After;
 import org.junit.Assert;
+import org.junit.Assume;
 import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Test;
+import org.junit.internal.AssumptionViolatedException;
 import org.junit.runner.RunWith;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
@@ -45,15 +47,15 @@ import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.mdsal.it.base.AbstractMdsalTestBase;
+import org.opendaylight.ovsdb.lib.notation.Version;
 import org.opendaylight.ovsdb.southbound.SouthboundConstants;
 import org.opendaylight.ovsdb.southbound.SouthboundMapper;
-import org.opendaylight.ovsdb.southbound.SouthboundProvider;
 import org.opendaylight.ovsdb.southbound.SouthboundUtil;
 import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
 import org.opendaylight.ovsdb.utils.southbound.utils.SouthboundUtils;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+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.inet.types.rev130715.PortNumber;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
 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.l2.types.rev130827.VlanId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.DatapathTypeBase;
@@ -77,6 +79,9 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.re
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ControllerEntryBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ProtocolEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ProtocolEntryBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.Autoattach;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.AutoattachBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.AutoattachKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfo;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfoBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.DatapathTypeEntry;
@@ -89,6 +94,10 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.re
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.Queues;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.QueuesBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.QueuesKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.autoattach.AutoattachExternalIds;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.autoattach.AutoattachExternalIdsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.autoattach.Mappings;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.autoattach.MappingsBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.qos.entries.QosExternalIds;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.qos.entries.QosExternalIdsBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.qos.entries.QosOtherConfig;
@@ -116,6 +125,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.re
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.TrunksBuilder;
 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.TopologyId;
 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;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
@@ -136,6 +146,7 @@ import org.ops4j.pax.exam.karaf.options.LogLevelOption;
 import org.ops4j.pax.exam.options.MavenUrlReference;
 import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
 import org.ops4j.pax.exam.spi.reactors.PerClass;
+import org.ops4j.pax.exam.util.Filter;
 import org.osgi.framework.BundleContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -153,6 +164,8 @@ public class SouthboundIT extends AbstractMdsalTestBase {
     private static final int OVSDB_UPDATE_TIMEOUT = 1000;
     private static final int OVSDB_ROUNDTRIP_TIMEOUT = 10000;
     private static final String FORMAT_STR = "%s_%s_%d";
+    private static final Version AUTOATTACH_FROM_VERSION = Version.fromString("7.11.2");
+    private static final Version IF_INDEX_FROM_VERSION = Version.fromString("7.2.1");
     private static String addressStr;
     private static int portNumber;
     private static String connectionType;
@@ -160,7 +173,9 @@ public class SouthboundIT extends AbstractMdsalTestBase {
     private static MdsalUtils mdsalUtils = null;
     private static Node ovsdbNode;
     private static int testMethodsRemaining;
-    private static DataBroker dataBroker;
+    private static Version schemaVersion;
+    @Inject @Filter(timeout=60000)
+    private static DataBroker dataBroker = null;
 
     @Inject
     private BundleContext bundleContext;
@@ -297,16 +312,6 @@ public class SouthboundIT extends AbstractMdsalTestBase {
                 .getURL();
     }
 
-    @Override
-    public String getModuleName() {
-        return "southbound-impl";
-    }
-
-    @Override
-    public String getInstanceName() {
-        return "southbound-default";
-    }
-
     @Override
     public MavenUrlReference getFeatureRepo() {
         return maven()
@@ -350,6 +355,10 @@ public class SouthboundIT extends AbstractMdsalTestBase {
                 connectionType, addressStr, portStr);
 
         return new Option[] {
+                propagateSystemProperties(
+                        SouthboundITConstants.SERVER_IPADDRESS,
+                        SouthboundITConstants.SERVER_PORT,
+                        SouthboundITConstants.CONNECTION_TYPE),
                 editConfigurationFilePut(SouthboundITConstants.CUSTOM_PROPERTIES,
                         SouthboundITConstants.SERVER_IPADDRESS, addressStr),
                 editConfigurationFilePut(SouthboundITConstants.CUSTOM_PROPERTIES,
@@ -372,11 +381,11 @@ public class SouthboundIT extends AbstractMdsalTestBase {
         } catch (Exception e) {
             LOG.warn("Failed to setup test", e);
         }
-        //dataBroker = getSession().getSALService(DataBroker.class);
-        Thread.sleep(3000);
-        dataBroker = SouthboundProvider.getDb();
         Assert.assertNotNull("db should not be null", dataBroker);
 
+        LOG.info("sleeping for 10s to let the features finish installing");
+        Thread.sleep(10000);
+
         addressStr = bundleContext.getProperty(SouthboundITConstants.SERVER_IPADDRESS);
         String portStr = bundleContext.getProperty(SouthboundITConstants.SERVER_PORT);
         try {
@@ -395,6 +404,7 @@ public class SouthboundIT extends AbstractMdsalTestBase {
         }
 
         mdsalUtils = new MdsalUtils(dataBroker);
+        assertTrue("Did not find " + SouthboundUtils.OVSDB_TOPOLOGY_ID.getValue(), getOvsdbTopology());
         final ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portNumber);
         final InstanceIdentifier<Node> iid = SouthboundUtils.createInstanceIdentifier(connectionInfo);
         dataBroker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
@@ -403,6 +413,10 @@ public class SouthboundIT extends AbstractMdsalTestBase {
                 iid, OPERATIONAL_LISTENER, AsyncDataBroker.DataChangeScope.SUBTREE);
 
         ovsdbNode = connectOvsdbNode(connectionInfo);
+        OvsdbNodeAugmentation ovsdbNodeAugmentation = ovsdbNode.getAugmentation(OvsdbNodeAugmentation.class);
+        assertNotNull("The OvsdbNodeAugmentation cannot be null", ovsdbNodeAugmentation);
+        schemaVersion = Version.fromString(ovsdbNodeAugmentation.getDbVersion());
+        LOG.info("schemaVersion = {}", schemaVersion);
 
         // Let's count the test methods (we need to use this instead of @AfterClass on teardown() since the latter is
         // useless with pax-exam)
@@ -439,6 +453,30 @@ public class SouthboundIT extends AbstractMdsalTestBase {
         }
     }
 
+    private Boolean getOvsdbTopology() {
+        LOG.info("getOvsdbTopology: looking for {}...", SouthboundUtils.OVSDB_TOPOLOGY_ID.getValue());
+        Boolean found = false;
+        final TopologyId topologyId = SouthboundUtils.OVSDB_TOPOLOGY_ID;
+        InstanceIdentifier<Topology> path =
+                InstanceIdentifier.create(NetworkTopology.class).child(Topology.class, new TopologyKey(topologyId));
+        for (int i = 0; i < 60; i++) {
+            Topology topology = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, path);
+            if (topology != null) {
+                LOG.info("getOvsdbTopology: found {}...", SouthboundUtils.OVSDB_TOPOLOGY_ID.getValue());
+                found = true;
+                break;
+            } else {
+                LOG.info("getOvsdbTopology: still looking ({})...", i);
+                try {
+                    Thread.sleep(1000);
+                } catch (InterruptedException e) {
+                    LOG.warn("Interrupted while waiting for {}", SouthboundUtils.OVSDB_TOPOLOGY_ID.getValue(), e);
+                }
+            }
+        }
+        return found;
+    }
+
     /**
      * Test passive connection mode. The southbound starts in a listening mode waiting for connections on port
      * 6640. This test will wait for incoming connections for {@link SouthboundITConstants#CONNECTION_INIT_TIMEOUT} ms.
@@ -645,6 +683,13 @@ public class SouthboundIT extends AbstractMdsalTestBase {
         assertNotNull(ovsdbNodeAugmentation.getOvsVersion());
     }
 
+    @Test
+    public void testOvsdbNodeDbVersion() throws InterruptedException {
+        OvsdbNodeAugmentation ovsdbNodeAugmentation = ovsdbNode.getAugmentation(OvsdbNodeAugmentation.class);
+        Assert.assertNotNull(ovsdbNodeAugmentation);
+        assertNotNull(ovsdbNodeAugmentation.getDbVersion());
+    }
+
     @Test
     public void testOpenVSwitchOtherConfig() throws InterruptedException {
         OvsdbNodeAugmentation ovsdbNodeAugmentation = ovsdbNode.getAugmentation(OvsdbNodeAugmentation.class);
@@ -838,6 +883,178 @@ public class SouthboundIT extends AbstractMdsalTestBase {
         }
     }
 
+    private static class TestAutoAttach implements AutoCloseable {
+        private final ConnectionInfo connectionInfo;
+        private final Uri autoattachId;
+        private final Uri bridgeId;
+
+        public TestAutoAttach (final ConnectionInfo connectionInfo,
+                final Uri autoattachId,
+                final Uri bridgeId,
+                @Nullable final String systemName,
+                @Nullable final String systemDescription,
+                @Nullable final List<Mappings> mappings,
+                @Nullable final List<AutoattachExternalIds> externalIds) {
+            this.connectionInfo = connectionInfo;
+            this.autoattachId = autoattachId;
+            this.bridgeId = bridgeId;
+
+            Autoattach aaEntry = new AutoattachBuilder()
+                    .setAutoattachId(autoattachId)
+                    .setBridgeId(bridgeId)
+                    .setSystemName(systemName)
+                    .setSystemDescription(systemDescription)
+                    .setMappings(mappings)
+                    .setAutoattachExternalIds(externalIds)
+                    .build();
+            InstanceIdentifier<Autoattach> iid = SouthboundUtils.createInstanceIdentifier(connectionInfo)
+                    .augmentation(OvsdbNodeAugmentation.class)
+                    .child(Autoattach.class, aaEntry.getKey());
+            final NotifyingDataChangeListener aaOperationalListener =
+                    new NotifyingDataChangeListener(LogicalDatastoreType.OPERATIONAL, iid);
+            aaOperationalListener.registerDataChangeListener();
+
+            Assert.assertTrue(mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION, iid, aaEntry));
+            try {
+                aaOperationalListener.waitForCreation(OVSDB_ROUNDTRIP_TIMEOUT);
+            } catch (InterruptedException e) {
+                LOG.warn("Sleep interrupted while waiting for queue {}", iid, e);
+            }
+        }
+        @Override
+        public void close() {
+            final InstanceIdentifier<Autoattach> iid = SouthboundUtils.createInstanceIdentifier(connectionInfo)
+                    .augmentation(OvsdbNodeAugmentation.class)
+                    .child(Autoattach.class, new AutoattachKey(this.autoattachId));
+            final NotifyingDataChangeListener aaOperationalListener =
+                    new NotifyingDataChangeListener(LogicalDatastoreType.OPERATIONAL, iid);
+            aaOperationalListener.registerDataChangeListener();
+
+            Assert.assertTrue(mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION, iid));
+            try {
+                aaOperationalListener.waitForDeletion(OVSDB_ROUNDTRIP_TIMEOUT);
+            } catch (InterruptedException e) {
+                LOG.warn("Sleep interrupted while waiting for qos deletion (qos {})", iid, e);
+            }
+        }
+    }
+
+    @Test
+    public void testCRUDAutoAttach() throws InterruptedException {
+        final boolean isOldSchema = schemaVersion.compareTo(AUTOATTACH_FROM_VERSION) < 0;
+
+        ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portNumber);
+        String testAutoattachId = new String("testAutoattachEntry");
+        String testSystemName = new String("testSystemName");
+        String testSystemDescription = new String("testSystemDescription");
+        String testAutoattachExternalKey = new String("testAutoattachExternalKey");
+        String testAutoattachExternalValue = new String("testAutoattachExternalValue");
+
+        try (TestBridge testBridge = new TestBridge(connectionInfo, SouthboundITConstants.BRIDGE_NAME)) {
+            OvsdbBridgeAugmentation bridge = getBridge(connectionInfo);
+            Assert.assertNotNull(bridge);
+
+            // CREATE: Create Autoattach table
+            NodeId nodeId = SouthboundUtils.createManagedNodeId(SouthboundUtils.createInstanceIdentifier(
+                    connectionInfo, bridge.getBridgeName()));
+            String bridgeId = nodeId.getValue();
+            try(TestAutoAttach testAutoattach = new TestAutoAttach(connectionInfo, new Uri(testAutoattachId),
+                    new Uri(bridgeId), testSystemName, testSystemDescription, null, null)) {
+                // READ: Read md-sal operational datastore to see if the AutoAttach table was created
+                // and if Bridge table was updated with AutoAttach Uuid
+                OvsdbNodeAugmentation ovsdbNodeAugmentation = getOvsdbNode(connectionInfo,
+                        LogicalDatastoreType.OPERATIONAL);
+                Autoattach operAa = getAutoAttach(ovsdbNodeAugmentation, new Uri(testAutoattachId));
+
+                // skip tests after verifying that Autoattach doesn't break with unsupported schema
+                Assume.assumeFalse(isOldSchema);
+
+                // FIXME: Remove once CRUD is supported
+                Assume.assumeFalse(operAa == null);
+
+                Assert.assertNotNull(operAa);
+                Assert.assertEquals(testSystemName, operAa.getSystemName());
+                bridge = getBridge(connectionInfo);
+                Uuid aaUuid = new Uuid(operAa.getAutoattachUuid().getValue());
+                Assert.assertEquals(aaUuid, bridge.getAutoAttach());
+
+                // UPDATE: Update mappings column of AutoAttach table that was created
+                List<Mappings> mappings = ImmutableList.of(new MappingsBuilder().setMappingsKey(100L).setMappingsValue(200).build());
+                Autoattach updatedAa = new AutoattachBuilder()
+                        .setAutoattachId(new Uri(testAutoattachId))
+                        .setMappings(mappings)
+                        .build();
+                InstanceIdentifier<Autoattach> iid = SouthboundUtils.createInstanceIdentifier(connectionInfo)
+                        .augmentation(OvsdbNodeAugmentation.class)
+                        .child(Autoattach.class, updatedAa.getKey());
+                final NotifyingDataChangeListener aaOperationalListener =
+                        new NotifyingDataChangeListener(LogicalDatastoreType.OPERATIONAL, iid);
+                aaOperationalListener.registerDataChangeListener();
+                Assert.assertTrue(mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION, iid, updatedAa));
+                aaOperationalListener.waitForUpdate(OVSDB_UPDATE_TIMEOUT);
+
+                // UPDATE: Update external_ids column of AutoAttach table that was created
+                List<AutoattachExternalIds> externalIds = new ArrayList<>();
+                externalIds.add(new AutoattachExternalIdsBuilder()
+                        .setAutoattachExternalIdKey(testAutoattachExternalKey)
+                        .setAutoattachExternalIdValue(testAutoattachExternalValue)
+                        .build());
+                updatedAa = new AutoattachBuilder()
+                        .setAutoattachId(new Uri(testAutoattachId))
+                        .setAutoattachExternalIds(externalIds)
+                        .build();
+                Assert.assertTrue(mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION, iid, updatedAa));
+                aaOperationalListener.waitForUpdate(OVSDB_UPDATE_TIMEOUT);
+
+                // READ: Read the updated AutoAttach table for latest mappings and external_ids column value
+                ovsdbNodeAugmentation = getOvsdbNode(connectionInfo,
+                        LogicalDatastoreType.OPERATIONAL);
+                operAa = getAutoAttach(ovsdbNodeAugmentation, new Uri(testAutoattachId));
+                Assert.assertNotNull(operAa);
+                List<Mappings> operMappingsList = operAa.getMappings();
+                for (Mappings operMappings: operMappingsList) {
+                    Assert.assertEquals(mappings.get(operMappingsList.indexOf(operMappings)).getMappingsKey(), operMappings.getMappingsKey());
+                    Assert.assertEquals(mappings.get(operMappingsList.indexOf(operMappings)).getMappingsValue(), operMappings.getMappingsValue());
+                }
+                List<AutoattachExternalIds> operExternalIds = operAa.getAutoattachExternalIds();
+                externalIds.add(new AutoattachExternalIdsBuilder()
+                        .setAutoattachExternalIdKey(SouthboundConstants.AUTOATTACH_ID_EXTERNAL_ID_KEY)
+                        .setAutoattachExternalIdValue(operAa.getAutoattachId().getValue())
+                        .build());
+                for (AutoattachExternalIds operExternalId : operExternalIds) {
+                    Assert.assertEquals(externalIds.get(operExternalIds.indexOf(operExternalId)).getAutoattachExternalIdKey(),
+                            operExternalId.getAutoattachExternalIdKey());
+                    Assert.assertEquals(externalIds.get(operExternalIds.indexOf(operExternalId)).getAutoattachExternalIdValue(),
+                            operExternalId.getAutoattachExternalIdValue());
+                }
+
+                // DELETE: Delete AutoAttach table
+                Assert.assertTrue(mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION, iid));
+                aaOperationalListener.waitForUpdate(OVSDB_UPDATE_TIMEOUT);
+                ovsdbNodeAugmentation = getOvsdbNode(connectionInfo,
+                        LogicalDatastoreType.OPERATIONAL);
+                operAa = getAutoAttach(ovsdbNodeAugmentation, new Uri(testAutoattachId));
+                Assert.assertNull(operAa);
+            } catch (AssumptionViolatedException e) {
+                LOG.warn("Skipped test for Autoattach due to unsupported schema", e);
+            } catch (Exception e) {
+                fail("Unexpected exception in CRUD test for Autoattach table for schema:" + schemaVersion.toString() +". " + e);
+            }
+        }
+    }
+
+    private Autoattach getAutoAttach(OvsdbNodeAugmentation ovsdbNodeAugmentation, Uri uri) {
+        if (ovsdbNodeAugmentation.getAutoattach() != null
+                && !ovsdbNodeAugmentation.getAutoattach().isEmpty()) {
+            for (Autoattach aa : ovsdbNodeAugmentation.getAutoattach()) {
+                if (aa.getKey().getAutoattachId().equals(uri)) {
+                    return aa;
+                }
+            }
+        }
+        return null;
+    }
+
     private static class TestQos implements AutoCloseable {
         private final ConnectionInfo connectionInfo;
         private final Uri qosId;
@@ -1071,6 +1288,45 @@ public class SouthboundIT extends AbstractMdsalTestBase {
         return tpList.get(index).getAugmentation(OvsdbTerminationPointAugmentation.class);
     }
 
+    @Test
+    public void testCRUDTerminationPointIfIndex() throws InterruptedException {
+        final boolean isOldSchema = schemaVersion.compareTo(IF_INDEX_FROM_VERSION) < 0;
+        Assume.assumeFalse(isOldSchema);
+        ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portNumber);
+
+        // Test create ifIndex
+        try (TestBridge testBridge = new TestBridge(connectionInfo, null, SouthboundITConstants.BRIDGE_NAME, null, true,
+                SouthboundConstants.OVSDB_FAIL_MODE_MAP.inverse().get("secure"),
+                true, SouthboundMapper.createDatapathType("netdev"), null, null, null)) {
+            OvsdbBridgeAugmentation bridge = getBridge(connectionInfo);
+            Assert.assertNotNull(bridge);
+            LOG.info("bridge: {}", bridge);
+            NodeId nodeId = SouthboundMapper.createManagedNodeId(SouthboundUtils.createInstanceIdentifier(
+                    connectionInfo, bridge.getBridgeName()));
+            OvsdbTerminationPointAugmentationBuilder ovsdbTerminationBuilder =
+                    createGenericOvsdbTerminationPointAugmentationBuilder();
+            String portName = "testIfIndex";
+            ovsdbTerminationBuilder.setName(portName);
+
+            Assert.assertTrue(addTerminationPoint(nodeId, portName, ovsdbTerminationBuilder));
+            InstanceIdentifier<Node> terminationPointIid = getTpIid(connectionInfo, bridge);
+            Node terminationPointNode = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, terminationPointIid);
+            Assert.assertNotNull(terminationPointNode);
+
+            // Test read ifIndex
+            List<TerminationPoint> terminationPoints = terminationPointNode.getTerminationPoint();
+            for (TerminationPoint terminationPoint : terminationPoints) {
+                OvsdbTerminationPointAugmentation ovsdbTerminationPointAugmentation =
+                        terminationPoint.getAugmentation(OvsdbTerminationPointAugmentation.class);
+                if (ovsdbTerminationPointAugmentation.getName().equals(portName)) {
+                    Long ifIndex = ovsdbTerminationPointAugmentation.getIfindex();
+                    Assert.assertNotNull(ifIndex);
+                    LOG.info("ifIndex: {} for the port:{}", ifIndex, portName);
+                }
+            }
+        }
+    }
+
     @Test
     public void testCRDTerminationPointOfPort() throws InterruptedException {
         final Long OFPORT_EXPECTED = 45002L;
@@ -1346,6 +1602,89 @@ public class SouthboundIT extends AbstractMdsalTestBase {
                 new PortOtherConfigsSouthboundHelper());
     }
 
+    @Test
+    public void testCRUDTerminationPoints() throws InterruptedException {
+        String port1 = "vx1";
+        String port2 = "vxlanport";
+        ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portNumber);
+
+        try (TestBridge testBridge = new TestBridge(connectionInfo, SouthboundITConstants.BRIDGE_NAME)) {
+            OvsdbBridgeAugmentation bridge = getBridge(connectionInfo, SouthboundITConstants.BRIDGE_NAME);
+            Assert.assertNotNull(bridge);
+            NodeId nodeId = SouthboundUtils.createManagedNodeId(SouthboundUtils.createInstanceIdentifier(
+                    connectionInfo, bridge.getBridgeName()));
+            OvsdbTerminationPointAugmentationBuilder ovsdbTerminationBuilder =
+                    createGenericOvsdbTerminationPointAugmentationBuilder();
+
+            // add and delete a single port
+            String portName = port1;
+            ovsdbTerminationBuilder.setName(portName);
+            Assert.assertTrue(addTerminationPoint(nodeId, portName, ovsdbTerminationBuilder));
+            InstanceIdentifier<Node> terminationPointIid = getTpIid(connectionInfo, bridge);
+            Node terminationPointNode = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, terminationPointIid);
+            Assert.assertNotNull(terminationPointNode);
+
+            SouthboundUtils.createInstanceIdentifier(connectionInfo,
+                    new OvsdbBridgeName(SouthboundITConstants.BRIDGE_NAME));
+            portName = port1;
+            InstanceIdentifier<TerminationPoint> nodePath =
+                    SouthboundUtils.createInstanceIdentifier(connectionInfo,
+                            new OvsdbBridgeName(SouthboundITConstants.BRIDGE_NAME))
+                            .child(TerminationPoint.class, new TerminationPointKey(new TpId(portName)));
+
+            Assert.assertTrue("failed to delete port " + portName,
+                    mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION, nodePath));
+            LOG.info("shague: waiting for delete {}", portName);
+            Thread.sleep(1000);
+            TerminationPoint terminationPoint = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, nodePath);
+            Assert.assertNull(terminationPoint);
+
+            // add two ports, then delete them
+            portName = port1;
+            ovsdbTerminationBuilder.setName(portName);
+            Assert.assertTrue(addTerminationPoint(nodeId, portName, ovsdbTerminationBuilder));
+            terminationPointIid = getTpIid(connectionInfo, bridge);
+            terminationPointNode = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, terminationPointIid);
+            Assert.assertNotNull(terminationPointNode);
+
+            portName = port2;
+            ovsdbTerminationBuilder.setName(portName);
+            Assert.assertTrue(addTerminationPoint(nodeId, portName, ovsdbTerminationBuilder));
+            terminationPointIid = getTpIid(connectionInfo, bridge);
+            terminationPointNode = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, terminationPointIid);
+            Assert.assertNotNull(terminationPointNode);
+
+            SouthboundUtils.createInstanceIdentifier(connectionInfo,
+                    new OvsdbBridgeName(SouthboundITConstants.BRIDGE_NAME));
+            portName = port1;
+            nodePath =
+                    SouthboundUtils.createInstanceIdentifier(connectionInfo,
+                            new OvsdbBridgeName(SouthboundITConstants.BRIDGE_NAME))
+                            .child(TerminationPoint.class, new TerminationPointKey(new TpId(portName)));
+
+            Assert.assertTrue("failed to delete port " + portName,
+                    mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION, nodePath));
+            LOG.info("shague: waiting for delete {}", portName);
+            Thread.sleep(1000);
+            terminationPoint = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, nodePath);
+            Assert.assertNull(terminationPoint);
+
+            portName = port2;
+            nodePath = SouthboundUtils.createInstanceIdentifier(connectionInfo,
+                    new OvsdbBridgeName(SouthboundITConstants.BRIDGE_NAME))
+                    .child(TerminationPoint.class, new TerminationPointKey(new TpId(portName)));
+
+            Assert.assertTrue("failed to delete port " + portName,
+                    mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION, nodePath));
+            LOG.info("shague: waiting for delete {}", portName);
+            Thread.sleep(1000);
+            terminationPoint = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, nodePath);
+            Assert.assertNull(terminationPoint);
+
+            // DELETE handled by TestBridge
+        }
+    }
+
     @Test
     public void testCRUDTerminationPointVlan() throws InterruptedException {
         final Integer CREATED_VLAN_ID = 4000;
@@ -1836,7 +2175,7 @@ public class SouthboundIT extends AbstractMdsalTestBase {
 
     private Queues getQueue(Uri queueId, OvsdbNodeAugmentation node) {
         for (Queues queue : node.getQueues()) {
-            if (queue.getKey().getQueueId().equals(queueId))
+            if (queue.getKey().getQueueId().getValue().equals(queueId.getValue()))
                 return queue;
         }
         return null;
@@ -2170,7 +2509,7 @@ public class SouthboundIT extends AbstractMdsalTestBase {
             List<QueueList> operQueueList = operQos.getQueueList();
             Assert.assertNotNull(operQueueList);
             for (QueueList queueEntry : queueList) {
-                Assert.assertTrue(operQueueList.contains(queueEntry));
+                Assert.assertTrue(isQueueInList(operQueueList, queueEntry));
             }
 
             // DELETE one queue from queue list and check that one remains
@@ -2188,10 +2527,10 @@ public class SouthboundIT extends AbstractMdsalTestBase {
             operQueueList = operQos.getQueueList();
             Assert.assertNotNull(operQueueList);
             for (QueueList queueEntry : queueList) {
-                if (queueEntry.getQueueUuid().equals(queue2Uuid))
-                    Assert.assertTrue(operQueueList.contains(queueEntry));
-                else if (queueEntry.getQueueUuid().equals(queue1Uuid)) {
-                    Assert.assertFalse(operQueueList.contains(queueEntry));
+                if (queueEntry.getQueueUuid().equals(queue2Uuid)) {
+                    Assert.assertTrue(isQueueInList(operQueueList, queueEntry));
+                else if (queueEntry.getQueueUuid().equals(queue1Uuid)) {
+                    Assert.assertFalse(isQueueInList(operQueueList, queueEntry));
                 } else {
                     Assert.assertTrue("Unknown queue entry in qos queue list", false);
                 }
@@ -2213,6 +2552,16 @@ public class SouthboundIT extends AbstractMdsalTestBase {
         }
     }
 
+    private Boolean isQueueInList(List<QueueList> queueList, QueueList queue) {
+        for (QueueList queueEntry : queueList) {
+            if (queueEntry.getQueueNumber().equals(queue.getQueueNumber())
+                && queueEntry.getQueueUuid().equals(queue.getQueueUuid())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     /**
      * <p>
      * Representation of a southbound test case. Each test case has a name, a list of input values and a list of