Example #1
0
 def runServer(self):
     """
     Start a basic HTML server to host
     test related files.
     """
     if not self.options.serverPath:
         self.logger.warning('Can\'t start HTTP server, --server-path not specified')
         return
     pId = os.fork()
     # if child process
     if pId == 0:
         os.chdir(os.path.dirname(self.options.serverPath))
         self.server = PepHTTPServer(self.options.serverPort)
         self.logger.debug('Starting server on port ' + str(self.options.serverPort))
         self.server.serve_forever()
     else:
         self.child_pid = pId
Example #2
0
class Peptest():
    """
    Peptest
    Runs and logs tests designed to test responsiveness
    """
    profile_class = Profile
    runner_class = Runner

    def __init__(self, options, **kwargs):
        self.options = options
        self.child_pid = None
        self.logger = mozlog.getLogger('PEP')

        # create the profile
        self.profile = self.profile_class(profile=self.options.profilePath,
                                          addons=[os.path.join(here, 'extension')])

        # fork a server to serve the test related files
        if self.options.serverPath:
            self.runServer()

        tests = []
        if self.options.testPath.endswith('.js'):
            # a single test file was passed in
            testObj = {}
            testObj['path'] = os.path.realpath(self.options.testPath)
            testObj['name'] = os.path.basename(self.options.testPath)
            tests.append(testObj)
        else:
            # a test manifest was passed in
            # open and convert the manifest to json
            manifest = TestManifest()
            manifest.read(self.options.testPath)
            tests = manifest.get()
       
        # create a manifest object to be read by the JS side
        manifestObj = {}
        manifestObj['tests'] = tests
        
        # write manifest to a JSON file 
        jsonManifest = open(os.path.join(here, 'manifest.json'), 'w')
        jsonManifest.write(str(manifestObj).replace("'", "\""))
        jsonManifest.close()

        # setup environment
        env = os.environ.copy()
        env['MOZ_INSTRUMENT_EVENT_LOOP'] = '1'
        env['MOZ_INSTRUMENT_EVENT_LOOP_THRESHOLD'] = '50'
        env['MOZ_CRASHREPORTER_NO_REPORT'] = '1'

        # construct the browser arguments
        cmdargs = []
        # TODO Make browserArgs a list
        cmdargs.extend(self.options.browserArgs)
        cmdargs.extend(['-pep-start', os.path.realpath(jsonManifest.name)])
        cmdargs.append('-pep-noisy')
        
        # run with managed process handler
        self.runner = self.runner_class(profile=self.profile,
                                        binary=self.options.binary,
                                        cmdargs=cmdargs,
                                        env=env,
                                        process_class=PepProcess)

    def start(self):
        self.logger.debug('Starting Peptest')
       
        # start firefox 
        self.runner.start()
        self.runner.wait()
        crashed = self.checkForCrashes(results.currentTest)
        self.stop()
        
        if crashed or results.hasFails():
            return 1
        return 0

    def runServer(self):
        """
        Start a basic HTML server to host
        test related files.
        """
        if not self.options.serverPath:
            self.logger.warning('Can\'t start HTTP server, --server-path not specified')
            return
        pId = os.fork()
        # if child process
        if pId == 0:
            os.chdir(os.path.dirname(self.options.serverPath))
            self.server = PepHTTPServer(self.options.serverPort)
            self.logger.debug('Starting server on port ' + str(self.options.serverPort))
            self.server.serve_forever()
        else:
            self.child_pid = pId
    
    def stop(self):
        """Kill the app"""
        # stop the runner
        if self.runner is not None:
            self.runner.stop()

        # kill the server process
        if self.child_pid is not None:
            # TODO Kill properly (?)
            os.kill(self.child_pid, signal.SIGKILL)

        # remove harness related files
        files = ['manifest.json']
        for f in files:
            if os.path.exists(os.path.join(here, f)):
                os.remove(os.path.join(here, f))

        if os.path.exists(os.path.join(here, 'symbols')):
            shutil.rmtree(os.path.join('symbols'))

        # delete any minidumps that may have been created
        dumpDir = os.path.join(self.profile.profile, 'minidumps')
        if self.options.profilePath and os.path.exists(dumpDir):
            shutil.rmtree(dumpDir)

    def checkForCrashes(self, testName=None):
        """
        Detects when a crash occurs and prints the output from
        MINIDUMP_STACKWALK. Returns true if crash detected,
        otherwise false.
        """
        stackwalkPath = os.environ.get('MINIDUMP_STACKWALK', None)
        # try to get the caller's filename if no test name is given
        if testName is None:
            try:
                testName = os.path.basename(sys._getframe(1).f_code.co_filename)
            except:
                testName = "unknown"

        foundCrash = False
        dumpDir = os.path.join(self.profile.profile, 'minidumps')
        dumps = glob.glob(os.path.join(dumpDir, '*.dmp'))

        symbolsPath = self.options.symbolsPath
        
        for d in dumps:
            import subprocess
            foundCrash = True
            self.logger.info("PROCESS-CRASH | %s | application crashed (minidump found)", testName)
            print "Crash dump filename: " + d
            
            # only proceed if a symbols path and stackwalk path were specified
            if symbolsPath and stackwalkPath and os.path.exists(stackwalkPath):
                # if symbolsPath is a url, download and extract the zipfile
                if utils.isURL(symbolsPath):
                    bundle = utils.download(symbolsPath, here)
                    symbolsPath = os.path.join(os.path.dirname(bundle), 'symbols')
                    utils.extract(bundle, symbolsPath, delete=True)

                # run minidump_stackwalk
                p = subprocess.Popen([stackwalkPath, d, symbolsPath],
                                    stdout=subprocess.PIPE,
                                    stderr=subprocess.PIPE)
                (out, err) = p.communicate()
                if len(out) > 3:
                    # minidump_stackwalk is chatty, so ignore stderr when it succeeds.
                    print out
                else:
                    print "stderr from minidump_stackwalk:"
                    print err
                if p.returncode != 0:
                    print "minidump_stackwalk exited with return code %d" % p.returncode
            else:
                self.logger.warning('No symbols_path or stackwalk path specified, can\'t process dump')
                break
        return foundCrash