tools/e32test-driver/qemuruntest.py
author Gareth Stockwell <gareth.stockwell@accenture.com>
Mon, 06 Sep 2010 16:25:43 +0100
changeset 107 3bc1a978be44
parent 34 92d87f2e53c2
permissions -rwxr-xr-x
Fix for Bug 3671 - QEMU GDB stub listens on IPv6-only port on Windows 7 The connection string used by the GDB stub does not specify which version of the Internet Protocol should be used by the port on which it listens. On host platforms with IPv6 support, such as Windows 7, this means that the stub listens on an IPv6-only port. Since the GDB client uses IPv4, this means that the client cannot connect to QEMU.

#
# 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"