brizental pushed to branch tor-browser-149.0a1-16.0-2 at The Tor Project / Applications / Tor Browser
Commits:
-
863fc44a
by Beatriz Rizental at 2026-03-24T14:25:12-03:00
-
33b1e93e
by Beatriz Rizental at 2026-03-24T14:25:12-03:00
-
24ce6582
by Beatriz Rizental at 2026-03-24T14:25:13-03:00
7 changed files:
- mobile/android/fenix/app/src/main/java/org/mozilla/fenix/FenixApplication.kt
- mobile/shared/modules/geckoview/DelayedInit.sys.mjs
- + mobile/shared/modules/geckoview/test/xpcshell/test_DelayedInit.js
- mobile/shared/modules/geckoview/test/xpcshell/xpcshell.toml
- testing/mozharness/configs/android/android14-x86_64.py
- testing/mozharness/configs/android/android_common.py
- testing/mozharness/scripts/android_emulator_unittest.py
Changes:
| ... | ... | @@ -507,6 +507,12 @@ open class FenixApplication : Application(), Provider, ThemeProvider { |
| 507 | 507 | logElapsedTime(logger, "Starting Relay feature integration") {
|
| 508 | 508 | components.relayFeatureIntegration.start()
|
| 509 | 509 | }
|
| 510 | + |
|
| 511 | + // If running Marionette tests a GeckoEngineSession needs to be
|
|
| 512 | + // started and that must happen on the main thread.
|
|
| 513 | + logElapsedTime(logger, "Maybe setup Marionette") {
|
|
| 514 | + maybeSetupMarionette()
|
|
| 515 | + }
|
|
| 510 | 516 | }
|
| 511 | 517 | }
|
| 512 | 518 | |
| ... | ... | @@ -675,6 +681,13 @@ open class FenixApplication : Application(), Provider, ThemeProvider { |
| 675 | 681 | FxNimbus.initialize { nimbus }
|
| 676 | 682 | }
|
| 677 | 683 | |
| 684 | + private fun maybeSetupMarionette() {
|
|
| 685 | + // If Marionette is enabled, start a GeckoEngineSession immediatelly.
|
|
| 686 | + if (System.getenv("MOZ_MARIONETTE") == "1") {
|
|
| 687 | + components.core.engine.speculativeCreateSession(components.appStore.state.mode.isPrivate)
|
|
| 688 | + }
|
|
| 689 | + }
|
|
| 690 | + |
|
| 678 | 691 | /**
|
| 679 | 692 | * Initiate Megazord sequence! Megazord Battle Mode!
|
| 680 | 693 | *
|
| ... | ... | @@ -96,7 +96,11 @@ var Impl = { |
| 96 | 96 | return false;
|
| 97 | 97 | }
|
| 98 | 98 | this.complete = true;
|
| 99 | - this.fn.call();
|
|
| 99 | + try {
|
|
| 100 | + this.fn.call();
|
|
| 101 | + } catch (e) {
|
|
| 102 | + console.error("Error running init", e);
|
|
| 103 | + }
|
|
| 100 | 104 | this.fn = null;
|
| 101 | 105 | return true;
|
| 102 | 106 | },
|
| 1 | +/* Any copyright is dedicated to the Public Domain.
|
|
| 2 | +http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
| 3 | +"use strict";
|
|
| 4 | + |
|
| 5 | +const { DelayedInit } = ChromeUtils.importESModule(
|
|
| 6 | + "resource://gre/modules/DelayedInit.sys.mjs"
|
|
| 7 | +);
|
|
| 8 | + |
|
| 9 | +add_task(async function test_delayed_init_continues_queue_on_failure() {
|
|
| 10 | + const results = [];
|
|
| 11 | + const waitMs = 0;
|
|
| 12 | + |
|
| 13 | + DelayedInit.schedule(
|
|
| 14 | + () => {
|
|
| 15 | + results.push("first");
|
|
| 16 | + },
|
|
| 17 | + null,
|
|
| 18 | + null,
|
|
| 19 | + waitMs
|
|
| 20 | + );
|
|
| 21 | + |
|
| 22 | + DelayedInit.schedule(
|
|
| 23 | + () => {
|
|
| 24 | + results.push("second");
|
|
| 25 | + throw new Error("Deliberate error for testing");
|
|
| 26 | + },
|
|
| 27 | + null,
|
|
| 28 | + null,
|
|
| 29 | + waitMs
|
|
| 30 | + );
|
|
| 31 | + |
|
| 32 | + DelayedInit.schedule(
|
|
| 33 | + () => {
|
|
| 34 | + results.push("third");
|
|
| 35 | + },
|
|
| 36 | + null,
|
|
| 37 | + null,
|
|
| 38 | + waitMs
|
|
| 39 | + );
|
|
| 40 | + |
|
| 41 | + await new Promise(resolve => ChromeUtils.idleDispatch(resolve));
|
|
| 42 | + |
|
| 43 | + Assert.deepEqual(
|
|
| 44 | + results,
|
|
| 45 | + ["first", "second", "third"],
|
|
| 46 | + "Queue processes all inits even when one fails"
|
|
| 47 | + );
|
|
| 48 | +}); |
| ... | ... | @@ -7,6 +7,8 @@ prefs = "browser.crashReports.onDemand=true" |
| 7 | 7 | |
| 8 | 8 | ["test_ChildCrashHandler.js"]
|
| 9 | 9 | |
| 10 | +["test_DelayedInit.js"]
|
|
| 11 | + |
|
| 10 | 12 | ["test_GeckoViewAppConstants.js"]
|
| 11 | 13 | |
| 12 | 14 | ["test_RemoteSettingsCrashPull.js"] |
| ... | ... | @@ -11,8 +11,9 @@ config = { |
| 11 | 11 | "emulator_avd_name": "mozemulator-android34-x86_64",
|
| 12 | 12 | "emulator_process_name": "qemu-system-x86_64",
|
| 13 | 13 | "emulator_extra_args": [
|
| 14 | - "-gpu",
|
|
| 15 | - "on",
|
|
| 14 | + "-no-window",
|
|
| 15 | + "-no-audio",
|
|
| 16 | + "-no-boot-anim",
|
|
| 16 | 17 | "-skip-adb-auth",
|
| 17 | 18 | "-verbose",
|
| 18 | 19 | "-show-kernel",
|
| ... | ... | @@ -315,6 +315,19 @@ config = { |
| 315 | 315 | "--deviceSerial=%(device_serial)s",
|
| 316 | 316 | ],
|
| 317 | 317 | },
|
| 318 | + "marionette": {
|
|
| 319 | + "run_filename": "runtests.py",
|
|
| 320 | + "testsdir": "marionette/harness/marionette_harness",
|
|
| 321 | + "install": True,
|
|
| 322 | + "options": [
|
|
| 323 | + "-vv",
|
|
| 324 | + "--address=127.0.0.1:2828",
|
|
| 325 | + "--app=fennec",
|
|
| 326 | + ],
|
|
| 327 | + "tests": [
|
|
| 328 | + "%(abs_marionette_manifest_dir)s/unit-tests.toml",
|
|
| 329 | + ],
|
|
| 330 | + },
|
|
| 318 | 331 | }, # end suite_definitions
|
| 319 | 332 | "structured_suites": [
|
| 320 | 333 | "mochitest-media",
|
| ... | ... | @@ -7,15 +7,18 @@ import copy |
| 7 | 7 | import datetime
|
| 8 | 8 | import json
|
| 9 | 9 | import os
|
| 10 | +import socket
|
|
| 10 | 11 | import subprocess
|
| 11 | 12 | import sys
|
| 13 | +import tempfile
|
|
| 14 | +import time
|
|
| 12 | 15 | |
| 13 | 16 | # load modules from parent dir
|
| 14 | 17 | here = os.path.abspath(os.path.dirname(__file__))
|
| 15 | 18 | sys.path.insert(1, os.path.dirname(here))
|
| 16 | 19 | |
| 17 | 20 | from mozharness.base.log import WARNING
|
| 18 | -from mozharness.base.script import BaseScript, PreScriptAction
|
|
| 21 | +from mozharness.base.script import BaseScript, PostScriptAction, PreScriptAction
|
|
| 19 | 22 | from mozharness.mozilla.automation import TBPL_RETRY
|
| 20 | 23 | from mozharness.mozilla.mozbase import MozbaseMixin
|
| 21 | 24 | from mozharness.mozilla.testing.android import AndroidMixin
|
| ... | ... | @@ -26,7 +29,7 @@ from mozharness.mozilla.testing.codecoverage import ( |
| 26 | 29 | from mozharness.mozilla.testing.testbase import TestingMixin, testing_config_options
|
| 27 | 30 | |
| 28 | 31 | SUITE_DEFAULT_E10S = ["geckoview-junit", "mochitest", "reftest"]
|
| 29 | -SUITE_NO_E10S = ["cppunittest", "gtest", "jittest", "xpcshell"]
|
|
| 32 | +SUITE_NO_E10S = ["cppunittest", "gtest", "jittest", "xpcshell", "marionette"]
|
|
| 30 | 33 | SUITE_REPEATABLE = ["mochitest", "reftest", "xpcshell"]
|
| 31 | 34 | |
| 32 | 35 | |
| ... | ... | @@ -178,6 +181,15 @@ class AndroidEmulatorTest( |
| 178 | 181 | "times in which case the test must contain at least one of the given tags.",
|
| 179 | 182 | },
|
| 180 | 183 | ],
|
| 184 | + [
|
|
| 185 | + ["--package-name"],
|
|
| 186 | + {
|
|
| 187 | + "action": "store",
|
|
| 188 | + "default": None,
|
|
| 189 | + "dest": "package_name",
|
|
| 190 | + "help": "The Android package name for the app being installed.",
|
|
| 191 | + },
|
|
| 192 | + ],
|
|
| 181 | 193 | ]
|
| 182 | 194 | + copy.deepcopy(testing_config_options)
|
| 183 | 195 | + copy.deepcopy(code_coverage_config_options)
|
| ... | ... | @@ -228,6 +240,7 @@ class AndroidEmulatorTest( |
| 228 | 240 | self.enable_isolated_zygote_process = c.get("enable_isolated_zygote_process")
|
| 229 | 241 | self.extra_prefs = c.get("extra_prefs")
|
| 230 | 242 | self.test_tags = c.get("test_tags")
|
| 243 | + self.package_name = c.get("package_name") or self.query_package_name()
|
|
| 231 | 244 | |
| 232 | 245 | def query_abs_dirs(self):
|
| 233 | 246 | if self.abs_dirs:
|
| ... | ... | @@ -329,6 +342,16 @@ class AndroidEmulatorTest( |
| 329 | 342 | "error_summary_file": error_summary_file,
|
| 330 | 343 | "xpcshell_extra": c.get("xpcshell_extra", ""),
|
| 331 | 344 | "gtest_dir": os.path.join(dirs["abs_test_install_dir"], "gtest"),
|
| 345 | + "abs_marionette_manifest_dir": os.path.join(
|
|
| 346 | + dirs["abs_test_install_dir"],
|
|
| 347 | + "marionette",
|
|
| 348 | + "tests",
|
|
| 349 | + "testing",
|
|
| 350 | + "marionette",
|
|
| 351 | + "harness",
|
|
| 352 | + "marionette_harness",
|
|
| 353 | + "tests",
|
|
| 354 | + ),
|
|
| 332 | 355 | }
|
| 333 | 356 | |
| 334 | 357 | user_paths = self._get_mozharness_test_paths(self.test_suite)
|
| ... | ... | @@ -345,7 +368,7 @@ class AndroidEmulatorTest( |
| 345 | 368 | |
| 346 | 369 | if "%(app)" in option:
|
| 347 | 370 | # only query package name if requested
|
| 348 | - cmd.extend([option % {"app": self.query_package_name()}])
|
|
| 371 | + cmd.extend([option % {"app": self.package_name}])
|
|
| 349 | 372 | else:
|
| 350 | 373 | option = option % str_format_values
|
| 351 | 374 | if option:
|
| ... | ... | @@ -409,6 +432,7 @@ class AndroidEmulatorTest( |
| 409 | 432 | self.config["suite_definitions"][self.test_suite].get("tests"),
|
| 410 | 433 | None,
|
| 411 | 434 | try_tests,
|
| 435 | + str_format_values=str_format_values,
|
|
| 412 | 436 | )
|
| 413 | 437 | )
|
| 414 | 438 | |
| ... | ... | @@ -449,6 +473,7 @@ class AndroidEmulatorTest( |
| 449 | 473 | },
|
| 450 | 474 | ),
|
| 451 | 475 | ("xpcshell", {"xpcshell": "xpcshell"}),
|
| 476 | + ("marionette", {"marionette": "marionette"}),
|
|
| 452 | 477 | ]
|
| 453 | 478 | suites = []
|
| 454 | 479 | for category, all_suites in all:
|
| ... | ... | @@ -473,6 +498,61 @@ class AndroidEmulatorTest( |
| 473 | 498 | # in the base class, this checks for mozinstall, but we don't use it
|
| 474 | 499 | pass
|
| 475 | 500 | |
| 501 | + def _configure_marionette_virtualenv(self, action):
|
|
| 502 | + dirs = self.query_abs_dirs()
|
|
| 503 | + requirements = os.path.join(
|
|
| 504 | + dirs["abs_test_install_dir"], "config", "marionette_requirements.txt"
|
|
| 505 | + )
|
|
| 506 | + if not os.path.isfile(requirements):
|
|
| 507 | + self.fatal(f"Could not find marionette requirements file: {requirements}")
|
|
| 508 | + |
|
| 509 | + self.register_virtualenv_module(requirements=[requirements])
|
|
| 510 | + |
|
| 511 | + def _marionette_setup(self):
|
|
| 512 | + adb = self.query_exe("adb")
|
|
| 513 | + |
|
| 514 | + self.run_command([adb, "forward", "tcp:2828", "tcp:2828"])
|
|
| 515 | + |
|
| 516 | + with tempfile.NamedTemporaryFile(suffix=".yaml") as tmp_file:
|
|
| 517 | + tmp_file.write(
|
|
| 518 | + b"""args:
|
|
| 519 | +- --marionette
|
|
| 520 | +- --remote-allow-system-access
|
|
| 521 | +"""
|
|
| 522 | + )
|
|
| 523 | + tmp_file.flush()
|
|
| 524 | + |
|
| 525 | + remote_path = f"/data/local/tmp/{self.package_name}-geckoview-config.yaml"
|
|
| 526 | + self.run_command([adb, "push", tmp_file.name, remote_path])
|
|
| 527 | + |
|
| 528 | + self.run_command([
|
|
| 529 | + adb,
|
|
| 530 | + "shell",
|
|
| 531 | + "am",
|
|
| 532 | + "start",
|
|
| 533 | + "-S",
|
|
| 534 | + "-W",
|
|
| 535 | + "-n",
|
|
| 536 | + f"{self.package_name}/org.mozilla.gecko.BrowserApp",
|
|
| 537 | + ])
|
|
| 538 | + |
|
| 539 | + # Wait for Marionette to be ready
|
|
| 540 | + for attempt in range(5):
|
|
| 541 | + try:
|
|
| 542 | + self.info(
|
|
| 543 | + f"Checking Marionette on 127.0.0.1:2828 (attempt {attempt + 1}/5)"
|
|
| 544 | + )
|
|
| 545 | + socket.create_connection(("127.0.0.1", 2828), 10).close()
|
|
| 546 | + self.info("Marionette is reachable")
|
|
| 547 | + break
|
|
| 548 | + except OSError:
|
|
| 549 | + if attempt == 4:
|
|
| 550 | + self.fatal(
|
|
| 551 | + "Timed out waiting for 127.0.0.1:2828 to become reachable"
|
|
| 552 | + )
|
|
| 553 | + self.info("Marionette not reachable yet, retrying in 10s")
|
|
| 554 | + time.sleep(10)
|
|
| 555 | + |
|
| 476 | 556 | @PreScriptAction("create-virtualenv")
|
| 477 | 557 | def pre_create_virtualenv(self, action):
|
| 478 | 558 | dirs = self.query_abs_dirs()
|
| ... | ... | @@ -488,6 +568,9 @@ class AndroidEmulatorTest( |
| 488 | 568 | if requirements:
|
| 489 | 569 | self.register_virtualenv_module(requirements=[requirements])
|
| 490 | 570 | |
| 571 | + if ("marionette", "marionette") in suites:
|
|
| 572 | + self._configure_marionette_virtualenv(action)
|
|
| 573 | + |
|
| 491 | 574 | def download_and_extract(self):
|
| 492 | 575 | """
|
| 493 | 576 | Download and extract product APK, tests.zip, and host utils.
|
| ... | ... | @@ -525,6 +608,9 @@ class AndroidEmulatorTest( |
| 525 | 608 | for per_test_suite, suite in suites:
|
| 526 | 609 | self.test_suite = suite
|
| 527 | 610 | |
| 611 | + if self.test_suite == "marionette":
|
|
| 612 | + self._marionette_setup()
|
|
| 613 | + |
|
| 528 | 614 | try:
|
| 529 | 615 | cwd = self._query_tests_dir(self.test_suite)
|
| 530 | 616 | except Exception:
|
| ... | ... | @@ -594,6 +680,19 @@ class AndroidEmulatorTest( |
| 594 | 680 | % (suite_category, suite, tbpl_status),
|
| 595 | 681 | )
|
| 596 | 682 | |
| 683 | + @PostScriptAction("run-tests")
|
|
| 684 | + def marionette_teardown(self, *args, **kwargs):
|
|
| 685 | + if ("marionette", "marionette") in self._query_suites():
|
|
| 686 | + adb = self.query_exe("adb")
|
|
| 687 | + self.run_command([adb, "shell", "am", "force-stop", self.package_name])
|
|
| 688 | + self.run_command([adb, "uninstall", self.package_name])
|
|
| 689 | + self.run_command([
|
|
| 690 | + adb,
|
|
| 691 | + "shell",
|
|
| 692 | + "rm",
|
|
| 693 | + f"/data/local/tmp/{self.package_name}-geckoview-config.yaml",
|
|
| 694 | + ])
|
|
| 695 | + |
|
| 597 | 696 | |
| 598 | 697 | if __name__ == "__main__":
|
| 599 | 698 | test = AndroidEmulatorTest()
|