## 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 sysmswindows = (sys.platform == "win32")# import the following so we can kill QEMUif mswindows:# import win32api import signalelse: import signalimport osimport timeimport reimport subprocessfrom 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.timeclass 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"