Updating test for TOST QA Pod

Add more robust topology check to Segment routing tests
Fix Typos
Include minimum flow count # in the comparision (>= vs > )
Add option for username and password in onos-app function
Don't add app prefix if it looks like it is already the full name

Change-Id: Ib4af0f72df8e7dcc5c179fafea1fd9c61d931246
(cherry picked from commit cda0902ee85041b22da8ad7638a8518914d07322)
diff --git a/TestON/drivers/common/cli/emulator/mininetclidriver.py b/TestON/drivers/common/cli/emulator/mininetclidriver.py
index 7a4e565..439b4fb 100644
--- a/TestON/drivers/common/cli/emulator/mininetclidriver.py
+++ b/TestON/drivers/common/cli/emulator/mininetclidriver.py
@@ -3915,6 +3915,8 @@
         if hostHome is not None:
             self.hostHome = hostHome
         try:
+            self.handle.sendline( "" )
+            self.handle.expect( self.Prompt() )
             if not host:
                 host = self.name
             if self.mExecDir:
diff --git a/TestON/drivers/common/cli/onosclidriver.py b/TestON/drivers/common/cli/onosclidriver.py
index 4112977..ef69aec 100755
--- a/TestON/drivers/common/cli/onosclidriver.py
+++ b/TestON/drivers/common/cli/onosclidriver.py
@@ -2689,7 +2689,7 @@
         count = self.getTotalFlowsNum( timeout=timeout )
         count = int( count ) if count else 0
         main.log.debug( "found {} flows".format( count ) )
-        return count if ( count > min ) else False
+        return count if ( count >= min ) else False
 
     def checkFlowsState( self, isPENDING=True, timeout=60, noExit=False ):
         """
@@ -3133,7 +3133,7 @@
         count = self.flowAddedCount( deviceId, core )
         count = int( count ) if count else 0
         main.log.debug( "found {} flows".format( count ) )
-        return count if ((count > expectedFlowCount) if (comparison == 0) else (count == expectedFlowCount)) else main.FALSE
+        return count if ((count >= expectedFlowCount) if (comparison == 0) else (count == expectedFlowCount)) else main.FALSE
 
     def getAllDevicesId( self ):
         """
@@ -3261,7 +3261,7 @@
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanAndExit()
 
-    def checkStatus( self, numoswitch, numolink = -1, numoctrl = -1, logLevel="info" ):
+    def checkStatus( self, numoswitch, numolink = -1, numoctrl = -1, numoSCCs=1, logLevel="info" ):
         """
         Checks the number of switches & links that ONOS sees against the
         supplied values. By default this will report to main.log, but the
@@ -3270,6 +3270,7 @@
         Params: numoswitch = expected number of switches
                 numolink = expected number of links
                 numoctrl = expected number of controllers
+                numoSCCs = Number of expected SCCs
                 logLevel = level to log to.
                 Currently accepts 'info', 'warn' and 'report'
 
@@ -3292,36 +3293,52 @@
             devices = topology.get( 'devices', False )
             links = topology.get( 'links', False )
             nodes = summary.get( 'nodes', False )
-            if devices is False or links is False or nodes is False:
+            SCCs = summary.get( 'SCC(s)', False )
+            if devices is False or links is False or nodes is False or SCCs is False:
+                main.log.warn( "Issues parsing topology and summary output" )
+                main.log.debug( topology )
+                main.log.debug( summary )
                 return main.ERROR
             switchCheck = ( int( devices ) == int( numoswitch ) )
-            # Is the number of links is what we expected
+            if not switchCheck:
+                main.log.debug( "switch Check Failed" )
             linkCheck = ( int( links ) == int( numolink ) ) or int( numolink ) == -1
+            if not linkCheck:
+                main.log.debug( "link Check Failed" )
             nodeCheck = ( int( nodes ) == int( numoctrl ) ) or int( numoctrl ) == -1
-            if switchCheck and linkCheck and nodeCheck:
+            if not nodeCheck:
+                main.log.debug( "node Check Failed" )
+            SCCsCheck = ( int( SCCs ) == int( numoSCCs ) ) or int( numoSCCs ) == -1
+            if not SCCsCheck:
+                main.log.debug( "SCCs Check Failed" )
+            if switchCheck and linkCheck and nodeCheck and SCCsCheck:
                 # We expected the correct numbers
-                output = output + "The number of links and switches match "\
+                output = output + "The number of links, switches, nodes, and SCCs match "\
                     + "what was expected"
                 result = main.TRUE
             else:
                 output = output + \
-                    "The number of links and switches does not match " + \
+                    "The number of links, switches, nodes, and SCCs  does not match " + \
                     "what was expected"
                 result = main.FALSE
-            output = output + "\n ONOS sees %i devices" % int( devices )
-            output = output + " (%i expected) " % int( numoswitch )
-            if int( numolink ) > 0:
+            output = output + "\n ONOS sees %i devices " % int( devices )
+            output = output + "(%i expected) " % int( numoswitch )
+            if int( numolink ) >= 0:
                 output = output + "and %i links " % int( links )
-                output = output + "(%i expected)" % int( numolink )
-            if int( numoctrl ) > 0:
+                output = output + "(%i expected) " % int( numolink )
+            if int( numoctrl ) >= 0:
                 output = output + "and %i controllers " % int( nodes )
-                output = output + "(%i expected)" % int( numoctrl )
+                output = output + "(%i expected) " % int( numoctrl )
+            if int( numoSCCs ) >= 0:
+                output = output + "and %i SCCs " % int( SCCs )
+                output = output + "(%i expected)" % int( numoSCCs )
             if logLevel == "report":
                 main.log.report( output )
             elif logLevel == "warn":
                 main.log.warn( output )
             else:
                 main.log.info( output )
+            main.TOPOOUTPUT = output
             return result
         except pexpect.EOF:
             main.log.error( self.name + ": EOF exception found" )
@@ -6757,7 +6774,7 @@
             output = ""
             for cmdStr in cmdList:
                 self.handle.sendline( cmdStr )
-                self.handle.expect( self.dockerPrompt )
+                self.handle.expect( self.dockerPrompt, timeout=120 )
                 self.handle.sendline( "" )
                 self.handle.expect( self.dockerPrompt )
                 handle = self.handle.before
diff --git a/TestON/drivers/common/cli/onosdriver.py b/TestON/drivers/common/cli/onosdriver.py
index a2fade7..e9cca52 100755
--- a/TestON/drivers/common/cli/onosdriver.py
+++ b/TestON/drivers/common/cli/onosdriver.py
@@ -2574,7 +2574,7 @@
 
         return main.TRUE if onosStatus else main.FALSE
 
-    def onosNetCfg( self, controllerIp, path, fileName, user=None, password=None):
+    def onosNetCfg( self, controllerIp, path, fileName, user=None, password=None ):
         """
         Push a specified json file to ONOS through the onos-netcfg service
 
