tools/e32test-driver/qemuruntest.py
changeset 34 92d87f2e53c2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/e32test-driver/qemuruntest.py	Fri Jan 15 09:07:44 2010 +0000
@@ -0,0 +1,199 @@
+#
+# Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+# All rights reserved.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser General Public License for more details.
+# 
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Launch QEMU for SVP with a specified ROM image and core using a COM port for IO
+# Uses Python's Popen class for process control.
+# Test output is captured by invoking QEMU in -nographic mode. This redirects serial output to stdout which can then be PIPE'd
+# using Popen.
+# Tests which hang(or crash into the the crash debugger) are detected using a trivial 'watchdog'. IWBN to use e.g. 'select'
+# with a timeout, but this won't work on Windoze, which only supports timeout's on sockets. If the watchdog timeouts out QEMU is killed.
+# When the test suite runs to (recognizable) completion QEMU is killed. Unfortunately this appears to require an OS specific
+# solution. NB unrecognized completion will result in the watchdog killing QEMU.
+# QemuTestRunner collects  output into LineTimeInfo objects. These record the time at which each line was received. The time can be used as a crude
+# measure of how long a test took to execute.
+# The raw data gathered from running the tests can be retrieved using GetResults. This returns a list of LineTimeInfo objects.
+
+import sys
+mswindows = (sys.platform == "win32")
+
+# import the following so we can kill QEMU
+
+if mswindows:
+#    import win32api
+    import signal
+else:
+    import signal
+
+import os
+
+import time
+
+import re
+
+import subprocess
+from subprocess import *
+
+from stat import *
+
+import watchdog
+
+__all__ = ["QemuTestRunner"]
+
+class LineTimeInfo(object):
+    def __init__(self, line, atime):
+        self.line = line
+        self.time = atime
+
+    def GetLine(self):
+        return self.line
+
+    def GetTime(self):
+        return self.time
+
+class QemuTestRunner(object):
+    def __init__(self, qemupath, cpu, rompath, board = 'syborg', endOfTestFn=None, displayp=False, dataFile = None):
+        """Create new QemuTestRunner instance."""
+        self.qemupath = qemupath
+        self.board = board
+        self.cpu = cpu
+        self.rompath = rompath
+        self.endOfTestFn = endOfTestFn
+        self.displayp = displayp
+        #self.cmd = qemupath + " -M syborg -cpu " + cpu + " -kernel " + rompath + " -nographic"
+        self.cmd = "%s -M %s -cpu %s -kernel %s -nographic" % (qemupath, board, cpu, rompath)
+        self.endOfTestPattern = re.compile('RUNTESTS: Completed test script')
+        self.lineTimeInfo = []
+        self.id = None
+        self.dataFile = dataFile
+        self.watchdog = watchdog.WatchDog(900, lambda : self.KillSim())
+        
+    def Run(self):
+        self.lineTimeInfo = []
+        output = False
+        self.timeStarted = time.gmtime()
+        self.id = time.strftime("%d-%m%--%Y-%H-%M-%S", self.timeStarted)
+        if self.dataFile != None:
+            filename = self.dataFile + "-" + self.GetRunId() + "-data.txt"
+            self.dataFileName = filename
+            output = open(filename, 'wb')
+        p = Popen( self.cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE )
+        self.popen = p
+        stdin = p.stdin
+        stdout = p.stdout
+        stop = False
+
+        if self.displayp:
+            print >> sys.stdout, self.cmd
+            
+        self.watchdog.Start()
+        try:
+            while p.poll() == None and not stop:
+                line = stdout.readline()
+                atime = time.clock()
+                self.watchdog.Reset()
+                if self.displayp and p.returncode == None:
+                    print >> sys.stdout , line
+                if output and p.returncode == None:
+                    print >> output , line
+                if p.returncode == None:
+                    self.lineTimeInfo.append(LineTimeInfo(line, atime))
+                    if self.endOfTestFn != None:
+                        stop = self.endOfTestFn(line)
+                    else:
+                        stop = self.EndOfTestp(line)
+        finally:
+            self.timeEnded = time.gmtime()
+            self.watchdog.Stop()
+            if output:
+                output.close()
+            self.testSuiteFinished = stop;
+                
+        if p.returncode == None:
+            self.KillSim()
+            return True
+        else:
+            return False
+
+    def GetDataFileName(self):
+        return self.dataFileName
+
+    def TestSuiteFinishedp(self):
+        return self.testSuiteFinished
+    
+    def EndOfTestp(self, l):
+        return re.match(self.endOfTestPattern,l) != None
+
+    def KillSim(self):
+#        if mswindows:
+#            win32api.TerminateProcess(int(self.popen._handle), -1)
+#        else:
+            os.kill(slef.popen.pid, signal.SIGKILL)
+
+    def GetResults(self):
+        return self.lineTimeInfo
+
+    def GetRomName(self):
+        return self.rompath
+
+    def GetRunId(self):
+        return self.id
+
+    def GetSummary(self):
+        simStat = os.stat(self.qemupath)
+        simSummary = "QEMU Executable: %s size: %d creation time: %d\n" % (self.qemupath, simStat[ST_SIZE], simStat[ST_CTIME])
+        boardSummary ="Board: %s\n" %  self.board
+        cpuSummary = "CPU: %s\n" % self.cpu
+        romStat = os.stat(self.rompath)
+        romSummary = "ROM image: %s size: %d creation date: %d\n" % (self.rompath, romStat[ST_SIZE], romStat[ST_CTIME])
+        timeFormat = "%d-%m%--%Y %H:%M:%S"
+        startTime = "Start time: " + time.strftime(timeFormat, self.timeStarted) + "\n"
+        endTime = "End time: " + time.strftime(timeFormat, self.timeEnded) + "\n"
+        status = "Testsuite did not complete\n"
+        if self.TestSuiteFinishedp():
+            status = "Testsuite completed\n"
+        return simSummary + boardSummary + cpuSummary + romSummary + startTime + endTime + status
+
+    def GetReportFileName(self):
+        return self.GetRomName() + "-" + self.GetRunId() + "-results-summary.txt"
+
+class PseudoRunner(QemuTestRunner):
+    def __init__(self, input):
+        #self.qemupath = qemupath
+        #self.board = board
+        #self.cpu = cpu
+        #self.rompath = rompath
+        #self.endOfTestFn = endOfTestFn
+        #self.displayp = displayp
+        #self.cmd = qemupath + " -M syborg -cpu " + cpu + " -kernel " + rompath + " -nographic"
+        #self.endOfTestPattern = re.compile('RUNTESTS: Completed test script')
+        self.lineTimeInfo = []
+        #self.id = None
+        self.dataFile = input
+        for line in open(input):
+            self.lineTimeInfo.append(LineTimeInfo(line, 0))
+        
+    def GetRomName(self):
+        return "Unknown"
+
+    def GetRunId(self):
+        return None
+
+    def GetSummary(self):
+        return ""
+
+    def GetReportFileName(self):
+        return "Runtest-Summary.txt"