Calculate ScaleTopo latency

Change-Id: I4fff71f72ae6162c3bd0c86108af54ce164a0f1d
diff --git a/TestON/drivers/common/cli/onosclidriver.py b/TestON/drivers/common/cli/onosclidriver.py
index c30ac53..ebfd8a5 100755
--- a/TestON/drivers/common/cli/onosclidriver.py
+++ b/TestON/drivers/common/cli/onosclidriver.py
@@ -5017,14 +5017,19 @@
                 all: return all the strings that contain the search term
                 last: return the last string that contains the search term
                 first: return the first string that contains the search term
+                num: return the number that the searchTerm appears in the log
         """
         try:
             assert type( searchTerm ) is str
-            cmd = "cat /opt/onos/log/karaf.log | grep " + searchTerm
+            cmd = "cat /opt/onos/log/karaf.log | grep \'" + searchTerm + "\'"
             if mode == 'last':
                 cmd = cmd + " | tail -n 1"
             if mode == 'first':
                 cmd = cmd + " | head -n 1"
+            if mode == 'num':
+                cmd = "cat /opt/onos/log/karaf.log | grep -c \'" + searchTerm + "\'"
+                num = self.sendline( cmd )
+                return num
             before = self.sendline( cmd )
             before = before.splitlines()
             # make sure the returned list only contains the search term
diff --git a/TestON/tests/SCPF/SCPFscaleTopo/SCPFscaleTopo.params b/TestON/tests/SCPF/SCPFscaleTopo/SCPFscaleTopo.params
index 0abc6b7..9af6dae 100755
--- a/TestON/tests/SCPF/SCPFscaleTopo/SCPFscaleTopo.params
+++ b/TestON/tests/SCPF/SCPFscaleTopo/SCPFscaleTopo.params
@@ -18,10 +18,20 @@
         <multiovs>multiovs.py</multiovs>
     </DEPENDENCY>
 
+    <DATABASE>
+        <dbPath>/tmp/scaleTopoResultDb</dbPath>
+    </DATABASE>
+
     <ENV>
         <cellApps>drivers,openflow</cellApps>
     </ENV>
 
+    <SearchTerm>
+        <start>New switch connection</start>
+        <end>Topology DefaultTopology</end>
+        <Disconnect>Switch disconnected callback</Disconnect>
+    </SearchTerm>
+
     <GIT>
         <pull>False</pull>
         <branch>master</branch>
@@ -53,7 +63,7 @@
 
     <TOPOLOGY>
         <topology>torus</topology>
-        <scale>20,25,30,35,40,45,50,55,60</scale>
+        <scale>5,10,20,30,35,40,50,55,60</scale>
         <host>True</host>
     </TOPOLOGY>
 
diff --git a/TestON/tests/SCPF/SCPFscaleTopo/SCPFscaleTopo.py b/TestON/tests/SCPF/SCPFscaleTopo/SCPFscaleTopo.py
index 7babb49..2561e52 100644
--- a/TestON/tests/SCPF/SCPFscaleTopo/SCPFscaleTopo.py
+++ b/TestON/tests/SCPF/SCPFscaleTopo/SCPFscaleTopo.py
@@ -20,11 +20,13 @@
             - Install ONOS package
             - Build ONOS package
         """
-
         main.case( "Constructing test variables" )
         main.step( "Constructing test variables" )
         stepResult = main.FALSE
-
+        # The variable to decide if the data should be written into data base.
+        # 1 means Yes and -1 means No.
+        main.writeData = 1
+        main.searchTerm = main.params[ 'SearchTerm' ]
         main.testOnDirectory = os.path.dirname( os.getcwd ( ) )
         main.apps = main.params[ 'ENV' ][ 'cellApps' ]
         gitBranch = main.params[ 'GIT' ][ 'branch' ]
@@ -64,6 +66,20 @@
         for i in range(main.numCtrls):
                 main.CLIs.append( getattr( main, 'ONOScli%s' % (i+1) ) )
 