@@ -2967,7 +2967,8 @@
             main.log.exception( self.name + ": Uncaught exception!" )
             main.cleanAndExit()
 
-    def onosApp( self, onosIP, option, fileName, filePath='~/onos/'):
+    def onosApp( self, onosIP, option, fileName, filePath='~/onos/',
+                 appName=None, user=None, password=None ):
         """
         Wrapper for onos-app script
 
@@ -2977,14 +2978,21 @@
             [ list|install|install!|reinstall|reinstall!|activate|deactivate|uninstall ]
         - fileName - The name of the app file
         Optional Arguments:
+        - appName - The name of the app, some options require this
         - filePath - The location of the file
+        - user - ONOS cli user
+        - password - ONOS cli password
 
         Returns main.TRUE on successfully executing the command, and main.FALSE if
         there is an error.
         """
         # FIXME: Not all options may work, more testing is required, only tested with install(!)
         try:
-            cmd = "onos-app %s %s %s/%s" % ( onosIP, option, filePath, fileName )
+            cmd = "onos-app %s %s %s %s/%s" % ( onosIP, option, appName if "reinstall" in option else "", filePath, fileName )
+            if user:
+                cmd += " -u %s" % user
+            if password:
+                cmd += " -p %s" % password
             main.log.info( self.name + ": Sending: " + cmd )
             self.handle.sendline( cmd )
             self.handle.expect( self.prompt )
diff --git a/TestON/drivers/common/cli/stratumosswitchdriver.py b/TestON/drivers/common/cli/stratumosswitchdriver.py
index 79f1d89..3eae155 100644
--- a/TestON/drivers/common/cli/stratumosswitchdriver.py
+++ b/TestON/drivers/common/cli/stratumosswitchdriver.py
@@ -203,20 +203,21 @@
             main.log.info( "Modify start container script" )
             self.handle.sendline( "sed -i '/--privileged/a \    --name stratum \\\\' start-stratum-container.sh" )
             self.handle.expect( self.prompt )
-            #self.handle.sendline( "sed -i '/LOG_DIR:\/var\/log\/stratum/a \    --entrypoint /bin/bash \\\\' start-stratum-container.sh" )
-            #self.handle.expect( self.prompt )
             # TODO: Add docker pull command to the start-stratum-container.sh script
 
             main.log.info( "Getting chassis config" )
             # TODO: Parameterize this
