def server_init(self): """ Additional initialization required to satisfy MochitestDesktop.startServers """ self._locations = None self.server = None self.wsserver = None self.websocketProcessBridge = None self.SERVER_STARTUP_TIMEOUT = 180 if mozinfo.info.get("debug") else 90 if self.options.remoteWebServer is None: if os.name != "nt": self.options.remoteWebServer = moznetwork.get_ip() else: raise UserError("--remote-webserver must be specified") self.options.webServer = self.options.remoteWebServer self.options.webSocketPort = "9988" self.options.httpdPath = None self.options.keep_open = False self.options.pidFile = "" self.options.subsuite = None self.options.xrePath = None if build_obj and "MOZ_HOST_BIN" in os.environ: self.options.xrePath = os.environ["MOZ_HOST_BIN"] if not self.options.utilityPath: self.options.utilityPath = self.options.xrePath if not self.options.xrePath: self.options.xrePath = self.options.utilityPath if build_obj: self.options.certPath = os.path.join( build_obj.topsrcdir, "build", "pgo", "certs" )
def python( self, command_context, no_virtualenv, no_activate, exec_file, ipython, requirements, args, ): # Avoid logging the command self.log_manager.terminal_handler.setLevel(logging.CRITICAL) # Note: subprocess requires native strings in os.environ on Windows. append_env = {"PYTHONDONTWRITEBYTECODE": str("1")} if requirements and no_virtualenv: raise UserError( "Cannot pass both --requirements and --no-virtualenv.") if no_virtualenv: from mach_bootstrap import mach_sys_path python_path = sys.executable append_env["PYTHONPATH"] = os.pathsep.join( mach_sys_path(self.topsrcdir)) else: self.virtualenv_manager.ensure() if not no_activate: self.virtualenv_manager.activate() python_path = self.virtualenv_manager.python_path if requirements: self.virtualenv_manager.install_pip_requirements( requirements, require_hashes=False) if exec_file: exec(open(exec_file).read()) return 0 if ipython: bindir = os.path.dirname(python_path) python_path = which("ipython", path=bindir) if not python_path: if not no_virtualenv: # Use `_run_pip` directly rather than `install_pip_package` to bypass # `req.check_if_exists()` which may detect a system installed ipython. self.virtualenv_manager._run_pip(["install", "ipython"]) python_path = which("ipython", path=bindir) if not python_path: print("error: could not detect or install ipython") return 1 return self.run_process( [python_path] + args, pass_thru=True, # Allow user to run Python interactively. ensure_exit_code=False, # Don't throw on non-zero exit code. python_unbuffered=False, # Leave input buffered. append_env=append_env, )
def __init__(self, log, options): self.log = log verbose = False if options.log_tbpl_level == 'debug' or options.log_mach_level == 'debug': verbose = True self.device = ADBDeviceFactory(adb=options.adbPath or 'adb', device=options.deviceSerial, test_root=options.remoteTestRoot, verbose=verbose, run_as_package=options.app) self.options = options self.log.debug("options=%s" % vars(options)) update_mozinfo() self.remote_profile = posixpath.join(self.device.test_root, 'junit-profile') self.remote_filter_list = posixpath.join(self.device.test_root, 'junit-filters.list') if self.options.coverage and not self.options.coverage_output_dir: raise UserError( "--coverage-output-dir is required when using --enable-coverage" ) if self.options.coverage: self.remote_coverage_output_file = posixpath.join( self.device.test_root, 'junit-coverage.ec') self.coverage_output_file = os.path.join( self.options.coverage_output_dir, 'junit-coverage.ec') self.server_init() self.cleanup() self.device.clear_logcat() self.build_profile() self.startServers(self.options, debuggerInfo=None, public=True) self.log.debug("Servers started")
def current_firefox_checkout(env, hg=None): """Determine whether we're in a Firefox checkout. Returns one of None, ``git``, or ``hg``. """ HG_ROOT_REVISIONS = set( [ # From mozilla-unified. "8ba995b74e18334ab3707f27e9eb8f4e37ba3d29", ] ) path = os.getcwd() while path: hg_dir = os.path.join(path, ".hg") git_dir = os.path.join(path, ".git") if hg and os.path.exists(hg_dir): # Verify the hg repo is a Firefox repo by looking at rev 0. try: node = subprocess.check_output( [hg, "log", "-r", "0", "--template", "{node}"], cwd=path, env=env, universal_newlines=True, ) if node in HG_ROOT_REVISIONS: _warn_if_risky_revision(path) return ("hg", path) # Else the root revision is different. There could be nested # repos. So keep traversing the parents. except subprocess.CalledProcessError: pass # Just check for known-good files in the checkout, to prevent attempted # foot-shootings. Determining a canonical git checkout of mozilla-unified # is...complicated elif os.path.exists(git_dir): moz_configure = os.path.join(path, "moz.configure") if os.path.exists(moz_configure): _warn_if_risky_revision(path) return ("git", path) path, child = os.path.split(path) if child == "": break raise UserError( "Could not identify the root directory of your checkout! " "Are you running `mach bootstrap` in an hg or git clone?" )
def create_state_dir(self): state_dir = get_state_dir() if not os.path.exists(state_dir): should_create_state_dir = True if not self.instance.no_interactive: should_create_state_dir = self.instance.prompt_yesno( prompt=STATE_DIR_INFO.format(statedir=state_dir)) # This directory is by default in $HOME, or overridden via an env # var, so we probably shouldn't gate it on --no-system-changes. if should_create_state_dir: print("Creating global state directory: %s" % state_dir) os.makedirs(state_dir, mode=0o770) else: raise UserError("Need permission to create global state " "directory at %s" % state_dir) return state_dir
def generate_test_certs(command_context, specifications): """Generate test certificates and keys from specifications.""" command_context.activate_virtualenv() import pycert import pykey if not specifications: specifications = find_all_specifications(command_context) for specification in specifications: if is_certspec_file(specification): module = pycert elif is_keyspec_file(specification): module = pykey else: raise UserError("'{}' is not a .certspec or .keyspec file".format( specification)) run_module_main_on(module, os.path.abspath(specification)) return 0
def run_tests(self, test_filters_file=None, test_filters=None): """ Run the tests. """ if not self.device.is_app_installed(self.options.app): raise UserError("%s is not installed" % self.options.app) if self.device.process_exist(self.options.app): raise UserError( "%s already running before starting tests" % self.options.app ) # test_filters_file and test_filters must be mutually-exclusive if test_filters_file and test_filters: raise UserError( "Test filters may not be specified when test-filters-file is provided" ) self.test_started = False self.pass_count = 0 self.fail_count = 0 self.todo_count = 0 self.total_count = 0 self.runs = 0 self.seen_last_test = False def callback(line): # Output callback: Parse the raw junit log messages, translating into # treeherder-friendly test start/pass/fail messages. line = six.ensure_str(line) self.log.process_output(self.options.app, str(line)) # Expect per-test info like: "INSTRUMENTATION_STATUS: class=something" match = re.match(r"INSTRUMENTATION_STATUS:\s*class=(.*)", line) if match: self.class_name = match.group(1) # Expect per-test info like: "INSTRUMENTATION_STATUS: test=something" match = re.match(r"INSTRUMENTATION_STATUS:\s*test=(.*)", line) if match: self.test_name = match.group(1) match = re.match(r"INSTRUMENTATION_STATUS:\s*numtests=(.*)", line) if match: self.total_count = int(match.group(1)) match = re.match(r"INSTRUMENTATION_STATUS:\s*current=(.*)", line) if match: self.current_test_id = int(match.group(1)) match = re.match(r"INSTRUMENTATION_STATUS:\s*stack=(.*)", line) if match: self.exception_message = match.group(1) if ( "org.mozilla.geckoview.test.rule.TestHarnessException" in self.exception_message ): # This is actually a problem in the test harness itself raise JavaTestHarnessException(self.exception_message) # Expect per-test info like: "INSTRUMENTATION_STATUS_CODE: 0|1|..." match = re.match(r"INSTRUMENTATION_STATUS_CODE:\s*([+-]?\d+)", line) if match: status = match.group(1) full_name = "%s#%s" % (self.class_name, self.test_name) if full_name == self.current_full_name: # A crash in the test harness might cause us to ignore tests, # so we double check that we've actually ran all the tests if self.total_count == self.current_test_id: self.seen_last_test = True if status == "0": message = "" status = "PASS" expected = "PASS" self.pass_count += 1 if self.verbose: self.log.info("Printing logcat for test:") print(self.collectLogcatForCurrentTest()) elif status == "-3": # ignored (skipped) message = "" status = "SKIP" expected = "SKIP" self.todo_count += 1 elif status == "-4": # known fail message = "" status = "FAIL" expected = "FAIL" self.todo_count += 1 else: if self.exception_message: message = self.exception_message else: message = "status %s" % status status = "FAIL" expected = "PASS" self.fail_count += 1 self.log.info("Printing logcat for test:") print(self.collectLogcatForCurrentTest()) self.log.test_end(full_name, status, expected, message) self.test_started = False else: if self.test_started: # next test started without reporting previous status self.fail_count += 1 status = "FAIL" expected = "PASS" self.log.test_end( self.current_full_name, status, expected, "missing test completion status", ) self.log.test_start(full_name) self.test_started = True self.current_full_name = full_name # Ideally all test names should be reported to suite_start, but these test # names are not known in advance. self.log.suite_start(["geckoview-junit"]) try: self.device.grant_runtime_permissions(self.options.app) cmd = self.build_command_line( test_filters_file=test_filters_file, test_filters=test_filters ) while self.need_more_runs(): self.class_name = "" self.exception_message = "" self.test_name = "" self.current_full_name = "" self.current_test_id = 0 self.runs += 1 self.log.info("launching %s" % cmd) p = self.device.shell( cmd, timeout=self.options.max_time, stdout_callback=callback ) if p.timedout: self.log.error( "TEST-UNEXPECTED-TIMEOUT | runjunit.py | " "Timed out after %d seconds" % self.options.max_time ) self.log.info("Passed: %d" % self.pass_count) self.log.info("Failed: %d" % self.fail_count) self.log.info("Todo: %d" % self.todo_count) if not self.seen_last_test: self.log.error( "TEST-UNEXPECTED-FAIL | runjunit.py | " "Some tests did not run (probably due to a crash in the harness)" ) finally: self.log.suite_end() if self.check_for_crashes(): self.fail_count = 1 if self.options.coverage: try: self.device.pull( self.remote_coverage_output_file, self.coverage_output_file ) except ADBError: # Avoid a task retry in case the code coverage file is not found. self.log.error( "No code coverage file (%s) found on remote device" % self.remote_coverage_output_file ) return -1 return 1 if self.fail_count else 0