Added more ITs to hwvtep 73/31973/1
authorVishal Thapar <vishal.thapar@ericsson.com>
Thu, 24 Dec 2015 08:58:59 +0000 (14:28 +0530)
committerVishal Thapar <vishal.thapar@ericsson.com>
Thu, 31 Dec 2015 14:50:06 +0000 (20:20 +0530)
Adds following tests and required utils code:
1. testHwvtepNodeConnectDisconnect
2. testAddDeletePhysicalSwitch

Fixes issues found while writing and running ITs

Change-Id: Ia1b4bb03e228dd16c7b01dedc0ef1a4b3d3ea256
Signed-off-by: Vishal Thapar <vishal.thapar@ericsson.com>
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepSouthboundConstants.java
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/HwvtepSouthboundMapper.java
hwvtepsouthbound/hwvtepsouthbound-impl/src/main/java/org/opendaylight/ovsdb/hwvtepsouthbound/transact/HwvtepOperationalState.java
hwvtepsouthbound/hwvtepsouthbound-it/src/test/java/org/opendaylight/ovsdb/hwvtepsouthbound/it/HwvtepSouthboundIT.java
utils/hwvtepsouthbound-utils/src/main/java/org/opendaylight/ovsdb/utils/hwvtepsouthbound/utils/HwvtepSouthboundUtils.java

