mobile/perfrunner.py
author Chris AtLee <catlee@mozilla.com>
Thu, 24 Sep 2009 08:57:51 -0400
changeset 1545 ec36de49b85abfc3017f167d3cb5b2fca3368fe4
parent 1127 7cb377ca0adac93a822c173187fff863ae2506a4
permissions -rw-r--r--
Bug 516820 - Turn off tiger tests on m-c, and support per-OS testing. p=anodelman r=bhearsum

# -*- Python -*-

from twisted.python import log
from buildbot import buildset
from buildbot.scheduler import Scheduler
from buildbot.process.buildstep import BuildStep
from buildbot.process.factory import BuildFactory
from buildbot.buildset import BuildSet
from buildbot.sourcestamp import SourceStamp
from buildbot.steps.shell import ShellCommand, WithProperties
from buildbot.steps.transfer import FileDownload
from buildbot.status.builder import SUCCESS, WARNINGS, FAILURE, SKIPPED, EXCEPTION
import re, urllib, sys, os
from time import strptime, strftime, localtime
from datetime import datetime
from os import path
import copy

MozillaEnvironments = { }

# platform SDK location.  we can build both from one generic template.
# modified from vc8 environment
MozillaEnvironments['vc8perf'] = {
    "MOZ_CRASHREPORTER_NO_REPORT": '1',
    "MOZ_NO_REMOTE": '1',
    "NO_EM_RESTART": '1',
    "XPCOM_DEBUG_BREAK": 'warn',
    "CYGWINBASE": 'C:\\cygwin',
    "PATH": 'C:\\Python24;' + \
            'C:\\Python24\\Scripts;' + \
            'C:\\cygwin\\bin;' + \
            'C:\\WINDOWS\\System32;' + \
            'C:\\program files\\gnuwin32\\bin;' + \
            'C:\\WINDOWS;'
}

MozillaEnvironments['linux'] = {
    "MOZ_CRASHREPORTER_NO_REPORT": '1',
    "MOZ_NO_REMOTE": '1',
    "NO_EM_RESTART": '1',
    "XPCOM_DEBUG_BREAK": 'warn',
    "DISPLAY": ":0",
}

MozillaEnvironments['mac'] = {
    "MOZ_NO_REMOTE": '1',
    "NO_EM_RESTART": '1',
    "XPCOM_DEBUG_BREAK": 'warn',
    "MOZ_CRASHREPORTER_NO_REPORT": '1',
    # for extracting dmg's
    "PAGER": '/bin/cat',
}

class MultiBuildScheduler(Scheduler):
    """Trigger N (default three) build requests based upon the same change request"""
    def __init__(self, numberOfBuildsToTrigger=3, **kwargs):
        self.numberOfBuildsToTrigger = numberOfBuildsToTrigger
        Scheduler.__init__(self, **kwargs)

    def fireTimer(self):
        self.timer = None
        self.nextBuildTime = None
        changes = self.importantChanges + self.unimportantChanges
        self.importantChanges = []
        self.unimportantChanges = []

        # submit
        for i in range(0, self.numberOfBuildsToTrigger):
            bs = buildset.BuildSet(self.builderNames, SourceStamp(changes=changes))
            self.submitBuildSet(bs)


class MozillaWget(ShellCommand):
    """Download built Firefox client from dated staging directory."""
    haltOnFailure = True
    
    def __init__(self, branch="HEAD", command=None, **kwargs):
        ShellCommand.__init__(self, **kwargs)
        self.addFactoryArguments(branch=branch, command=command)
        self.branch = branch
        self.command = command or ["wget"]

    def setBuild(self, build):
        ShellCommand.setBuild(self, build)
        self.changes = build.source.changes
        #a full url is always provided by sendchange
        self.fileURL = self.changes[-1].files[0]
        self.filename = os.path.basename(self.fileURL)
        # Lie about when we started so the talos runs line up with builds on
        # the waterfall
        try:
            timestamp = int(os.path.basename(os.path.dirname(self.fileURL)))
            self.changes[-1].when = timestamp
        except:
            pass
    
    def getFilename(self):
        return self.filename
    
    def describe(self, done=False):
        return ["Wget Download"]
    
    def start(self):
        if self.branch:
            self.setProperty("fileURL", self.fileURL)
            self.setProperty("filename", self.filename)
        self.setCommand(["wget", "-nv", "-N", self.fileURL])
        ShellCommand.start(self)
    
    def evaluateCommand(self, cmd):
        superResult = ShellCommand.evaluateCommand(self, cmd)
        if SUCCESS != superResult:
            return FAILURE
        if None != re.search('ERROR', cmd.logs['stdio'].getText()):
            return FAILURE
        return SUCCESS


