Merge "Collect t3 output on SRMulticast failures"
diff --git a/TestON/tests/USECASE/SegmentRouting/SRMulticast/SRMulticast.params b/TestON/tests/USECASE/SegmentRouting/SRMulticast/SRMulticast.params
index f687a40..c9f4f55 100644
--- a/TestON/tests/USECASE/SegmentRouting/SRMulticast/SRMulticast.params
+++ b/TestON/tests/USECASE/SegmentRouting/SRMulticast/SRMulticast.params
@@ -34,9 +34,9 @@
     </CTRL>
 
     <timers>
-        <LinkDiscovery>45</LinkDiscovery>
-        <SwitchDiscovery>45</SwitchDiscovery>
-        <OnosDiscovery>45</OnosDiscovery>
+        <LinkDiscovery>30</LinkDiscovery>
+        <SwitchDiscovery>30</SwitchDiscovery>
+        <OnosDiscovery>30</OnosDiscovery>
         <loadNetcfgSleep>5</loadNetcfgSleep>
         <startMininetSleep>60</startMininetSleep>
         <balanceMasterSleep>10</balanceMasterSleep>
diff --git a/TestON/tests/USECASE/SegmentRouting/dependencies/Testcaselib.py b/TestON/tests/USECASE/SegmentRouting/dependencies/Testcaselib.py
index 071724e..5b1645b 100644
--- a/TestON/tests/USECASE/SegmentRouting/dependencies/Testcaselib.py
+++ b/TestON/tests/USECASE/SegmentRouting/dependencies/Testcaselib.py
@@ -1006,10 +1006,15 @@
             main.log.debug( host.hostMac )
 
     @staticmethod
-    def verifyMulticastTraffic( main, routeName, expect, skipOnFail=True, maxRetry=3 ):
+    def verifyMulticastTraffic( main, routeName, expect, skipOnFail=True, maxRetry=0 ):
         """
         Verify multicast traffic using scapy
         """
+        from tests.dependencies.topology import Topology
+        try:
+            main.topo
+        except ( NameError, AttributeError ):
+            main.topo = Topology()
         routeData = main.multicastConfig[ routeName ]
         srcs = main.mcastRoutes[ routeName ][ "src" ]
         dsts = main.mcastRoutes[ routeName ][ "dst" ]
@@ -1038,44 +1043,21 @@
                 pkt = srcEntry[ "packet" ]
                 # Send packet and check received packet
                 expectedResult = expect.pop( 0 ) if isinstance( expect, list ) else expect
-                trafficResult = utilities.retry( Testcaselib.sendMulticastTraffic,
-                                                 main.FALSE,
-                                                 args=( main, sender, receiver, pktFilter, pkt,
-                                                        sIface, dIface, expectedResult ),
-                                                 attempts=maxRetry,
-                                                 sleep=1 )
+                t3Cmd = "t3-troubleshoot -vv -sp {} -et ipv{} -d {} -dm {}".format( srcEntry[ "port" ], routeData[ "ipVersion" ],
+                                                                                routeData[ "group" ], srcEntry[ "Ether" ] )
+                trafficResult = main.topo.sendScapyPackets( sender, receiver, pktFilter, pkt, sIface, dIface,
+                                                            expectedResult, maxRetry, True, t3Cmd )
                 utilities.assert_equals( expect=main.TRUE,
                                          actual=trafficResult,
                                          onpass="{} to {}: Pass".format( srcEntry[ "host" ], dstEntry[ "host" ] ),
                                          onfail="{} to {}: Fail".format( srcEntry[ "host" ], dstEntry[ "host" ] ) )
                 if skipOnFail and trafficResult != main.TRUE:
+                    main.stop()
                     Testcaselib.saveOnosDiagnostics( main )
                     Testcaselib.cleanup( main, copyKarafLog=False )
                     main.skipCase()
 
     @staticmethod