index 41d4c72bbbbd2a818a51161893879f9d42a9938a..5ede8be68e7af83413880a645e861e11f6338403 100644 (file)
@@ -20,6 +20,7 @@ public class HwvtepSouthboundConstants {
 
     public static final TopologyId HWVTEP_TOPOLOGY_ID = new TopologyId(new Uri("hwvtep:1"));
     public static final String HWVTEP_URI_PREFIX = "hwvtep";
+    public static final String PSWITCH_URI_PREFIX = "physicalswitch";
     public static final Integer DEFAULT_OVSDB_PORT = 6640;
     public static final String IID_OTHER_CONFIG_KEY = "opendaylight-iid";
     public static final String UUID = "uuid";
index cf0cd7a576e0971236c0b6b571fd87f034fdbbef..8cc989c22bc73ff3d3d7b6a8d00c8d7790da4ece 100644 (file)
@@ -79,7 +79,7 @@ public class HwvtepSouthboundMapper {
     }
 
     public static NodeId createManagedNodeId(InstanceIdentifier<Node> iid) {
-        NodeKey nodeKey = iid.firstKeyOf(Node.class, NodeKey.class);
+        NodeKey nodeKey = iid.firstKeyOf(Node.class);
         return nodeKey.getNodeId();
     }
 
@@ -143,14 +143,25 @@ public class HwvtepSouthboundMapper {
 
     public static InstanceIdentifier<Node> createInstanceIdentifier(HwvtepConnectionInstance client,
                     PhysicalSwitch pSwitch) {
-        String nodeString = client.getNodeKey().getNodeId().getValue() + "/physicalswitch/" + pSwitch.getName();
-        NodeId nodeId = new NodeId(new Uri(nodeString));
-        NodeKey nodeKey = new NodeKey(nodeId);
+        //TODO: Clean this up
+        return createInstanceIdentifier(client, new HwvtepNodeName(pSwitch.getName()));
+    }
+
+    public static InstanceIdentifier<Node> createInstanceIdentifier(HwvtepConnectionInstance client,
+                    HwvtepNodeName psName) {
+        NodeKey nodeKey = new NodeKey(createManagedNodeId(client, psName));
         return InstanceIdentifier.builder(NetworkTopology.class)
                         .child(Topology.class, new TopologyKey(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID))
                         .child(Node.class, nodeKey).build();
     }
 
+    public static NodeId createManagedNodeId(HwvtepConnectionInstance client, HwvtepNodeName psName) {
+        String nodeString = client.getNodeKey().getNodeId().getValue()
+                        + "/" + HwvtepSouthboundConstants.PSWITCH_URI_PREFIX + "/" + psName.getValue();
+        NodeId nodeId = new NodeId(new Uri(nodeString));
+        return nodeId;
+    }
+
     public static InstanceIdentifier<LogicalSwitches> createInstanceIdentifier(HwvtepConnectionInstance client,
                     LogicalSwitch lSwitch) {
         InstanceIdentifier<LogicalSwitches> iid = null;
index 58de15991d663c11c22c9f62bf575f5c7785779f..0e31fb09d63b451aa7af6d2552bb0227a57d3cdc 100644 (file)
@@ -67,7 +67,7 @@ public class HwvtepOperationalState {
                     operationalNodes.put(entry.getKey(), readNode.get());
                     HwvtepGlobalAugmentation hgAugmentation = readNode.get().getAugmentation(HwvtepGlobalAugmentation.class);
                     PhysicalSwitchAugmentation psAugmentation = readNode.get().getAugmentation(PhysicalSwitchAugmentation.class);
-                    if (hgAugmentation != null) {
+                    if (hgAugmentation != null && hgAugmentation.getSwitches() != null) {
                         for (Switches pswitch : hgAugmentation.getSwitches()) {
                             @SuppressWarnings("unchecked")
                             InstanceIdentifier<Node> psNodeIid = (InstanceIdentifier<Node>) pswitch.getSwitchRef().getValue();
index 58e5d406d5c8c08d9d2a862e58ca90ac4dcf6bbf..cfeb8e0bd0014a2167307c6685a9c6df3ccd9c64 100644 (file)
@@ -7,14 +7,24 @@
  */
 package org.opendaylight.ovsdb.hwvtepsouthbound.it;
 
+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.vmOption;
 import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.editConfigurationFilePut;
+import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.keepRuntimeFolder;
 
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Method;
-import java.util.concurrent.atomic.AtomicBoolean;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Collection;
+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;
@@ -24,15 +34,36 @@ import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.mdsal.it.base.AbstractMdsalTestBase;
 import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundConstants;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundMapper;
 import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundProvider;
+import org.opendaylight.ovsdb.utils.hwvtepsouthbound.utils.HwvtepSouthboundUtils;
 import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
+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.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalRef;
+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.PhysicalSwitchAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.PhysicalSwitchAugmentationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.ConnectionInfo;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.ConnectionInfoBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.ManagementIps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.TunnelIps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.Tunnels;
 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.yangtools.yang.binding.InstanceIdentifier;
+import org.ops4j.pax.exam.Configuration;
 import org.ops4j.pax.exam.Option;
 import org.ops4j.pax.exam.junit.PaxExam;
 import org.ops4j.pax.exam.karaf.options.LogLevelOption.LogLevel;
@@ -48,13 +79,107 @@ import org.slf4j.LoggerFactory;
 public class HwvtepSouthboundIT extends AbstractMdsalTestBase {
     private static final Logger LOG = LoggerFactory.getLogger(HwvtepSouthboundIT.class);
 
+    //Constants
+
+    public static final String ORG_OPS4J_PAX_LOGGING_CFG = "etc/org.ops4j.pax.logging.cfg";
+    public static final String CUSTOM_PROPERTIES = "etc/custom.properties";
+    public static final String SERVER_IPADDRESS = "ovsdbserver.ipaddress";
+    public static final String DEFAULT_SERVER_IPADDRESS = "127.0.0.1";
+    public static final String SERVER_PORT = "ovsdbserver.port";
+    public static final String DEFAULT_SERVER_PORT = "6640";
+    public static final String CONNECTION_TYPE = "ovsdbserver.connection";
+    public static final String CONNECTION_TYPE_ACTIVE = "active";
+    public static final String CONNECTION_TYPE_PASSIVE = "passive";
+    public static final int CONNECTION_INIT_TIMEOUT = 10000;
+    public static final String OPENFLOW_CONNECTION_PROTOCOL = "tcp";
+    private static final String PS_NAME = "ps0";
+
+    private static final int OVSDB_UPDATE_TIMEOUT = 1000;
+    private static final int OVSDB_ROUNDTRIP_TIMEOUT = 10000;
+
     private static MdsalUtils mdsalUtils = null;
     private static boolean setup = false;
     private static int testMethodsRemaining;
+    private static String addressStr;
+    private static int portNumber;
+    private static String connectionType;
+    private static Node hwvtepNode;
 
     @Inject
     private BundleContext bundleContext;
 
+    private static final NotifyingDataChangeListener OPERATIONAL_LISTENER =
+            new NotifyingDataChangeListener(LogicalDatastoreType.OPERATIONAL);
+
+    private static class NotifyingDataChangeListener implements DataTreeChangeListener<Node> {
+        private final LogicalDatastoreType type;
+        private final Set<InstanceIdentifier<Node>> createdNodes = new HashSet<>();
+        private final Set<InstanceIdentifier<Node>> removedNodes = new HashSet<>();
+        private final Set<InstanceIdentifier<Node>> updatedNodes = new HashSet<>();
+
+        private NotifyingDataChangeListener(LogicalDatastoreType type) {
+            this.type = type;
+        }
+
+        @Override
+        public void onDataTreeChanged(Collection<DataTreeModification<Node>> changes) {
+            for (DataTreeModification<Node> change : changes) {
+                final InstanceIdentifier<Node> key = change.getRootPath().getRootIdentifier();
+                final DataObjectModification<Node> mod = change.getRootNode();
+                    switch (mod.getModificationType()) {
+                    case DELETE:
+                        removedNodes.add(key);
+                        break;
+                    case SUBTREE_MODIFIED:
+                        updatedNodes.add(key);
+                        break;
+                    case WRITE:
+                        if (mod.getDataBefore() == null) {
+                            LOG.trace("Data added: {}", mod.getDataAfter());
+                            createdNodes.add(key);
+                        } else {
+                            updatedNodes.add(key);
+                        }
+                        break;
+                    default:
+                        throw new IllegalArgumentException("Unhandled modification type " + mod.getModificationType());
+                    }
+            }
+        }
+
+        public boolean isCreated(InstanceIdentifier<Node> iid) {
+            return createdNodes.remove(iid);
+        }
+
+        public boolean isRemoved(InstanceIdentifier<Node> iid) {
+            return removedNodes.remove(iid);
+        }
+
+        public boolean isUpdated(InstanceIdentifier<Node> iid) {
+            return updatedNodes.remove(iid);
+        }
+    }
+
+    @Configuration
+    public Option[] config() {
+        Option[] options = super.config();
+        Option[] propertyOptions = getPropertiesOptions();
+        Option[] otherOptions = getOtherOptions();
+        Option[] combinedOptions = new Option[options.length + propertyOptions.length + otherOptions.length];
+        System.arraycopy(options, 0, combinedOptions, 0, options.length);
+        System.arraycopy(propertyOptions, 0, combinedOptions, options.length, propertyOptions.length);
+        System.arraycopy(otherOptions, 0, combinedOptions, options.length + propertyOptions.length,
+                otherOptions.length);
+        return combinedOptions;
+    }
+
+    private Option[] getOtherOptions() {
+        return new Option[] {
+                vmOption("-javaagent:../jars/org.jacoco.agent.jar=destfile=../../jacoco-it.exec"),
+                keepRuntimeFolder()
+        };
+    }
+
     @Override
     public String getModuleName() {
         return "hwvtepsouthbound";
@@ -99,6 +224,28 @@ public class HwvtepSouthboundIT extends AbstractMdsalTestBase {
                 .getURL();
     }
 
+    protected String usage() {
+        return "Integration Test needs a valid connection configuration as follows :\n"
+                + "active connection : mvn -Dovsdbserver.ipaddress=x.x.x.x -Dovsdbserver.port=yyyy verify\n"
+                + "passive connection : mvn -Dovsdbserver.connection=passive verify\n";
+    }
+
+    private Option[] getPropertiesOptions() {
+        Properties props = new Properties(System.getProperties());
+        String addressStr = props.getProperty(SERVER_IPADDRESS, DEFAULT_SERVER_IPADDRESS);
+        String portStr = props.getProperty(SERVER_PORT, DEFAULT_SERVER_PORT);
+        String connectionType = props.getProperty(CONNECTION_TYPE, CONNECTION_TYPE_ACTIVE);
+
+        LOG.info("getPropertiesOptions: Using the following properties: mode= {}, ip:port= {}:{}",
+                connectionType, addressStr, portStr);
+
+        return new Option[] {
+                editConfigurationFilePut(CUSTOM_PROPERTIES, SERVER_IPADDRESS, addressStr),
+                editConfigurationFilePut(CUSTOM_PROPERTIES, SERVER_PORT, portStr),
+                editConfigurationFilePut(CUSTOM_PROPERTIES, CONNECTION_TYPE, connectionType),
+        };
+    }
+
     @Before
     @Override
     public void setup() throws InterruptedException {
@@ -117,9 +264,33 @@ public class HwvtepSouthboundIT extends AbstractMdsalTestBase {
         DataBroker dataBroker = HwvtepSouthboundProvider.getDb();
         Assert.assertNotNull("db should not be null", dataBroker);
 
+        addressStr = bundleContext.getProperty(SERVER_IPADDRESS);
+        String portStr = bundleContext.getProperty(SERVER_PORT);
+        try {
+            portNumber = Integer.parseInt(portStr);
+        } catch (NumberFormatException e) {
+            fail("Invalid port number " + portStr + System.lineSeparator() + usage());
+        }
+
+        connectionType = bundleContext.getProperty(CONNECTION_TYPE);
+
+        LOG.info("setUp: Using the following properties: mode= {}, ip:port= {}:{}",
+                connectionType, addressStr, portNumber);
+        if (connectionType.equalsIgnoreCase(CONNECTION_TYPE_ACTIVE)) {
+            if (addressStr == null) {
+                fail(usage());
+            }
+        }
 
         mdsalUtils = new MdsalUtils(dataBroker);
+        final ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portNumber);
+        final InstanceIdentifier<Node> iid = HwvtepSouthboundUtils.createInstanceIdentifier(connectionInfo);
+        final DataTreeIdentifier<Node> treeId =
+                        new DataTreeIdentifier<Node>(LogicalDatastoreType.OPERATIONAL, iid);
+
+        dataBroker.registerDataTreeChangeListener(treeId, OPERATIONAL_LISTENER);
 
+        hwvtepNode = connectHwvtepNode(connectionInfo);
         // Let's count the test methods (we need to use this instead of @AfterClass on teardown() since the latter is
         // useless with pax-exam)
         for (Method method : getClass().getMethods()) {
@@ -142,6 +313,130 @@ public class HwvtepSouthboundIT extends AbstractMdsalTestBase {
         setup = true;
     }
 
+    private Node connectHwvtepNode(ConnectionInfo connectionInfo) throws InterruptedException {
+        final InstanceIdentifier<Node> iid = HwvtepSouthboundUtils.createInstanceIdentifier(connectionInfo);
+        Assert.assertTrue(mdsalUtils.put(LogicalDatastoreType.CONFIGURATION,
+                        iid, HwvtepSouthboundUtils.createNode(connectionInfo)));
+        waitForOperationalCreation(iid);
+        Node node = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, iid);
+        Assert.assertNotNull(node);
+        LOG.info("Connected to {}", HwvtepSouthboundUtils.connectionInfoToString(connectionInfo));
+        return node;
+    }
+
+    private static void disconnectHwvtepNode(final ConnectionInfo connectionInfo) throws InterruptedException {
+        final InstanceIdentifier<Node> iid = HwvtepSouthboundUtils.createInstanceIdentifier(connectionInfo);
+        Assert.assertTrue(mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION, iid));
+        waitForOperationalDeletion(iid);
+        Node node = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, iid);
+        Assert.assertNull(node);
+        LOG.info("Disconnected from {}", HwvtepSouthboundUtils.connectionInfoToString(connectionInfo));
+    }
+
+    private void waitForOperationalCreation(InstanceIdentifier<Node> iid) throws InterruptedException {
+        synchronized (OPERATIONAL_LISTENER) {
+            long _start = System.currentTimeMillis();
+            LOG.info("Waiting for OPERATIONAL DataChanged creation on {}", iid);
+            while (!OPERATIONAL_LISTENER.isCreated(
+                    iid) && (System.currentTimeMillis() - _start) < OVSDB_ROUNDTRIP_TIMEOUT) {
+                OPERATIONAL_LISTENER.wait(OVSDB_UPDATE_TIMEOUT);
+            }
+            LOG.info("Woke up, waited {} for creation of {}", (System.currentTimeMillis() - _start), iid);
+        }
+    }
+
+    private static void waitForOperationalDeletion(InstanceIdentifier<Node> iid) throws InterruptedException {
+        synchronized (OPERATIONAL_LISTENER) {
+            long _start = System.currentTimeMillis();
+            LOG.info("Waiting for OPERATIONAL DataChanged deletion on {}", iid);
+            while (!OPERATIONAL_LISTENER.isRemoved(
+                    iid) && (System.currentTimeMillis() - _start) < OVSDB_ROUNDTRIP_TIMEOUT) {
+                OPERATIONAL_LISTENER.wait(OVSDB_UPDATE_TIMEOUT);
+            }
+            LOG.info("Woke up, waited {} for deletion of {}", (System.currentTimeMillis() - _start), iid);
+        }
+    }
+
+    private ConnectionInfo getConnectionInfo(String addressStr, int portNumber) {
+        InetAddress inetAddress = null;
+        try {
+            inetAddress = InetAddress.getByName(addressStr);
+        } catch (UnknownHostException e) {
+            fail("Could not resolve " + addressStr + ": " + e);
+        }
+
+        IpAddress address = HwvtepSouthboundMapper.createIpAddress(inetAddress);
+        PortNumber port = new PortNumber(portNumber);
+
+        final ConnectionInfo connectionInfo = new ConnectionInfoBuilder()
+                .setRemoteIp(address)
+                .setRemotePort(port)
+                .build();
+        LOG.info("connectionInfo: {}", connectionInfo);
+        return connectionInfo;
+    }
+
+    private static class TestPhysicalSwitch implements AutoCloseable {
+        private final ConnectionInfo connectionInfo;
+        private final String psName;
+
+
+        public TestPhysicalSwitch(final ConnectionInfo connectionInfo, String psName) {
+            this(connectionInfo, psName, null, null, null, true, null, null, null);
+        }
+
+        public TestPhysicalSwitch (final ConnectionInfo connectionInfo, final String name,
+                        @Nullable InstanceIdentifier<Node> psIid, @Nullable NodeId psNodeId,
+                        @Nullable final String description, final boolean setManagedBy,
+                        @Nullable final List<ManagementIps> managementIps,
+                        @Nullable final List<TunnelIps> tunnelIps,
+                        @Nullable final List<Tunnels> tunnels) {
+            this.connectionInfo = connectionInfo;
+            this.psName = name;
+            NodeBuilder psNodeBuilder = new NodeBuilder();
+            if(psIid == null) {
+                psIid = HwvtepSouthboundUtils.createInstanceIdentifier(connectionInfo, new HwvtepNodeName(psName));
+            }
+            if(psNodeId == null) {
+                psNodeId = HwvtepSouthboundMapper.createManagedNodeId(psIid);
+            }
+            psNodeBuilder.setNodeId(psNodeId);
+            PhysicalSwitchAugmentationBuilder psAugBuilder = new PhysicalSwitchAugmentationBuilder();
+            psAugBuilder.setHwvtepNodeName(new HwvtepNodeName(psName));
+            if(description != null) {
+                psAugBuilder.setHwvtepNodeDescription(description);
+            }
+            if(setManagedBy) {
+                InstanceIdentifier<Node> nodePath = HwvtepSouthboundUtils.createInstanceIdentifier(connectionInfo);
+                psAugBuilder.setManagedBy(new HwvtepGlobalRef(nodePath));
+            }
+            psAugBuilder.setManagementIps(managementIps);
+            psAugBuilder.setTunnelIps(tunnelIps);
+            psAugBuilder.setTunnels(tunnels);
+            psNodeBuilder.addAugmentation(PhysicalSwitchAugmentation.class, psAugBuilder.build());
+            LOG.debug("Built with intent to store PhysicalSwitch data {}", psAugBuilder.toString());
+            Assert.assertTrue(
+                            mdsalUtils.merge(LogicalDatastoreType.CONFIGURATION, psIid, psNodeBuilder.build()));
+                    try {
+                        Thread.sleep(OVSDB_UPDATE_TIMEOUT);
+                    } catch (InterruptedException e) {
+                        LOG.warn("Sleep interrupted while waiting for bridge creation (bridge {})", psName, e);
+                    }
+        }
+
+        @Override
+        public void close() {
+            final InstanceIdentifier<Node> iid =
+                            HwvtepSouthboundUtils.createInstanceIdentifier(connectionInfo, new HwvtepNodeName(psName));
+            Assert.assertTrue(mdsalUtils.delete(LogicalDatastoreType.CONFIGURATION, iid));
+            try {
+                Thread.sleep(OVSDB_UPDATE_TIMEOUT);
+            } catch (InterruptedException e) {
+                LOG.warn("Sleep interrupted while waiting for bridge deletion (bridge {})", psName, e);
+            }
+        }
+    }
+
     @After
     public void teardown() {
         testMethodsRemaining--;
@@ -182,4 +477,46 @@ public class HwvtepSouthboundIT extends AbstractMdsalTestBase {
                 topology);
     }
 
+    @Test
+    public void testAddDeleteHwvtepNode() throws InterruptedException {
+        ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portNumber);
+        // At this point we're connected, disconnect and reconnect (the connection will be removed at the very end)
+        disconnectHwvtepNode(connectionInfo);
+        connectHwvtepNode(connectionInfo);
+    }
+
+    @Test
+    public void testAddDeletePhysicalSwitch() throws InterruptedException {
+        ConnectionInfo connectionInfo = getConnectionInfo(addressStr, portNumber);
+
+        try (TestPhysicalSwitch testPSwitch = new TestPhysicalSwitch(connectionInfo, PS_NAME)) {
+            PhysicalSwitchAugmentation pSwitch = getPhysicalSwitch(connectionInfo);
+            Assert.assertNotNull(pSwitch);
+            LOG.info("PhysicalSwitch: {}", pSwitch);
+        }
+    }
+
+    private PhysicalSwitchAugmentation getPhysicalSwitch(ConnectionInfo connectionInfo) {
+        return getPhysicalSwitch(connectionInfo, PS_NAME);
+    }
+
+    private PhysicalSwitchAugmentation getPhysicalSwitch(ConnectionInfo connectionInfo, String psName) {
+        return getPhysicalSwitch(connectionInfo, psName, LogicalDatastoreType.OPERATIONAL);
+    }
+
+    private PhysicalSwitchAugmentation getPhysicalSwitch(ConnectionInfo connectionInfo, String psName,
+                    LogicalDatastoreType dataStore) {
+        Node psNode = getPhysicalSwitchNode(connectionInfo, psName, dataStore);
+        Assert.assertNotNull(psNode);
+        PhysicalSwitchAugmentation psAugmentation = psNode.getAugmentation(PhysicalSwitchAugmentation.class);
+        Assert.assertNotNull(psAugmentation);
+        return psAugmentation;
+    }
+
+    private Node getPhysicalSwitchNode(ConnectionInfo connectionInfo, String psName, LogicalDatastoreType dataStore) {
+        InstanceIdentifier<Node> psIid =
+                        HwvtepSouthboundUtils.createInstanceIdentifier(connectionInfo, new HwvtepNodeName(psName));
+                return mdsalUtils.read(dataStore, psIid);
+    }
+
 }
index 516baf18b832ab617f5f36c6f32fe75416cc7065..21f3d8d84e2a318bca36d3c862973c0d6cb5507a 100644 (file)
@@ -9,12 +9,14 @@
 package org.opendaylight.ovsdb.utils.hwvtepsouthbound.utils;
 
 import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundConstants;
+import org.opendaylight.ovsdb.hwvtepsouthbound.HwvtepSouthboundMapper;
 import org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils;
 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.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.hwvtep.global.attributes.ConnectionInfo;
 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;
@@ -23,7 +25,6 @@ import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.
 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.yangtools.yang.binding.Augmentation;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -70,8 +71,28 @@ public class HwvtepSouthboundUtils {
         return path;
     }
 
+    public static InstanceIdentifier<Node> createInstanceIdentifier(ConnectionInfo key, HwvtepNodeName name) {
+        return HwvtepSouthboundMapper.createInstanceIdentifier(
+                        createManagedNodeId(key, name));
+    }
+
+    private static NodeId createManagedNodeId(ConnectionInfo key, HwvtepNodeName nodeName) {
+        return createManagedNodeId(key.getRemoteIp(), key.getRemotePort(), nodeName);
+    }
+
+    private static NodeId createManagedNodeId(IpAddress remoteIp, PortNumber remotePort, HwvtepNodeName nodeName) {
+        //This assumes that HwvtepNode can only be Physical switch
+        return new NodeId(createNodeId(remoteIp,remotePort).getValue()
+                        + "/" + HwvtepSouthboundConstants.PSWITCH_URI_PREFIX + "/" + nodeName.getValue());
+    }
+
     public static NodeKey createNodeKey(IpAddress ip, PortNumber port) {
         return new NodeKey(createNodeId(ip, port));
     }
 
+    public static Object connectionInfoToString(ConnectionInfo connectionInfo) {
+        return String.valueOf(
+                        connectionInfo.getRemoteIp().getValue()) + ":" + connectionInfo.getRemotePort().getValue();
+    }
+
 }