class MozillaWgetSymbols(ShellCommand):
    """Download the matching symbol package with a build."""
    haltOnFailure = False
    _suffixes = ('.tar.bz2', '.dmg', '.zip')

    def __init__(self, **kwargs):
        #def setBuild(self, build):
        #    ShellCommand.setBuild(self, build)
        ShellCommand.__init__(self, **kwargs)

    def describe(self, done=False):
        return ["Wget symbols"]

    def start(self):
        buildURL = self.getProperty('fileURL')

        for suffix in self._suffixes:
            if buildURL.endswith(suffix):
                self.symbolsURL = buildURL[:-len(suffix)] + '.crashreporter-symbols.zip'
                break

        symbolsFile = self.symbolsURL.split('/')[-1]
        self.setProperty('symbolsFile', symbolsFile)
        self.setCommand(['wget', '-nv', '-N', self.symbolsURL])
        ShellCommand.start(self)


class MozillaUnpackSymbols(ShellCommand):
    def __init__(self, **kwargs):
        ShellCommand.__init__(self, **kwargs)

    def describe(self, done=False):
        return ["Unpack symbols"]

    def start(self):
        self.setCommand(['unzip', '-o', '-d', 'symbols', self.getProperty('symbolsFile')])
        ShellCommand.start(self)


class MozillaInstallZip(ShellCommand):
    """Install given file, unzipping to executablePath"""
    
    def __init__(self, filename="", branch="", command=None, **kwargs):
        ShellCommand.__init__(self, **kwargs)
        self.addFactoryArguments(filename=filename, branch=branch,
                                 command=command)
        self.filename = filename
        self.branch = branch
        self.command = command or ["unzip", "-o"]
    
    def describe(self, done=False):
        return ["Install zip"]
    
    def start(self):
        # removed the mkdir because this happens on the master, not the slave
        if not self.filename:
            if self.branch:
                self.filename = self.getProperty("filename")
            else:
                return FAILURE
        if self.filename:
            self.command = self.command[:] + [self.filename]
        ShellCommand.start(self)
    
    def evaluateCommand(self, cmd):
        superResult = ShellCommand.evaluateCommand(self, cmd)
        if SUCCESS != superResult:
            return FAILURE
        if None != re.search('ERROR', cmd.logs['stdio'].getText()):
            return FAILURE
        if None != re.search('Usage:', cmd.logs['stdio'].getText()):
            return FAILURE
        return SUCCESS
    

class MozillaUpdateConfig(ShellCommand):
    """Configure YAML file for run_tests.py"""
   
    def __init__(self, branch, executablePath, branchName, addOptions=[],
                 useSymbols=False, **kwargs):
        ShellCommand.__init__(self, **kwargs)
        self.addFactoryArguments(branch=branch, executablePath=executablePath,
                                 branchName=branchName, addOptions=addOptions,
                                 useSymbols=useSymbols)
        self.branch = branch
        self.exePath = executablePath
        self.branchName = branchName
        self.addOptions = addOptions
        self.useSymbols = useSymbols

    def setBuild(self, build):
        ShellCommand.setBuild(self, build)
        self.title = build.slavename
        self.changes = build.source.changes
        self.buildid = strftime("%Y%m%d%H%M", localtime(self.changes[-1].when))


        extraopts = copy.copy(self.addOptions)
        if self.useSymbols:
            extraopts += ['--symbolsPath', '../symbols']

        if not self.command:
            self.setCommand(["python", "PerfConfigurator.py", "-v", "-e", self.exePath, "-t", self.title, "-b", self.branch, "-d", self.buildid, '--branchName', self.branchName] + extraopts)

    def describe(self, done=False):
        return ["Update config"]
    
    def evaluateCommand(self, cmd):
        superResult = ShellCommand.evaluateCommand(self, cmd)
        if SUCCESS != superResult:
            return FAILURE
        stdioText = cmd.logs['stdio'].getText()
        if None != re.search('ERROR', stdioText):
            return FAILURE
        if None != re.search('USAGE:', stdioText):
            return FAILURE
        configFileMatch = re.search('outputName\s*=\s*(\w*?.yml)', stdioText)
        if not configFileMatch:
            return FAILURE
        else:
            self.setProperty("configFile", configFileMatch.group(1))
        return SUCCESS
    

class MozillaRunPerfTests(ShellCommand):
    """Run the performance tests"""
    
    def __init__(self, branch, command=None, **kwargs):
        ShellCommand.__init__(self, **kwargs)
        self.addFactoryArguments(branch=branch, command=command)
        self.branch = branch
        self.command = command or ["python", "run_tests.py"]
    
    def describe(self, done=False):
        return ["Run performance tests"]
    
    def createSummary(self, log):
        summary = []
        for line in log.readlines():
            if "RETURN:" in line:
                summary.append(line.replace("RETURN:", "TinderboxPrint:"))
            if "FAIL:" in line:
                summary.append(line.replace("FAIL:", "TinderboxPrint:FAIL:"))
        self.addCompleteLog('summary', "\n".join(summary))
    
    def start(self):
        """docstring for start"""
        self.command = copy.copy(self.command)
        self.command.append(self.getProperty("configFile"))
        ShellCommand.start(self)
    
    def evaluateCommand(self, cmd):
        superResult = ShellCommand.evaluateCommand(self, cmd)
        stdioText = cmd.logs['stdio'].getText()
        if SUCCESS != superResult:
            return FAILURE
        if None != re.search('ERROR', stdioText):
            return FAILURE
        if None != re.search('USAGE:', stdioText):
            return FAILURE
        if None != re.search('FAIL:', stdioText):
            return WARNINGS
        return SUCCESS

class MozillaInstallTarBz2(ShellCommand):
    """Install given file, unzipping to executablePath"""
    
    def __init__(self, filename="", branch="", command=None, **kwargs):
        ShellCommand.__init__(self, **kwargs)
        self.addFactoryArguments(filename=filename, branch=branch,
                                 command=command)
        self.filename = filename
        self.branch = branch
        self.command = command or ["tar", "-jvxf"]
    
    def describe(self, done=False):
        return ["Install tar.bz2"]
    
    def start(self):
        if not self.filename:
            if self.branch:
                self.filename = self.getProperty("filename")
            else:
                return FAILURE
        if self.filename:
            self.command = self.command[:] + [self.filename]
        ShellCommand.start(self)
    
    def evaluateCommand(self, cmd):
        superResult = ShellCommand.evaluateCommand(self, cmd)
        if SUCCESS != superResult:
            return FAILURE
        return SUCCESS

class MozillaInstallTarGz(ShellCommand):
    """Install given file, unzipping to executablePath"""
    
    def __init__(self, filename="", branch="", command=None, **kwargs):
        ShellCommand.__init__(self, **kwargs)
        self.addFactoryArguments(filename=filename, branch=branch,
                                 command=command)
        self.filename = filename
        self.branch = branch
        self.command = command or ["tar", "-zvxf"]
    
    def describe(self, done=False):
        return ["Install tar.gz"]
    
    def start(self):
        if not self.filename:
            if self.branch:
                self.filename = self.getProperty("filename")
            else:
                return FAILURE
        if self.filename:
            self.command = self.command[:] + [self.filename]
        ShellCommand.start(self)
    
    def evaluateCommand(self, cmd):
        superResult = ShellCommand.evaluateCommand(self, cmd)
        if SUCCESS != superResult:
            return FAILURE
        return SUCCESS

class MozillaInstallDmg(ShellCommand):
    """Install given file, copying to workdir"""
    
    def __init__(self, filename="", branch="", command=None, **kwargs):
        ShellCommand.__init__(self, **kwargs)
        self.addFactoryArguments(filename=filename, branch=branch,
                                 command=command)
        self.filename = filename
        self.branch = branch
        self.command = command or ["bash", "installdmg.sh"]
    
    def describe(self, done=False):
        return ["Install dmg"]
    
    def start(self):
        if not self.filename:
            if self.branch:
                self.filename = self.getProperty("filename")
            else:
                return FAILURE
        if self.filename:
            self.command = self.command[:] + [self.filename]
        ShellCommand.start(self)
    
    def evaluateCommand(self, cmd):
        superResult = ShellCommand.evaluateCommand(self, cmd)
        if SUCCESS != superResult:
            return FAILURE
        return SUCCESS