+        main.allinfo = {} # The dictionary to record all the data from karaf.log
+        for i in range( 2 ):
+            main.allinfo[ i ]={}
+            for w in range ( 3 ):
+                # Totaltime: the time from the new switchConnection to its end
+                # swConnection: the time from the first new switchConnection to the last new switchConnection
+                # disconnectRate: the rate that shows how many switch disconnect after connection
+                main.allinfo[ i ][ 'info' + str( w ) ]= { 'totalTime': 0, 'swConnection': 0,'disconnectRate': 0 }
+
+        main.dbFilePath = main.params[ 'DATABASE' ][ 'dbPath' ]
+        main.log.info( "Create Database file " + main.dbFilePath )
+        resultDB = open(main.dbFilePath, 'w+' )
+        resultDB.close()
+
         main.startUp = imp.load_source( wrapperFile1,
                                         main.dependencyPath +
                                         wrapperFile1 +
@@ -253,11 +269,10 @@
                 " --switch ovsm --topo " + main.topoName + "," + main.currScale + "," + main.currScale
         for i in range( main.numCtrls ):
                 mnCmd += " --controller remote,ip=" + main.ONOSip[ i ]
-
-        stepResult = main.Mininet1.startNet(mnCmd=mnCmd)
+        stepResult = main.Mininet1.startNet( mnCmd=mnCmd )
         utilities.assert_equals( expect=main.TRUE,
                                  actual=stepResult,
-                                 onpass=main.topoName +
+                                  onpass=main.topoName +
                                     " topology started successfully",
                                  onfail=main.topoName +
                                     " topology failed to start" )
@@ -271,18 +286,26 @@
         """
         import json
         import time
+        # First capture
+        for i in range( 3 ):
+            # Calculate total time
+            main.allinfo[ 0 ][ 'info' + str( i )][ 'totalTime' ] = main.scaleTopoFunction.getInfoFromLog( main, main.searchTerm[ 'start' ], 'first', main.searchTerm[ 'end' ], 'last', index=i, funcMode='TD' )
+            # Calculate switch connection time
+            main.allinfo[ 0 ][ 'info' + str( i )][ 'swConnection' ] = main.scaleTopoFunction.getInfoFromLog( main, main.searchTerm[ 'start' ], 'first', main.searchTerm[ 'start' ], 'last', index=i, funcMode='TD' )
+            # Calculate the disconnecti rate
+            main.allinfo[ 0 ][ 'info' + str( i )][ 'disconnectRate' ] = main.scaleTopoFunction.getInfoFromLog( main, main.searchTerm[ 'Disconnect' ], 'num', main.searchTerm[ 'start' ], 'num', index=i, funcMode='DR' )
+        main.log.debug( "The data is " + str( main.allinfo[ 0 ] ) )
 
-        main.case( "Verifying topology: TORUS %sx%s" % (main.currScale, main.currScale) )
+        main.case( "Verifying topology: TORUS %sx%s" % ( main.currScale, main.currScale ) )
         main.caseExplanation = "Pinging all hosts and comparing topology " +\
                 "elements between Mininet and ONOS"
 
-        main.log.info( "Gathering topology information" )
+        main.log.info( "Gathering topology information")
         time.sleep( main.MNSleep )
         stepResult = main.TRUE
         main.step( "Comparing MN topology to ONOS topology" )
-
-        compareRetry=0
-        while compareRetry <3:
+        compareRetry = 0
+        while compareRetry < 3:
             #While loop for retry
             devices = main.topo.getAllDevices( main )
             ports = main.topo.getAllPorts( main )
@@ -429,8 +452,42 @@
         '''
             Report errors/warnings/exceptions
         '''
+        # Compare the slowest Node through total time of each node
+        slowestNode = 0
+        slowestTotalTime = 0
+        # Second capture
+        for i in range( 3 ):
+            # Calculate total time
+            main.allinfo[ 1 ][ 'info' + str( i )][ 'totalTime' ] = main.scaleTopoFunction.getInfoFromLog( main, main.searchTerm[ 'start' ], 'first', main.searchTerm[ 'end' ], 'last', index=i, funcMode='TD' )
+            # Compare the total time
+            if main.allinfo[ 1 ][ 'info' + str( i ) ][ 'totalTime' ] > slowestTotalTime:
+                slowestTotalTime = main.allinfo[ 1 ][ 'info' + str( i ) ][ 'totalTime' ]
+                slowestNode = i
+            # Calculate switch connection time
+            main.allinfo[ 1 ][ 'info' + str( i )][ 'swConnection' ] = main.scaleTopoFunction.getInfoFromLog( main, main.searchTerm[ 'start' ], 'first', main.searchTerm[ 'start' ], 'last', index=i, funcMode='TD' )
+            # Calculate the disconnecti rate
+            main.allinfo[ 1 ][ 'info' + str( i )][ 'disconnectRate' ] = main.scaleTopoFunction.getInfoFromLog( main, main.searchTerm[ 'Disconnect' ], 'num', main.searchTerm[ 'start' ],'num', index=i, funcMode='DR' )
+
+        if ( main.allinfo[ 0 ] != main.allinfo[ 1 ] ):
+            main.log.error( "The results of two capture are different!" )
+        main.log.debug( "The data is " + str( main.allinfo ) )
+        if main.writeData != -1:
+            main.log.info( "Write the date into database" )
+            # write the date into data base
+            with open( main.dbFilePath, "a" ) as dbFile:
+                temp = str( main.currScale )
+                temp += ",'baremetal1'"
+                # put result from second capture into data base
+                temp += "," + str( "%.2f" % main.allinfo[ 1 ][ 'info' + str( slowestNode )][ 'totalTime' ] )
+                temp += "," + str( "%.2f" % main.allinfo[ 1 ][ 'info' + str( slowestNode )][ 'swConnection' ] )
+                temp += "," + str( "%.2f" % main.allinfo[ 1 ][ 'info' + str( slowestNode )][ 'disconnectRate' ] )
+                temp += "\n"
+                dbFile.write( temp )
+        else:
+            main.log.error( "The data from log is wrong!" )
+        main.writeData = 1
         main.case( "Checking logs for errors, warnings, and exceptions" )
-        main.log.info("Error report: \n" )
+        main.log.info( "Error report: \n" )
         main.ONOSbench.logReport( main.ONOSip[ 0 ],
                                                             [ "INFO",
                                                               "FOLLOWER",
diff --git a/TestON/tests/SCPF/SCPFscaleTopo/dependencies/scaleTopoFunction.py b/TestON/tests/SCPF/SCPFscaleTopo/dependencies/scaleTopoFunction.py
index 075f4f2..d05e2a7 100644
--- a/TestON/tests/SCPF/SCPFscaleTopo/dependencies/scaleTopoFunction.py
+++ b/TestON/tests/SCPF/SCPFscaleTopo/dependencies/scaleTopoFunction.py
@@ -9,6 +9,74 @@
 def __init__( self ):
     self.default = ''
 
+def getTimestampFromString( main, targetString ):
+    #Get time string from the target string
+    try:
+        assert type( targetString ) is str
+        timeString = targetString.split( ' | ' )
+        timeString = timeString[ 0 ]
+        from datetime import datetime
+        # convert time string to timestamp
+        t = datetime.strptime( timeString, "%Y-%m-%d %H:%M:%S,%f" )
+        import time
+        timestamp = time.mktime( t.timetuple() )
+        timestamp += int( t.microsecond / 1000 ) / 1000.0
+        return timestamp
+    except AssertionError:
+        main.log.error( "Got nothing firom log" )
+        return -1
+    except IndexError:
+        main.log.error( "Time string index error" )
+        return -1
+    except ValueError:
+        main.log.error( "Got wrong string from log" )
+        return -1
+
+def getInfoFromLog( main, term1, mode1, term2, mode2, index=0, funcMode='TD' ):
+    '''
+    Description:
+        Get needed informations of the search term from karaf.log
+        Includes onosclidriver functions
+    Function mode:
+        TD (time difference):
+            Get time difference between start and end
+            Term1: startTerm
+            Term2: endTerm
+        DR (disconnect rate):
+            Get switch disconnect rate
+            Term1: disconnectTerm
+            Term2: connectTerm
+
+    '''
+    try:
+        termInfo1 = main.CLIs[ index ].logSearch( term1, mode=mode1 )
+        termInfo2 = main.CLIs[ index ].logSearch( term2, mode=mode2 )
+        if funcMode == 'TD':
+            startTime = getTimestampFromString( main, termInfo1[0] )
+            endTime = getTimestampFromString ( main, termInfo2[0] )
+            if startTime == -1 or endTime == -1:
+                main.log.error( "Wrong Time!" )
+                main.writeData = -1
+                return -1
+            return endTime - startTime
+        if funcMode == 'DR':
+            #In this mode, termInfo1 means the total number of switch disconnection and
+            #termInfo2 means the total number of new switch connection
+            #termInfo2 - termInfo1 means the actual real number of switch connection.
+            disconnection = int( termInfo1 ) * 1.0
+            expectConnection = int( main.currScale ) ** 2
+            realConnection = int( termInfo2 ) - int( termInfo1 )
+            if expectConnection != realConnection:
+                main.log.error( "The number of real switch connection doesn't match the number of expected connection" )
+                main.writeData = -1
+                return -1
+            rate = disconnection / expectConnection
+            return rate
+    except IndexError:
+        main.log.error( "Catch the wrong information of search term" )
+        main.writeData = -1
+        return -1
+
 def testTopology( main, topoFile='', args='', mnCmd='', timeout=300, clean=True ):
     """
     Description: