tools/e32test-driver/qemuruntest.py
changeset 34 92d87f2e53c2
equal deleted inserted replaced
33:1af5c1be89f8 34:92d87f2e53c2
       
     1 #
       
     2 # Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 # All rights reserved.
       
     4 #
       
     5 # This program is free software: you can redistribute it and/or modify
       
     6 # it under the terms of the GNU Lesser General Public License as published by
       
     7 # the Free Software Foundation, either version 3 of the License, or
       
     8 # (at your option) any later version.
       
     9 #
       
    10 # This program is distributed in the hope that it will be useful,
       
    11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    13 # GNU Lesser General Public License for more details.
       
    14 # 
       
    15 # You should have received a copy of the GNU Lesser General Public License
       
    16 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
       
    17 
       
    18 # Launch QEMU for SVP with a specified ROM image and core using a COM port for IO
       
    19 # Uses Python's Popen class for process control.
       
    20 # Test output is captured by invoking QEMU in -nographic mode. This redirects serial output to stdout which can then be PIPE'd
       
    21 # using Popen.
       
    22 # Tests which hang(or crash into the the crash debugger) are detected using a trivial 'watchdog'. IWBN to use e.g. 'select'
       
    23 # 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.
       
    24 # When the test suite runs to (recognizable) completion QEMU is killed. Unfortunately this appears to require an OS specific
       
    25 # solution. NB unrecognized completion will result in the watchdog killing QEMU.
       
    26 # QemuTestRunner collects  output into LineTimeInfo objects. These record the time at which each line was received. The time can be used as a crude
       
    27 # measure of how long a test took to execute.
       
    28 # The raw data gathered from running the tests can be retrieved using GetResults. This returns a list of LineTimeInfo objects.
       
    29 
       
    30 import sys
       
    31 mswindows = (sys.platform == "win32")
       
    32 
       
    33 # import the following so we can kill QEMU
       
    34 
       
    35 if mswindows:
       
    36 #    import win32api
       
    37     import signal
       
    38 else:
       
    39     import signal
       
    40 
       
    41 import os
       
    42 
       
    43 import time
       
    44 
       
    45 import re
       
    46 
       
    47 import subprocess
       
    48 from subprocess import *
       
    49 
       
    50 from stat import *
       
    51 
       
    52 import watchdog
       
    53 
       
    54 __all__ = ["QemuTestRunner"]
       
    55 
       
    56 class LineTimeInfo(object):
       
    57     def __init__(self, line, atime):
       
    58         self.line = line
       
    59         self.time = atime
       
    60 
       
    61     def GetLine(self):
       
    62         return self.line
       
    63 
       
    64     def GetTime(self):
       
    65         return self.time
       
    66 
       
    67 class QemuTestRunner(object):
       
    68     def __init__(self, qemupath, cpu, rompath, board = 'syborg', endOfTestFn=None, displayp=False, dataFile = None):
       
    69         """Create new QemuTestRunner instance."""
       
    70         self.qemupath = qemupath
       
    71         self.board = board
       
    72         self.cpu = cpu
       
    73         self.rompath = rompath
       
    74         self.endOfTestFn = endOfTestFn
       
    75         self.displayp = displayp
       
    76         #self.cmd = qemupath + " -M syborg -cpu " + cpu + " -kernel " + rompath + " -nographic"
       
    77         self.cmd = "%s -M %s -cpu %s -kernel %s -nographic" % (qemupath, board, cpu, rompath)
       
    78         self.endOfTestPattern = re.compile('RUNTESTS: Completed test script')
       
    79         self.lineTimeInfo = []
       
    80         self.id = None
       
    81         self.dataFile = dataFile
       
    82         self.watchdog = watchdog.WatchDog(900, lambda : self.KillSim())
       
    83         
       
    84     def Run(self):
       
    85         self.lineTimeInfo = []
       
    86         output = False
       
    87         self.timeStarted = time.gmtime()
       
    88         self.id = time.strftime("%d-%m%--%Y-%H-%M-%S", self.timeStarted)
       
    89         if self.dataFile != None:
       
    90             filename = self.dataFile + "-" + self.GetRunId() + "-data.txt"
       
    91             self.dataFileName = filename
       
    92             output = open(filename, 'wb')
       
    93         p = Popen( self.cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE )
       
    94         self.popen = p
       
    95         stdin = p.stdin
       
    96         stdout = p.stdout
       
    97         stop = False
       
    98 
       
    99         if self.displayp:
       
   100             print >> sys.stdout, self.cmd
       
   101             
       
   102         self.watchdog.Start()
       
   103         try:
       
   104             while p.poll() == None and not stop:
       
   105                 line = stdout.readline()
       
   106                 atime = time.clock()
       
   107                 self.watchdog.Reset()
       
   108                 if self.displayp and p.returncode == None:
       
   109                     print >> sys.stdout , line
       
   110                 if output and p.returncode == None:
       
   111                     print >> output , line
       
   112                 if p.returncode == None:
       
   113                     self.lineTimeInfo.append(LineTimeInfo(line, atime))
       
   114                     if self.endOfTestFn != None:
       
   115                         stop = self.endOfTestFn(line)
       
   116                     else:
       
   117                         stop = self.EndOfTestp(line)
       
   118         finally:
       
   119             self.timeEnded = time.gmtime()
       
   120             self.watchdog.Stop()
       
   121             if output:
       
   122                 output.close()
       
   123             self.testSuiteFinished = stop;
       
   124                 
       
   125         if p.returncode == None:
       
   126             self.KillSim()
       
   127             return True
       
   128         else:
       
   129             return False
       
   130 
       
   131     def GetDataFileName(self):
       
   132         return self.dataFileName
       
   133 
       
   134     def TestSuiteFinishedp(self):
       
   135         return self.testSuiteFinished
       
   136     
       
   137     def EndOfTestp(self, l):
       
   138         return re.match(self.endOfTestPattern,l) != None
       
   139 
       
   140     def KillSim(self):
       
   141 #        if mswindows:
       
   142 #            win32api.TerminateProcess(int(self.popen._handle), -1)
       
   143 #        else:
       
   144             os.kill(slef.popen.pid, signal.SIGKILL)
       
   145 
       
   146     def GetResults(self):
       
   147         return self.lineTimeInfo
       
   148 
       
   149     def GetRomName(self):
       
   150         return self.rompath
       
   151 
       
   152     def GetRunId(self):
       
   153         return self.id
       
   154 
       
   155     def GetSummary(self):
       
   156         simStat = os.stat(self.qemupath)
       
   157         simSummary = "QEMU Executable: %s size: %d creation time: %d\n" % (self.qemupath, simStat[ST_SIZE], simStat[ST_CTIME])
       
   158         boardSummary ="Board: %s\n" %  self.board
       
   159         cpuSummary = "CPU: %s\n" % self.cpu
       
   160         romStat = os.stat(self.rompath)
       
   161         romSummary = "ROM image: %s size: %d creation date: %d\n" % (self.rompath, romStat[ST_SIZE], romStat[ST_CTIME])
       
   162         timeFormat = "%d-%m%--%Y %H:%M:%S"
       
   163         startTime = "Start time: " + time.strftime(timeFormat, self.timeStarted) + "\n"
       
   164         endTime = "End time: " + time.strftime(timeFormat, self.timeEnded) + "\n"
       
   165         status = "Testsuite did not complete\n"
       
   166         if self.TestSuiteFinishedp():
       
   167             status = "Testsuite completed\n"
       
   168         return simSummary + boardSummary + cpuSummary + romSummary + startTime + endTime + status
       
   169 
       
   170     def GetReportFileName(self):
       
   171         return self.GetRomName() + "-" + self.GetRunId() + "-results-summary.txt"
       
   172 
       
   173 class PseudoRunner(QemuTestRunner):
       
   174     def __init__(self, input):
       
   175         #self.qemupath = qemupath
       
   176         #self.board = board
       
   177         #self.cpu = cpu
       
   178         #self.rompath = rompath
       
   179         #self.endOfTestFn = endOfTestFn
       
   180         #self.displayp = displayp
       
   181         #self.cmd = qemupath + " -M syborg -cpu " + cpu + " -kernel " + rompath + " -nographic"
       
   182         #self.endOfTestPattern = re.compile('RUNTESTS: Completed test script')
       
   183         self.lineTimeInfo = []
       
   184         #self.id = None
       
   185         self.dataFile = input
       
   186         for line in open(input):
       
   187             self.lineTimeInfo.append(LineTimeInfo(line, 0))
       
   188         
       
   189     def GetRomName(self):
       
   190         return "Unknown"
       
   191 
       
   192     def GetRunId(self):
       
   193         return None
       
   194 
       
   195     def GetSummary(self):
       
   196         return ""
       
   197 
       
   198     def GetReportFileName(self):
       
   199         return "Runtest-Summary.txt"