class MozillaInstallDmgEx(ShellCommand):
    """Install given file, copying to workdir"""
    #This is a temporary class to test the new InstallDmg script without affecting the production mac machines
    # if this works everything should be switched over the using it
    
    def __init__(self, filename="", branch="", command=None, **kwargs):
        ShellCommand.__init__(self, **kwargs)
        self.addFactoryArguments(filename=filename, branch=branch,
                                 command=command)
        self.filename = filename
        self.branch = branch
        self.command = command or ["expect", "installdmg.ex"]
    
    def describe(self, done=False):
        return ["Install dmg"]
    
    def start(self):
        if not self.filename:
            if self.branch:
                self.filename = self.getProperty("filename")
            else:
                return FAILURE
        if self.filename:
            self.command = self.command[:] + [self.filename]
        ShellCommand.start(self)
    
    def evaluateCommand(self, cmd):
        superResult = ShellCommand.evaluateCommand(self, cmd)
        if SUCCESS != superResult:
            return FAILURE
        return SUCCESS

class TalosFactory(BuildFactory):
    """Create working talos build factory"""

    winClean   = ["touch temp.zip &", "rm", "-rf", "*.zip", "talos/", "firefox/", "symbols/"]
    macClean   = "rm -vrf *"
    linuxClean = "rm -vrf *"

    def __init__(self, OS, envName, buildBranch, branchName, fetchSymbols, configOptions, buildPath, talosCmd, customManifest='', cvsRoot=":pserver:anonymous@cvs-mirror.mozilla.org:/cvsroot"):
        BuildFactory.__init__(self)
        if OS in ('linux', 'linuxbranch',):
            cleanCmd = self.linuxClean
        elif OS in ('win',):
            cleanCmd = self.winClean
        else:
            cleanCmd = self.macClean
        self.addStep(ShellCommand(
                           workdir=".",
                           description="Cleanup",
                           command=cleanCmd,
                           env=MozillaEnvironments[envName]))
        self.addStep(FileDownload(
                           mastersrc="scripts/count_and_reboot.py",
                           slavedest="count_and_reboot.py",
                           workdir="."))
        self.addStep(ShellCommand(
                           command=["cvs", "-d", cvsRoot, "co", "-d", "talos",
                                    "mozilla/testing/performance/talos"],
                           workdir=".",
                           description="checking out talos",
                           haltOnFailure=True,
                           flunkOnFailure=True,
                           env=MozillaEnvironments[envName]))
        self.addStep(FileDownload(
                           mastersrc="scripts/generate-tpcomponent.py",
                           slavedest="generate-tpcomponent.py",
                           workdir="talos/page_load_test"))
        if customManifest != '':
            self.addStep(FileDownload(
                           mastersrc=customManifest,
                           slavedest="manifest.txt",
                           workdir="talos/page_load_test"))
        self.addStep(ShellCommand(
                           command=["python", "generate-tpcomponent.py"],
                           workdir="talos/page_load_test",
                           description="setting up pageloader",
                           haltOnFailure=True,
                           flunkOnFailure=True,
                           env=MozillaEnvironments[envName]))
        self.addStep(MozillaWget(
                           workdir=".",
                           branch=buildBranch,
                           env=MozillaEnvironments[envName]))
        if fetchSymbols:
            self.addStep(MozillaWgetSymbols(workdir="."))
            self.addStep(MozillaUnpackSymbols(workdir="."))
        #install the browser, differs based upon platform
        if OS == 'linux':
            self.addStep(MozillaInstallTarBz2(
                               workdir=".",
                               branch=buildBranch,
                               haltOnFailure=True,
                               env=MozillaEnvironments[envName]))
        elif OS == 'linuxbranch': #special case for old linux builds
            self.addStep(MozillaInstallTarGz(
                           workdir=".",
                           branch=buildBranch,
                           haltOnFailure=True,
                           env=MozillaEnvironments[envName]))
        elif OS == 'win':
            self.addStep(MozillaInstallZip(
                               workdir=".",
                               branch=buildBranch,
                               haltOnFailure=True,
                               env=MozillaEnvironments[envName]))
            self.addStep(ShellCommand(
                               workdir="firefox/",
                               flunkOnFailure=False,
                               warnOnFailure=False,
                               description="chmod files (see msys bug)",
                               command=["chmod", "-v", "-R", "a+x", "."],
                               env=MozillaEnvironments[envName]))
        elif OS == 'tiger':
            self.addStep(FileDownload(
                           mastersrc="scripts/installdmg.sh",
                           slavedest="installdmg.sh",
                           workdir="."))
            self.addStep(MozillaInstallDmg(
                               workdir=".",
                               branch=buildBranch,
                               haltOnFailure=True,
                               env=MozillaEnvironments[envName]))
        else: #leopard
            self.addStep(FileDownload(
                           mastersrc="scripts/installdmg.ex",
                           slavedest="installdmg.ex",
                           workdir="."))
            self.addStep(MozillaInstallDmgEx(
                               workdir=".",
                               branch=buildBranch,
                               haltOnFailure=True,
                               env=MozillaEnvironments[envName]))
        self.addStep(MozillaUpdateConfig(
                           workdir="talos/",
                           branch=buildBranch,
                           branchName=branchName,
                           haltOnFailure=True,
                           executablePath=buildPath,
                           addOptions=configOptions,
                           env=MozillaEnvironments[envName],
                           useSymbols=fetchSymbols))
        self.addStep(MozillaRunPerfTests(
                           warnOnWarnings=True,
                           workdir="talos/",
                           branch=buildBranch,
                           timeout=21600,
                           haltOnFailure=False,
                           command=talosCmd,
                           env=MozillaEnvironments[envName]))
        self.addStep(ShellCommand(
                           flunkOnFailure=False,
                           warnOnFailure=False,
                           alwaysRun=True,
                           workdir='.',
                           description="reboot after 1 test run",
                           command=["python", "count_and_reboot.py", "-f", "../talos_count.txt", "-n", "1", "-z"],
                           env=MozillaEnvironments[envName]))