-            self.handle.sendline( "wget --backups=1 https://raw.githubusercontent.com/stratum/stratum/master/stratum/hal/config/x86-64-accton-wedge100bf-32x-r0/chassis_config.pb.txt" )
-            self.handle.expect( self.prompt )
+            filename = "~/TestON/tests/USECASE/SegmentRouting/dependencies/chassis_config.pb.txt.qa"
+            main.ONOSbench.secureCopy( self.user_name, self.ip_address, filename, "~/TestON/chassis_config.pb.txt", pwd=self.pwd, direction="to" )
             main.log.info( "Modify chassis config" )
             # TODO: Parameterize this
-            self.handle.sendline( "sed -i '$!N;s/\(port: [5|6]\\n\  speed_bps: \)\([0-9]*\)/\\1 40000000000/;P;D' chassis_config.pb.txt" )
-            self.handle.expect( self.prompt )
             self.handle.sendline( "export CHASSIS_CONFIG=~/TestON/chassis_config.pb.txt" )
             self.handle.expect( self.prompt )
+            #self.handle.sendline( "export DOCKER_IMAGE=registry.aetherproject.org/tost/stratum-bfrt" )
+            self.handle.sendline( "export DOCKER_IMAGE=stratumproject/stratum-bf" )
+            self.handle.expect( self.prompt )
+            self.handle.sendline( "export DOCKER_IMAGE_TAG=9.2.0" )
+            self.handle.expect( self.prompt )
             self.handle.sendline( "chmod +x start-stratum-container.sh" )
             self.handle.expect( self.prompt )
         except pexpect.TIMEOUT:
@@ -237,7 +238,7 @@
         """
         try:
             main.log.info( "Starting switch agent" )
-            self.handle.sendline( "./start-stratum-container.sh --bf-sim" )
+            self.handle.sendline( "./start-stratum-container.sh --bf-sim --bf-switchd-background=false" )
             self.handle.expect( "Chassis config pushed successfully." )
             return main.TRUE
         except pexpect.TIMEOUT:
diff --git a/TestON/drivers/common/clidriver.py b/TestON/drivers/common/clidriver.py
index 928db71..3083f44 100644
--- a/TestON/drivers/common/clidriver.py
+++ b/TestON/drivers/common/clidriver.py
@@ -274,7 +274,7 @@
                     timeout=120 )
 
     def secureCopy( self, userName, ipAddress, filePath, dstPath, pwd="",
-                    direction="from" ):
+                    direction="from", options="" ):
         """
         Definition:
             Execute scp command in linux to copy to/from a remote host
@@ -294,12 +294,13 @@
         ssh_newkey = 'Are you sure you want to continue connecting'
         refused = "ssh: connect to host " + \
                   ipAddress + " port 22: Connection refused"
+        cmd = "scp %s " % options
 
         if direction == "from":
-            cmd = 'scp ' + str( userName ) + '@' + str( ipAddress ) + ':' + \
+            cmd = cmd + str( userName ) + '@' + str( ipAddress ) + ':' + \
                   str( filePath ) + ' ' + str( dstPath )
         elif direction == "to":
-            cmd = 'scp ' + str( filePath ) + ' ' + str( userName ) + \
+            cmd = cmd + str( filePath ) + ' ' + str( userName ) + \
                   '@' + str( ipAddress ) + ':' + str( dstPath )
         else:
             main.log.debug( "Wrong direction using secure copy command!" )
@@ -337,9 +338,11 @@
                 returnVal = main.FALSE
             elif i == 4:  # File Not found
                 main.log.error( self.name + ": No such file found" )
+                main.log.debug( self.handle.before + self.handle.after )
                 returnVal = main.FALSE
             elif i == 5:  # Permission denied
                 main.log.error( self.name + ": Permission denied. Check folder permissions" )
+                main.log.debug( self.handle.before + self.handle.after )
                 returnVal = main.FALSE
             elif i == 6:  # prompt returned
                 return returnVal
@@ -356,7 +359,7 @@
         self.handle.expect( self.prompt )
         return returnVal
 
-    def scp( self, remoteHost, filePath, dstPath, direction="from" ):
+    def scp( self, remoteHost, filePath, dstPath, direction="from", options="" ):
         """
         Definition:
             Execute scp command in linux to copy to/from a remote host
@@ -375,7 +378,8 @@
                                 filePath,
                                 dstPath,
                                 pwd=remoteHost.pwd,
-                                direction=direction )
+                                direction=direction,
+                                options=options )
 
     def sshToNode( self, ipAddress, uName="sdn", pwd="rocks" ):
         ssh_newkey = 'Are you sure you want to continue connecting'