michael@0: # This Source Code Form is subject to the terms of the Mozilla Public michael@0: # License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: # You can obtain one at http://mozilla.org/MPL/2.0/. michael@0: from __future__ import print_function, unicode_literals michael@0: michael@0: import json michael@0: import os michael@0: import signal michael@0: import sys michael@0: import threading michael@0: michael@0: here = os.path.abspath(os.path.dirname(__file__)) michael@0: michael@0: from runreftest import RefTest, ReftestOptions michael@0: michael@0: from marionette import Marionette michael@0: from mozprocess import ProcessHandler michael@0: from mozrunner import FirefoxRunner michael@0: import mozinfo michael@0: import mozlog michael@0: michael@0: log = mozlog.getLogger('REFTEST') michael@0: michael@0: class B2GDesktopReftest(RefTest): michael@0: def __init__(self, marionette): michael@0: RefTest.__init__(self) michael@0: self.last_test = os.path.basename(__file__) michael@0: self.marionette = marionette michael@0: self.profile = None michael@0: self.runner = None michael@0: self.test_script = os.path.join(here, 'b2g_start_script.js') michael@0: self.timeout = None michael@0: michael@0: def run_marionette_script(self): michael@0: assert(self.marionette.wait_for_port()) michael@0: self.marionette.start_session() michael@0: self.marionette.set_context(self.marionette.CONTEXT_CHROME) michael@0: michael@0: if os.path.isfile(self.test_script): michael@0: f = open(self.test_script, 'r') michael@0: self.test_script = f.read() michael@0: f.close() michael@0: self.marionette.execute_script(self.test_script) michael@0: michael@0: def run_tests(self, test_path, options): michael@0: reftestlist = self.getManifestPath(test_path) michael@0: if not reftestlist.startswith('file://'): michael@0: reftestlist = 'file://%s' % reftestlist michael@0: michael@0: self.profile = self.create_profile(options, reftestlist, michael@0: profile_to_clone=options.profile) michael@0: env = self.buildBrowserEnv(options, self.profile.profile) michael@0: kp_kwargs = { 'processOutputLine': [self._on_output], michael@0: 'onTimeout': [self._on_timeout], michael@0: 'kill_on_timeout': False } michael@0: michael@0: if not options.debugger: michael@0: if not options.timeout: michael@0: if mozinfo.info['debug']: michael@0: options.timeout = 420 michael@0: else: michael@0: options.timeout = 300 michael@0: self.timeout = options.timeout + 30.0 michael@0: michael@0: log.info("%s | Running tests: start.", os.path.basename(__file__)) michael@0: cmd, args = self.build_command_line(options.app, michael@0: ignore_window_size=options.ignoreWindowSize, michael@0: browser_arg=options.browser_arg) michael@0: self.runner = FirefoxRunner(profile=self.profile, michael@0: binary=cmd, michael@0: cmdargs=args, michael@0: env=env, michael@0: process_class=ProcessHandler, michael@0: symbols_path=options.symbolsPath, michael@0: kp_kwargs=kp_kwargs) michael@0: michael@0: status = 0 michael@0: try: michael@0: self.runner.start(outputTimeout=self.timeout) michael@0: log.info("%s | Application pid: %d", michael@0: os.path.basename(__file__), michael@0: self.runner.process_handler.pid) michael@0: michael@0: # kick starts the reftest harness michael@0: self.run_marionette_script() michael@0: status = self.runner.wait() michael@0: finally: michael@0: self.runner.check_for_crashes(test_name=self.last_test) michael@0: self.runner.cleanup() michael@0: michael@0: if status > 0: michael@0: log.testFail("%s | application terminated with exit code %s", michael@0: self.last_test, status) michael@0: elif status < 0: michael@0: log.info("%s | application killed with signal %s", michael@0: self.last_test, -status) michael@0: michael@0: log.info("%s | Running tests: end.", os.path.basename(__file__)) michael@0: return status michael@0: michael@0: def create_profile(self, options, reftestlist, profile_to_clone=None): michael@0: profile = RefTest.createReftestProfile(self, options, reftestlist, michael@0: profile_to_clone=profile_to_clone) michael@0: michael@0: prefs = {} michael@0: # Turn off the locale picker screen michael@0: prefs["browser.firstrun.show.localepicker"] = False michael@0: prefs["browser.homescreenURL"] = "app://test-container.gaiamobile.org/index.html" michael@0: prefs["browser.manifestURL"] = "app://test-container.gaiamobile.org/manifest.webapp" michael@0: prefs["browser.tabs.remote"] = False michael@0: prefs["dom.ipc.tabs.disabled"] = False michael@0: prefs["dom.mozBrowserFramesEnabled"] = True michael@0: prefs["font.size.inflation.emPerLine"] = 0 michael@0: prefs["font.size.inflation.minTwips"] = 0 michael@0: prefs["network.dns.localDomains"] = "app://test-container.gaiamobile.org" michael@0: prefs["reftest.browser.iframe.enabled"] = False michael@0: prefs["reftest.remote"] = False michael@0: prefs["reftest.uri"] = "%s" % reftestlist michael@0: # Set a future policy version to avoid the telemetry prompt. michael@0: prefs["toolkit.telemetry.prompted"] = 999 michael@0: prefs["toolkit.telemetry.notifiedOptOut"] = 999 michael@0: michael@0: # Set the extra prefs. michael@0: profile.set_preferences(prefs) michael@0: return profile michael@0: michael@0: def build_command_line(self, app, ignore_window_size=False, michael@0: browser_arg=None): michael@0: cmd = os.path.abspath(app) michael@0: args = ['-marionette'] michael@0: michael@0: if browser_arg: michael@0: args += [browser_arg] michael@0: michael@0: if not ignore_window_size: michael@0: args.extend(['--screen', '800x1000']) michael@0: return cmd, args michael@0: michael@0: def _on_output(self, line): michael@0: print(line) michael@0: # TODO use structured logging michael@0: if "TEST-START" in line and "|" in line: michael@0: self.last_test = line.split("|")[1].strip() michael@0: michael@0: def _on_timeout(self): michael@0: msg = "%s | application timed out after %s seconds with no output" michael@0: log.testFail(msg % (self.last_test, self.timeout)) michael@0: michael@0: # kill process to get a stack michael@0: self.runner.stop(sig=signal.SIGABRT) michael@0: michael@0: michael@0: def run_desktop_reftests(parser, options, args): michael@0: kwargs = {} michael@0: if options.marionette: michael@0: host, port = options.marionette.split(':') michael@0: kwargs['host'] = host michael@0: kwargs['port'] = int(port) michael@0: marionette = Marionette.getMarionetteOrExit(**kwargs) michael@0: michael@0: reftest = B2GDesktopReftest(marionette) michael@0: michael@0: options = ReftestOptions.verifyCommonOptions(parser, options, reftest) michael@0: if options == None: michael@0: sys.exit(1) michael@0: michael@0: # add a -bin suffix if b2g-bin exists, but just b2g was specified michael@0: if options.app[-4:] != '-bin': michael@0: if os.path.isfile("%s-bin" % options.app): michael@0: options.app = "%s-bin" % options.app michael@0: michael@0: if options.desktop and not options.profile: michael@0: raise Exception("must specify --profile when specifying --desktop") michael@0: michael@0: sys.exit(reftest.run_tests(args[0], options))