#
# Just like MozillaRunPerfTests, except:
#  - hackTbPrint/printId to fix multiple test run tinderboxPrints
#  - remove describe() since it's too generic for multiple test runs
#  - remove start() since I'm already passing the command
#
class MaemoRunPerfTests(ShellCommand):
    """Run the performance tests"""
       
    def __init__(self, hackTbPrint=None, printId=1, **kwargs):
        if 'branch' in kwargs:
            self.branch = kwargs['branch']
        if not 'command' in kwargs:
            kwargs['command'] = ["python", "run_tests.py"]
        ShellCommand.__init__(self, **kwargs)
        self.hackTbPrint = hackTbPrint
        self.printId = printId
    
    def createSummary(self, log):
        summary = []
        for line in log.readlines():
            if "RETURN:" in line:
                # The RETURN: messages aren't designed to have multiple
                # test runs; hacking them to be less noisy
                if (self.hackTbPrint):
                    line.replace("<br>","")
                    if "graph.html" in line:
                        if "| " in line:
                            p = re.compile(r'\s*\|\s*')
                            line = 'RETURN:<small>%s</small>' % \
                                   p.split(line)[1]
                    else:
                        if not self.printId:
                            continue
                        if ("id:" not in line):
                            if ("rev:" not in line):
                                continue
                            else:
                                line = "%s<br>" % line
                summary.append(line.replace("RETURN:", "TinderboxPrint:"))
            if "FAIL:" in line:
                summary.append(line.replace("FAIL:", "TinderboxPrint:FAIL:"))
        self.addCompleteLog('summary', "\n".join(summary))
            
    def evaluateCommand(self, cmd):
        superResult = ShellCommand.evaluateCommand(self, cmd)
        stdioText = cmd.logs['stdio'].getText()
        if SUCCESS != superResult:
            return FAILURE
        if None != re.search('ERROR', stdioText):
            return FAILURE
        if None != re.search('USAGE:', stdioText):
            return FAILURE
        if None != re.search('FAIL:', stdioText):
            return WARNINGS
        return SUCCESS

