diff -r 1af5c1be89f8 -r 92d87f2e53c2 tools/e32test-driver/qemuruntest.py --- /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 . + +# 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"