Merge "[SDFAB-506] Add QoS test for on edge ports with GTP encapped traffic"
diff --git a/TestON/drivers/common/api/deepinsightapidriver.py b/TestON/drivers/common/api/deepinsightapidriver.py
new file mode 100644
index 0000000..af02256
--- /dev/null
+++ b/TestON/drivers/common/api/deepinsightapidriver.py
@@ -0,0 +1,93 @@
+from deepinsight.client import DeepInsightClient
+from drivers.common.apidriver import API
+
+class DeepInsightApiDriver( API ):
+    def __init__( self ):
+        self.name = None
+        self.serverUrl = None
+        self.accessToken = None
+        self.refreshToken = None
+        self.requestAuthHeader = None
+        self.verifySsl = False
+        self.client = None
+        super( DeepInsightApiDriver, self ).__init__()
+
+    def connect(
+        self,
+        **connectargs
+    ):
+        for key in connectargs:
+            vars(self)[key] = connectargs[key]
+        self.name = self.options["name"]
+        self.client = DeepInsightClient(
+            server_url = self.options["server_url"],
+            username = self.options["username"],
+            password = self.options["password"],
+            verify_ssl = self.options["verify_ssl"] == "True",
+        )
+        self.handle = super( DeepInsightApiDriver, self ).connect()
+        return self.handle
+
+    def disconnect( self, **connectargs ):
+        self.client.logout()
+
+    def getFlows(
+        self,
+        startTimeMs = None,
+        endTimeMs = None,
+        maxResults = 100,
+        srcIp = None,
+        dstIp = None,
+        srcPort = None,
+        dstPort = None,
+        ipProto = None,
+    ):
+        return self.client.get_flows(
+            startTimeMs,
+            endTimeMs,
+            maxResults,
+            srcIp,
+            dstIp,
+            srcPort,
+            dstPort,
+            ipProto,
+        )
+
+    def getSwitchPacketDrop(
+        self,
+        switchId,
+        egressPort = 0,
+        queueId = 0,
+        startTime = None,
+        endTime = None,
+        numBuckets = 100,
+    ):
+        return self.client.get_switch_packet_drop(
+            switchId,
+            egressPort,
+            queueId,
+            startTime,
+            endTime,
+            numBuckets,
+        )
+
+    def getSwitchAnomalies(
+        self, switchId, startTime = None, endTime = None
+    ):
+        return self.client.get_switch_anomalies(
+            switchId, startTime, endTime
+        )
+
+    def getSwitchLatencies(
+        self,
+        switchId,
+        startTime = None,
+        endTime = None,
+        granularity = 1000,
+    ):
+        return self.client.get_switch_latencies(
+            switchId,
+            startTime,
+            endTime,
+            granularity,
+        )
diff --git a/TestON/drivers/common/cli/hostdriver.py b/TestON/drivers/common/cli/hostdriver.py
index a4ab31c..5bfe274 100644
--- a/TestON/drivers/common/cli/hostdriver.py
+++ b/TestON/drivers/common/cli/hostdriver.py
@@ -248,7 +248,7 @@
             main.log.error( self.name + ":     " + self.handle.before )
             return main.FALSE
 
-    def addRouteToHost( self, route, gw, interface=None, sudoRequired=True, purgeOnDisconnect=True ):
+    def addRouteToHost( self, route, gw, interface=None, sudoRequired=True, purgeOnDisconnect=True, cmdPath='/sbin/ip' ):
         """
         Adds a static route to the host
         Arguments:
@@ -260,7 +260,11 @@
         * purgeOnDisconnect - Boolean, remove this route before disconnecting from component
         """
         try:
-            cmd = "ip route add %s via %s" % ( route, gw )
+            if cmdPath:
+                cmd = cmdPath
+            else:
+                cmd = "ip"
+            cmd += " route add %s via %s" % ( route, gw )
             if sudoRequired:
                 cmd = "sudo %s" % cmd
             if interface:
@@ -300,7 +304,7 @@
             main.log.error( self.name + ":     " + self.handle.before )
             return main.FALSE
 
-    def deleteRoute( self, route, gw, interface=None, sudoRequired=True ):
+    def deleteRoute( self, route, gw, interface=None, sudoRequired=True, cmdPath='/sbin/ip'  ):
         """
         Deletess a static route from the host
         Arguments:
@@ -311,7 +315,11 @@
         * sudoRequired - Boolean, whether sudo is needed for this command, defaults to True
         """
         try:
-            cmd = "ip route del %s via %s" % ( route, gw )
+            if cmdPath:
+                cmd = cmdPath
+            else:
+                cmd = "ip"
+            cmd += " route del %s via %s" % ( route, gw )
             if sudoRequired:
                 cmd = "sudo %s" % cmd
             if interface:
diff --git a/TestON/tests/USECASE/SegmentRouting/SRStaging/SRStaging.topo b/TestON/tests/USECASE/SegmentRouting/SRStaging/SRStaging.topo
index 2f4c8f2..b9d705e 100644
--- a/TestON/tests/USECASE/SegmentRouting/SRStaging/SRStaging.topo
+++ b/TestON/tests/USECASE/SegmentRouting/SRStaging/SRStaging.topo
@@ -183,7 +183,7 @@
         </Host3>
 
         <ng40vm>
-            <host>192.168.122.102</host>
+            <host>10.92.1.95</host>
             <user>ng40</user>
             <password>ng40</password>
             <type>HostDriver</type>
diff --git a/TestON/tests/USECASE/SegmentRouting/SRStaging/SRpairedLeaves/SRpairedLeaves.params b/TestON/tests/USECASE/SegmentRouting/SRStaging/SRpairedLeaves/SRpairedLeaves.params
index 2cb31b3..85f3fd6 100644
--- a/TestON/tests/USECASE/SegmentRouting/SRStaging/SRpairedLeaves/SRpairedLeaves.params
+++ b/TestON/tests/USECASE/SegmentRouting/SRStaging/SRpairedLeaves/SRpairedLeaves.params
@@ -1,5 +1,5 @@
 <PARAMS>
-    <testcases>1,2,101,102,103,104,201,202,203,204,205,206,207,208,301</testcases>
+    <testcases>1,2,101,102,103,104,301,302</testcases>
 
     <GRAPH>
         <nodeCluster>pairedleaves</nodeCluster>