#
# Offshoot of TalosFactory, without any of the checkouts and with a
# number of options to make running on the mobile devices possible.
#
class MaemoTalosFactory(BuildFactory):
    """Create maemo talos build factory"""
    
    maemoClean = "rm -rf fennec fennec*.tar.bz2"

    def __init__(self,
                activeTests={
                    'ts':     20,
                    'tp':     20,
                    'tdhtml': 20,
                    'tsvg':   20,
                    'twinopen':   20,
                    'tsspider':   20,
                    'tgfx':   20,
                },
                talosConfigFile='sample.config',
                resultsServer=None,
                builderName = "unnamed",
                disableJit = 1,
                hackTbPrint = 0,
                branch = None,
                baseDir = "/media/mmc1",
    ):
        BuildFactory.__init__(self)
        self.baseDir = baseDir
        self.branch = branch
        self.disableJit = disableJit
        self.hackTbPrint = hackTbPrint

        self.addStep(ShellCommand(
                        command=["ifconfig","-a"],
                        description="IP",
        ))
        self.addStep(ShellCommand,
            workdir=self.baseDir,
            description="Cleanup",
            command=self.maemoClean
        )
        self.addStep(MozillaWget,
            workdir=self.baseDir,
            branch=self.branch,
            haltOnFailure=True
        )
        self.addStep(MozillaInstallTarBz2,
            workdir=self.baseDir,
            branch=self.branch,
            haltOnFailure=True
        )
        self.addStep(ShellCommand,
            workdir='%s/fennec' % self.baseDir,
            description=["get", "info"],
            command=['cat', 'application.ini', 'xulrunner/platform.ini']
        )
        if (self.disableJit):
            self.addStep(ShellCommand,
                        command = ["sh", "-x", "%s/talos/fix_jit.sh"%(self.baseDir)],
                        description="disable JIT",
            )
        self.addStep(ShellCommand,
                     command="echo performance > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor",
                     description=['disable', 'scaling', 'governor'],
                     haltOnFailure=True,
        )
        self.addStep(ShellCommand,
                        command = ["cp", "-r", "chrome","components","/media/mmc1/fennec"],
                        workdir = "%s/talos" % (self.baseDir),
                        description="Copy pageloader",
                        haltOnFailure=True,
        )

        firstTest = 1
        for testName in activeTests.keys():
            self.addStep(ShellCommand,
#                        command=['python','PerfConfigurator.py','-v','-e','/media/mmc1/fennec/fennec','-t',builderName,'-b',self.branch,'--activeTests',testName,'--sampleConfig',talosConfigFile,'--noChrome','--resultsServer',resultsServer,'--resultsLink','/server/bulk.cgi','--output','local.config'],
                        command='python PerfConfigurator.py -v -e %s/fennec/fennec -t `hostname` -b %s --activeTests %s --sampleConfig %s --browserWait %d --noChrome --oldresultsServer %s --oldresultsLink /server/bulk.cgi --output local.config' % (self.baseDir,self.branch,testName,talosConfigFile,activeTests[testName],resultsServer),
                        workdir = "%s/talos" % (self.baseDir),
                        description="Create config %s" % (testName),
                        haltOnFailure=True,
            )
            self.addStep(ShellCommand(
                        workdir = "%s/talos" % (self.baseDir),
                        command=["cat","local.config"],
                        description="Show config %s" % (testName),
            ))
            self.addStep(ShellCommand(
                        workdir = ".",
                        command="free; df -h",
                        description="Check memory/disk",
            ))
            self.addStep(MaemoRunPerfTests,
                        command=["python","run_tests.py","--noisy","--debug","local.config"],
                        workdir = "%s/talos" % (self.baseDir),
                        description="Run %s" % (testName),
                        branch=self.branch,
                        configFile="local.config",
                        timeout=60 * 60,
                        hackTbPrint=hackTbPrint,
                        printId=firstTest,
                        warnOnWarnings=True,
                        haltOnFailure=False,
            )
            firstTest = 0
        self.addStep(ShellCommand(
                        command="reboot; sleep 600",
                        warnOnFailure=False,
                        flunkOnFailure=False,
                        alwaysRun=True
        ))



def main(argv=None):
    if argv is None:
        argv = sys.argv
    #BUG - need to come up with a new test case now that we aren't doing url scraping in the perfrunner code
    #tester = LatestFileURL('http://stage.mozilla.org/pub/mozilla.org/firefox/tinderbox-builds/fx-win32-tbox-trunk/', "en-US.win32.zip")
   # tester.testrun()
    return 0

if __name__ == '__main__':
    main()