-    def sendMulticastTraffic( main, sender, receiver, pktFilter, pkt, sIface=None, dIface=None, expect=True ):
-        """
-        Send multicast traffic using scapy
-        """
-        receiver.startFilter( ifaceName=dIface, pktFilter=pktFilter )
-        sender.sendPacket( iface=sIface )
-        finished = receiver.checkFilter()
-        packet = ""
-        if finished:
-            packets = receiver.readPackets()
-            for packet in packets.splitlines():
-                main.log.debug( packet )
-        else:
-            kill = receiver.killFilter()
-            main.log.debug( kill )
-            sender.handle.sendline( "" )
-            sender.handle.expect( sender.scapyPrompt )
-            main.log.debug( sender.handle.before )
-        packetCaptured = True if pkt in packet else False
-        return main.TRUE if packetCaptured == expect else main.FALSE
-
-    @staticmethod
     def verifyPing( main, srcList, dstList, ipv6=False, expect=True, wait=1, acceptableFailed=0, skipOnFail=True ):
         """
         Verify reachability from each host in srcList to each host in dstList
diff --git a/TestON/tests/dependencies/topology.py b/TestON/tests/dependencies/topology.py
index 6527a83..e4f195b 100644
--- a/TestON/tests/dependencies/topology.py
+++ b/TestON/tests/dependencies/topology.py
@@ -273,7 +273,7 @@
                 thread = main.Thread( target=utilities.retry,
                                       name="{}-{}".format( srcIp, dstIp ),
                                       args=[ hostHandle.pingHostSetAlternative, [ main.FALSE ] ],
-                                      kwargs={ "args":( [ dstIp ], wait, ipv6 ),
+                                      kwargs={ "args": ( [ dstIp ], wait, ipv6 ),
                                                "attempts": acceptableFailed + 1,
                                                "sleep": 1 } )
                 pool.append( thread )
@@ -302,3 +302,65 @@
                     main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress, cmd, main.logdir,
                                                 "t3-CASE{}-{}-{}-".format( main.CurrentTestCaseNumber, srcIp, dstIp ) )
         return main.FALSE if unexpectedPings else main.TRUE
+
+    def sendScapyPackets( self, sender, receiver, pktFilter, pkt, sIface=None, dIface=None, expect=True, acceptableFailed=0, collectT3=True, t3Command="" ):
+        """
+        Description:
+            Call sendScapyPacket and retry if neccessary
+            If collectT3 is True and t3Command is specified, collect t3-troubleshoot output on unexpected scapy results
+            Buiid packets on the sender side by calling functions in Scapy CLI driver
+        Options:
+            sender: the component of the host that is sending packets
+            receiver: the component of the host that is receiving packets
+            pktFilter: packet filter used by receiver
+            pkt: keyword that is expected to be conrained in the received packets
+            expect: expect receiver to receive the packet if True, otherwise not receiving the packet
+            acceptableFailed: maximum number of unexpected scapy results acceptable
+            collectT3: save t3-troubleshoot output for unexpected scapy results
+        Returns:
+            main.TRUE if scapy result is expected, otherwise main.FALSE
+        """
+        main.log.info( "Sending scapy packets from  {} to {}, expected result is {}".format( sender.name, receiver.name,
+                                                                                             "pass" if expect else "fail" ) )
+        scapyResult = utilities.retry( self.sendScapyPacket,
+                                       main.FALSE,
+                                       args=( sender, receiver, pktFilter, pkt,
+                                              sIface, dIface, expect ),
+                                       attempts=acceptableFailed + 1,
+                                       sleep=1 )
+        if not scapyResult and collectT3 and t3Command:
+            main.log.debug( "Collecting t3 with source {} and destination {}".format( sender.name, receiver.name ) )
+            main.log.debug( "t3 command: {}".format( t3Command ) )
+            main.ONOSbench.dumpONOSCmd( main.Cluster.active( 0 ).ipAddress, t3Command, main.logdir,
+                                        "t3-CASE{}-{}-{}-".format( main.CurrentTestCaseNumber, sender.name, receiver.name ) )
+        return scapyResult
+
+    def sendScapyPacket( self, sender, receiver, pktFilter, pkt, sIface=None, dIface=None, expect=True ):
+        """
+        Description:
+            Send Scapy packets from sender to receiver and verify if result is as expected
+        Options:
+            sender: the component of the host that is sending packets
+            receiver: the component of the host that is receiving packets
+            pktFilter: packet filter used by receiver
+            pkt: keyword that is expected to be conrained in the received packets
+            expect: expect receiver to receive the packet if True, otherwise not receiving the packet
+        Returns:
+            main.TRUE if scapy result is expected, otherwise main.FALSE
+        """
+        receiver.startFilter( ifaceName=dIface, pktFilter=pktFilter )
+        sender.sendPacket( iface=sIface )
+        finished = receiver.checkFilter()
+        packet = ""
+        if finished:
+            packets = receiver.readPackets()
+            for packet in packets.splitlines():
+                main.log.debug( packet )
+        else:
+            kill = receiver.killFilter()
+            main.log.debug( kill )
+            sender.handle.sendline( "" )
+            sender.handle.expect( sender.scapyPrompt )
+            main.log.debug( sender.handle.before )
+        packetCaptured = True if pkt in packet else False
+        return main.TRUE if packetCaptured == expect else main.FALSE