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