diff --git a/TestON/tests/USECASE/SegmentRouting/SRStaging/SRpairedLeaves/SRpairedLeaves.py b/TestON/tests/USECASE/SegmentRouting/SRStaging/SRpairedLeaves/SRpairedLeaves.py
index 96618cf..5911832 100644
--- a/TestON/tests/USECASE/SegmentRouting/SRStaging/SRpairedLeaves/SRpairedLeaves.py
+++ b/TestON/tests/USECASE/SegmentRouting/SRStaging/SRpairedLeaves/SRpairedLeaves.py
@@ -48,6 +48,7 @@
         """
         try:
             from tests.USECASE.SegmentRouting.SRStaging.dependencies.SRStagingTest import SRStagingTest
+            from tests.USECASE.SegmentRouting.dependencies.Testcaselib import Testcaselib as run
             import json
         except ImportError:
             main.log.error( "SRStagingTest not found. Exiting the test" )
@@ -63,6 +64,7 @@
                               topology='0x2',
                               onosNodes=3,
                               description="%s tests on the %s pod" % ( descPrefix, pod ) )
+        hosts = [ 'h1', 'h2', 'h3', 'mgmt' ]
         run.pingAllFabricIntfs( main, hosts, dumpFlows=False )
         main.funcs.cleanup( main )
 
@@ -670,3 +672,61 @@
         # Cleanup
         main.log.warn( json.dumps( main.downtimeResults, indent=4, sort_keys=True ) )
         main.funcs.cleanup( main )
+
+    def CASE302 ( self, main ):
+        """
+        Send ping packets from one host to another host and check flows from DeepInsight.
+        """
+
+        try:
+            from tests.USECASE.SegmentRouting.SRStaging.dependencies.SRStagingTest import SRStagingTest
+            from tests.USECASE.SegmentRouting.dependencies.Testcaselib import Testcaselib as run
+            from core import utilities
+            import time
+            import socket
+        except ImportError as e:
+            main.log.exception( "SRStagingTest not found. Exiting the test" )
+            main.cleanAndExit()
+        try:
+            main.funcs
+        except ( NameError, AttributeError ):
+            main.funcs = SRStagingTest()
+
+        pod = main.params['GRAPH'].get( 'nodeCluster', "hardware" )
+        main.cfgName = 'CASE302'
+        main.funcs.setupTest( main,
+                              topology='0x2',
+                              onosNodes=3,
+                              description="INT flow report tests on %s POD" % ( pod ) )
+        startTimeMs = ( time.time() - 5 ) * 1000
+        run.verifyPing( main, ['h1'], ['h2'] )
+        endTimeMs = ( time.time() + 5 ) * 1000
+        main.step( "Checking flow report from DeepInsight" )
+
+        def getFiveTupleCount(*args, **kwargs):
+            flows = main.DeepInsight.getFlows(
+                startTimeMs=startTimeMs,
+                endTimeMs=endTimeMs,
+                srcIp=main.h1.interfaces[0]['ips'][0],
+                dstIp=main.h2.interfaces[0]['ips'][0],
+                ipProto=socket.IPPROTO_ICMP
+            )
+            if "FiveTupleCount" in flows:
+                return flows["FiveTupleCount"]
+            else:
+                return 0
+
+        # Need to wait few seconds until DeepInsight database updated.
+        fiveTupleCount = utilities.retry(
+            f=getFiveTupleCount,
+            retValue=0,
+            attempts=60,
+        )
+
+        utilities.assert_equals(
+            expect=1, actual=fiveTupleCount,
+            onpass="Got 1 flow report from DeepInsight as expected.",
+            onfail="Got %d flow reports from DeepInsight (expect 1)" % ( fiveTupleCount )
+        )
+
+        main.funcs.cleanup( main )
diff --git a/TestON/tests/USECASE/SegmentRouting/SRStaging/SRpairedLeaves/SRpairedLeaves.topo b/TestON/tests/USECASE/SegmentRouting/SRStaging/SRpairedLeaves/SRpairedLeaves.topo
index 40bf030..e529c6f 100644
--- a/TestON/tests/USECASE/SegmentRouting/SRStaging/SRpairedLeaves/SRpairedLeaves.topo
+++ b/TestON/tests/USECASE/SegmentRouting/SRStaging/SRpairedLeaves/SRpairedLeaves.topo
@@ -184,5 +184,19 @@
             </COMPONENTS>
         </NetworkBench>
 
+        <DeepInsight>
+            <host>10.76.28.74</host>
+            <user>jenkins</user>
+            <password></password>
+            <type>DeepInsightApiDriver</type>
+            <connect_order>1</connect_order>
+            <COMPONENTS>
+                <server_url>https://10.76.28.74:30000</server_url>
+                <username>diadmin</username>
+                <password>diadmin</password>
+                <verify_ssl>False</verify_ssl>
+            </COMPONENTS>
+        </DeepInsight>
+
     </COMPONENT>
 </TOPOLOGY>
diff --git a/TestON/tests/USECASE/SegmentRouting/SRStaging/dependencies/SRStagingTest.py b/TestON/tests/USECASE/SegmentRouting/SRStaging/dependencies/SRStagingTest.py
index a3ab6ba..f0f30a5 100644
--- a/TestON/tests/USECASE/SegmentRouting/SRStaging/dependencies/SRStagingTest.py
+++ b/TestON/tests/USECASE/SegmentRouting/SRStaging/dependencies/SRStagingTest.py
@@ -1353,8 +1353,9 @@
 
     def cleanup( self, main, headerOrder=None ):
         try:
-            for component in main.trafficComponents:
-                main.Network.removeComponent( component.name )
+            if hasattr( main, "trafficComponents" ):
+                for component in main.trafficComponents:
+                    main.Network.removeComponent( component.name )
             main.trafficComponents = []
         except Exception:
             main.log.exception( "Error cleaning up traffic components" )
diff --git a/TestON/tests/dependencies/topology.py b/TestON/tests/dependencies/topology.py
index 9d20cda..56a29a9 100644
--- a/TestON/tests/dependencies/topology.py
+++ b/TestON/tests/dependencies/topology.py
@@ -263,6 +263,15 @@
             srcIpList[ src ] = main.Network.getIPAddress( src, proto='IPV6' if ipv6 else 'IPV4', iface=hostHandle.interfaces[0].get("name") )
         unexpectedPings = []
         for dst in dstList:
+            if not hasattr( main, dst ):
+                main.log.info( "Creating component for host {}".format( dst ) )
+                main.Network.createHostComponent( dst )
+                hostHandle = getattr( main, dst )
+                if hasattr( main, 'Mininet1' ):
+                    main.log.info( "Starting CLI on host {}".format( dst ) )
+                    hostHandle.startHostCli()
+                else:
+                    hostHandle.connectInband()
             hostHandle = getattr( main, dst )
             dstIp = main.Network.getIPAddress( dst, proto='IPV6' if ipv6 else 'IPV4', iface=hostHandle.interfaces[0].get("name") )
             # Start pings from src hosts in parallel