Loading testing/mozharness/configs/android/android14-x86_64.py +3 −2 Original line number Diff line number Diff line Loading @@ -11,8 +11,9 @@ config = { "emulator_avd_name": "mozemulator-android34-x86_64", "emulator_process_name": "qemu-system-x86_64", "emulator_extra_args": [ "-gpu", "on", "-no-window", "-no-audio", "-no-boot-anim", "-skip-adb-auth", "-verbose", "-show-kernel", Loading testing/mozharness/configs/android/android_common.py +13 −0 Original line number Diff line number Diff line Loading @@ -310,6 +310,19 @@ config = { "--deviceSerial=%(device_serial)s", ], }, "marionette": { "run_filename": "runtests.py", "testsdir": "marionette/harness/marionette_harness", "install": True, "options": [ "-vv", "--address=127.0.0.1:2828", "--app=fennec", ], "tests": [ "%(abs_marionette_manifest_dir)s/unit-tests.toml", ], }, }, # end suite_definitions "unstructured_suites": [ "jittest", Loading testing/mozharness/scripts/android_emulator_unittest.py +102 −3 Original line number Diff line number Diff line Loading @@ -7,8 +7,11 @@ import copy import datetime import json import os import socket import subprocess import sys import tempfile import time # load modules from parent dir here = os.path.abspath(os.path.dirname(__file__)) Loading @@ -16,7 +19,7 @@ sys.path.insert(1, os.path.dirname(here)) from mozfile import load_source from mozharness.base.log import WARNING from mozharness.base.script import BaseScript, PreScriptAction from mozharness.base.script import BaseScript, PostScriptAction, PreScriptAction from mozharness.mozilla.automation import TBPL_RETRY from mozharness.mozilla.mozbase import MozbaseMixin from mozharness.mozilla.testing.android import AndroidMixin Loading @@ -27,7 +30,7 @@ from mozharness.mozilla.testing.codecoverage import ( from mozharness.mozilla.testing.testbase import TestingMixin, testing_config_options SUITE_DEFAULT_E10S = ["geckoview-junit", "mochitest", "reftest"] SUITE_NO_E10S = ["cppunittest", "gtest", "jittest", "xpcshell"] SUITE_NO_E10S = ["cppunittest", "gtest", "jittest", "xpcshell", "marionette"] SUITE_REPEATABLE = ["mochitest", "reftest", "xpcshell"] Loading Loading @@ -179,6 +182,15 @@ class AndroidEmulatorTest( "times in which case the test must contain at least one of the given tags.", }, ], [ ["--package-name"], { "action": "store", "default": None, "dest": "package_name", "help": "The Android package name for the app being installed.", }, ], ] + copy.deepcopy(testing_config_options) + copy.deepcopy(code_coverage_config_options) Loading Loading @@ -229,6 +241,7 @@ class AndroidEmulatorTest( self.enable_isolated_zygote_process = c.get("enable_isolated_zygote_process") self.extra_prefs = c.get("extra_prefs") self.test_tags = c.get("test_tags") self.package_name = c.get("package_name") or self.query_package_name() def query_abs_dirs(self): if self.abs_dirs: Loading Loading @@ -330,6 +343,16 @@ class AndroidEmulatorTest( "error_summary_file": error_summary_file, "xpcshell_extra": c.get("xpcshell_extra", ""), "gtest_dir": os.path.join(dirs["abs_test_install_dir"], "gtest"), "abs_marionette_manifest_dir": os.path.join( dirs["abs_test_install_dir"], "marionette", "tests", "testing", "marionette", "harness", "marionette_harness", "tests", ), } user_paths = self._get_mozharness_test_paths(self.test_suite) Loading @@ -346,7 +369,7 @@ class AndroidEmulatorTest( if "%(app)" in option: # only query package name if requested cmd.extend([option % {"app": self.query_package_name()}]) cmd.extend([option % {"app": self.package_name}]) else: option = option % str_format_values if option: Loading Loading @@ -410,6 +433,7 @@ class AndroidEmulatorTest( self.config["suite_definitions"][self.test_suite].get("tests"), None, try_tests, str_format_values=str_format_values, ) ) Loading Loading @@ -450,6 +474,7 @@ class AndroidEmulatorTest( }, ), ("xpcshell", {"xpcshell": "xpcshell"}), ("marionette", {"marionette": "marionette"}), ] suites = [] for category, all_suites in all: Loading @@ -474,6 +499,61 @@ class AndroidEmulatorTest( # in the base class, this checks for mozinstall, but we don't use it pass def _configure_marionette_virtualenv(self, action): dirs = self.query_abs_dirs() requirements = os.path.join( dirs["abs_test_install_dir"], "config", "marionette_requirements.txt" ) if not os.path.isfile(requirements): self.fatal(f"Could not find marionette requirements file: {requirements}") self.register_virtualenv_module(requirements=[requirements]) def _marionette_setup(self): adb = self.query_exe("adb") self.run_command([adb, "forward", "tcp:2828", "tcp:2828"]) with tempfile.NamedTemporaryFile(suffix=".yaml") as tmp_file: tmp_file.write( b"""args: - --marionette - --remote-allow-system-access """ ) tmp_file.flush() remote_path = f"/data/local/tmp/{self.package_name}-geckoview-config.yaml" self.run_command([adb, "push", tmp_file.name, remote_path]) self.run_command([ adb, "shell", "am", "start", "-S", "-W", "-n", f"{self.package_name}/org.mozilla.gecko.BrowserApp", ]) # Wait for Marionette to be ready for attempt in range(5): try: self.info( f"Checking Marionette on 127.0.0.1:2828 (attempt {attempt + 1}/5)" ) socket.create_connection(("127.0.0.1", 2828), 10).close() self.info("Marionette is reachable") break except OSError: if attempt == 4: self.fatal( "Timed out waiting for 127.0.0.1:2828 to become reachable" ) self.info("Marionette not reachable yet, retrying in 10s") time.sleep(10) @PreScriptAction("create-virtualenv") def pre_create_virtualenv(self, action): dirs = self.query_abs_dirs() Loading @@ -489,6 +569,9 @@ class AndroidEmulatorTest( if requirements: self.register_virtualenv_module(requirements=[requirements]) if ("marionette", "marionette") in suites: self._configure_marionette_virtualenv(action) def download_and_extract(self): """ Download and extract product APK, tests.zip, and host utils. Loading Loading @@ -526,6 +609,9 @@ class AndroidEmulatorTest( for per_test_suite, suite in suites: self.test_suite = suite if self.test_suite == "marionette": self._marionette_setup() try: cwd = self._query_tests_dir(self.test_suite) except Exception: Loading Loading @@ -605,6 +691,19 @@ class AndroidEmulatorTest( % (suite_category, suite, tbpl_status), ) @PostScriptAction("run-tests") def marionette_teardown(self, *args, **kwargs): if ("marionette", "marionette") in self._query_suites(): adb = self.query_exe("adb") self.run_command([adb, "shell", "am", "force-stop", self.package_name]) self.run_command([adb, "uninstall", self.package_name]) self.run_command([ adb, "shell", "rm", f"/data/local/tmp/{self.package_name}-geckoview-config.yaml", ]) if __name__ == "__main__": test = AndroidEmulatorTest() Loading Loading
testing/mozharness/configs/android/android14-x86_64.py +3 −2 Original line number Diff line number Diff line Loading @@ -11,8 +11,9 @@ config = { "emulator_avd_name": "mozemulator-android34-x86_64", "emulator_process_name": "qemu-system-x86_64", "emulator_extra_args": [ "-gpu", "on", "-no-window", "-no-audio", "-no-boot-anim", "-skip-adb-auth", "-verbose", "-show-kernel", Loading
testing/mozharness/configs/android/android_common.py +13 −0 Original line number Diff line number Diff line Loading @@ -310,6 +310,19 @@ config = { "--deviceSerial=%(device_serial)s", ], }, "marionette": { "run_filename": "runtests.py", "testsdir": "marionette/harness/marionette_harness", "install": True, "options": [ "-vv", "--address=127.0.0.1:2828", "--app=fennec", ], "tests": [ "%(abs_marionette_manifest_dir)s/unit-tests.toml", ], }, }, # end suite_definitions "unstructured_suites": [ "jittest", Loading
testing/mozharness/scripts/android_emulator_unittest.py +102 −3 Original line number Diff line number Diff line Loading @@ -7,8 +7,11 @@ import copy import datetime import json import os import socket import subprocess import sys import tempfile import time # load modules from parent dir here = os.path.abspath(os.path.dirname(__file__)) Loading @@ -16,7 +19,7 @@ sys.path.insert(1, os.path.dirname(here)) from mozfile import load_source from mozharness.base.log import WARNING from mozharness.base.script import BaseScript, PreScriptAction from mozharness.base.script import BaseScript, PostScriptAction, PreScriptAction from mozharness.mozilla.automation import TBPL_RETRY from mozharness.mozilla.mozbase import MozbaseMixin from mozharness.mozilla.testing.android import AndroidMixin Loading @@ -27,7 +30,7 @@ from mozharness.mozilla.testing.codecoverage import ( from mozharness.mozilla.testing.testbase import TestingMixin, testing_config_options SUITE_DEFAULT_E10S = ["geckoview-junit", "mochitest", "reftest"] SUITE_NO_E10S = ["cppunittest", "gtest", "jittest", "xpcshell"] SUITE_NO_E10S = ["cppunittest", "gtest", "jittest", "xpcshell", "marionette"] SUITE_REPEATABLE = ["mochitest", "reftest", "xpcshell"] Loading Loading @@ -179,6 +182,15 @@ class AndroidEmulatorTest( "times in which case the test must contain at least one of the given tags.", }, ], [ ["--package-name"], { "action": "store", "default": None, "dest": "package_name", "help": "The Android package name for the app being installed.", }, ], ] + copy.deepcopy(testing_config_options) + copy.deepcopy(code_coverage_config_options) Loading Loading @@ -229,6 +241,7 @@ class AndroidEmulatorTest( self.enable_isolated_zygote_process = c.get("enable_isolated_zygote_process") self.extra_prefs = c.get("extra_prefs") self.test_tags = c.get("test_tags") self.package_name = c.get("package_name") or self.query_package_name() def query_abs_dirs(self): if self.abs_dirs: Loading Loading @@ -330,6 +343,16 @@ class AndroidEmulatorTest( "error_summary_file": error_summary_file, "xpcshell_extra": c.get("xpcshell_extra", ""), "gtest_dir": os.path.join(dirs["abs_test_install_dir"], "gtest"), "abs_marionette_manifest_dir": os.path.join( dirs["abs_test_install_dir"], "marionette", "tests", "testing", "marionette", "harness", "marionette_harness", "tests", ), } user_paths = self._get_mozharness_test_paths(self.test_suite) Loading @@ -346,7 +369,7 @@ class AndroidEmulatorTest( if "%(app)" in option: # only query package name if requested cmd.extend([option % {"app": self.query_package_name()}]) cmd.extend([option % {"app": self.package_name}]) else: option = option % str_format_values if option: Loading Loading @@ -410,6 +433,7 @@ class AndroidEmulatorTest( self.config["suite_definitions"][self.test_suite].get("tests"), None, try_tests, str_format_values=str_format_values, ) ) Loading Loading @@ -450,6 +474,7 @@ class AndroidEmulatorTest( }, ), ("xpcshell", {"xpcshell": "xpcshell"}), ("marionette", {"marionette": "marionette"}), ] suites = [] for category, all_suites in all: Loading @@ -474,6 +499,61 @@ class AndroidEmulatorTest( # in the base class, this checks for mozinstall, but we don't use it pass def _configure_marionette_virtualenv(self, action): dirs = self.query_abs_dirs() requirements = os.path.join( dirs["abs_test_install_dir"], "config", "marionette_requirements.txt" ) if not os.path.isfile(requirements): self.fatal(f"Could not find marionette requirements file: {requirements}") self.register_virtualenv_module(requirements=[requirements]) def _marionette_setup(self): adb = self.query_exe("adb") self.run_command([adb, "forward", "tcp:2828", "tcp:2828"]) with tempfile.NamedTemporaryFile(suffix=".yaml") as tmp_file: tmp_file.write( b"""args: - --marionette - --remote-allow-system-access """ ) tmp_file.flush() remote_path = f"/data/local/tmp/{self.package_name}-geckoview-config.yaml" self.run_command([adb, "push", tmp_file.name, remote_path]) self.run_command([ adb, "shell", "am", "start", "-S", "-W", "-n", f"{self.package_name}/org.mozilla.gecko.BrowserApp", ]) # Wait for Marionette to be ready for attempt in range(5): try: self.info( f"Checking Marionette on 127.0.0.1:2828 (attempt {attempt + 1}/5)" ) socket.create_connection(("127.0.0.1", 2828), 10).close() self.info("Marionette is reachable") break except OSError: if attempt == 4: self.fatal( "Timed out waiting for 127.0.0.1:2828 to become reachable" ) self.info("Marionette not reachable yet, retrying in 10s") time.sleep(10) @PreScriptAction("create-virtualenv") def pre_create_virtualenv(self, action): dirs = self.query_abs_dirs() Loading @@ -489,6 +569,9 @@ class AndroidEmulatorTest( if requirements: self.register_virtualenv_module(requirements=[requirements]) if ("marionette", "marionette") in suites: self._configure_marionette_virtualenv(action) def download_and_extract(self): """ Download and extract product APK, tests.zip, and host utils. Loading Loading @@ -526,6 +609,9 @@ class AndroidEmulatorTest( for per_test_suite, suite in suites: self.test_suite = suite if self.test_suite == "marionette": self._marionette_setup() try: cwd = self._query_tests_dir(self.test_suite) except Exception: Loading Loading @@ -605,6 +691,19 @@ class AndroidEmulatorTest( % (suite_category, suite, tbpl_status), ) @PostScriptAction("run-tests") def marionette_teardown(self, *args, **kwargs): if ("marionette", "marionette") in self._query_suites(): adb = self.query_exe("adb") self.run_command([adb, "shell", "am", "force-stop", self.package_name]) self.run_command([adb, "uninstall", self.package_name]) self.run_command([ adb, "shell", "rm", f"/data/local/tmp/{self.package_name}-geckoview-config.yaml", ]) if __name__ == "__main__": test = AndroidEmulatorTest() Loading