brizental pushed to branch tor-browser-149.0a1-16.0-2 at The Tor Project / Applications / Tor Browser Commits: 70bab416 by Beatriz Rizental at 2026-03-24T18:49:21+01:00 fixup! TB 43817: Add tests for Tor Browser Bug 43243: Make test bootstrap UI agnostic -- share the code between Android and Desktop. - - - - - 6 changed files: - testing/marionette/harness/marionette_harness/__init__.py - testing/marionette/harness/marionette_harness/runner/__init__.py - testing/marionette/harness/marionette_harness/runner/mixins/__init__.py - + testing/marionette/harness/marionette_harness/runner/mixins/tor_browser.py - testing/tor/test_circuit_isolation.py - testing/tor/test_network_check.py Changes: ===================================== testing/marionette/harness/marionette_harness/__init__.py ===================================== @@ -28,5 +28,6 @@ from .runner import ( TestManifest, TestResult, TestResultCollection, + TorBrowserMixin, WindowManagerMixin, ) ===================================== testing/marionette/harness/marionette_harness/runner/__init__.py ===================================== @@ -13,4 +13,7 @@ from .base import ( TestResult, TestResultCollection, ) -from .mixins import WindowManagerMixin +from .mixins import ( + TorBrowserMixin, + WindowManagerMixin, +) ===================================== testing/marionette/harness/marionette_harness/runner/mixins/__init__.py ===================================== @@ -3,3 +3,4 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. from .window_manager import WindowManagerMixin +from .tor_browser import TorBrowserMixin ===================================== testing/marionette/harness/marionette_harness/runner/mixins/tor_browser.py ===================================== @@ -0,0 +1,73 @@ +from marionette_driver.errors import ScriptTimeoutException + +DEFAULT_BOOTSTRAP_TIMEOUT_MS = 60 * 1000 +DEFAULT_BOOTSTRAP_MAX_RETRIES = 3 + +class TorBrowserMixin: + def bootstrap( + self, + max_retries=DEFAULT_BOOTSTRAP_MAX_RETRIES, + ): + """Bootstrap the Tor connection. + + This doesn't fail if already bootstrapped, but will retry a few times if + a script timeout is hit. + + This function is UI-agnostic, meaning it can be used both on Desktop and Android. + """ + + attempt = 0 + while attempt < max_retries: + try: + with self.marionette.using_context("chrome"): + self.marionette.execute_async_script( + """ + const { TorConnect, TorConnectStage, TorConnectTopics } = ChromeUtils.importESModule( + "resource://gre/modules/TorConnect.sys.mjs" + ); + const [resolve] = arguments; + + // Only the first test of a suite will need to bootstrap. + if (TorConnect.stage.name === TorConnectStage.Bootstrapped) { + resolve(); + return; + } + + function waitForBootstrap() { + const topic = TorConnectTopics.BootstrapComplete; + Services.obs.addObserver(function observer() { + Services.obs.removeObserver(observer, topic); + resolve(); + }, topic); + TorConnect.beginBootstrapping(); + } + + const stageTopic = TorConnectTopics.StageChange; + function stageObserver() { + if (TorConnect.canBeginNormalBootstrap) { + Services.obs.removeObserver(stageObserver, stageTopic); + waitForBootstrap(); + } + } + Services.obs.addObserver(stageObserver, stageTopic); + stageObserver(); + """, + script_timeout=DEFAULT_BOOTSTRAP_TIMEOUT_MS, + ) + + return + except ScriptTimeoutException: + attempt += 1 + with self.marionette.using_context("chrome"): + self.marionette.execute_script( + """ + const { TorConnect } = ChromeUtils.importESModule( + "resource://gre/modules/TorConnect.sys.mjs" + ); + + TorConnect._makeStageRequest(TorConnectStage.Start, true); + """ + ) + + + raise RuntimeError("Unable to connect to Tor Network") ===================================== testing/tor/test_circuit_isolation.py ===================================== @@ -2,47 +2,13 @@ from ipaddress import ip_address from marionette_driver import By from marionette_driver.errors import NoSuchElementException -from marionette_harness import MarionetteTestCase +from marionette_harness import MarionetteTestCase, TorBrowserMixin -TOR_BOOTSTRAP_TIMEOUT = 30000 # 30s - -class TestCircuitIsolation(MarionetteTestCase): +class TestCircuitIsolation(MarionetteTestCase, TorBrowserMixin): def tearDown(self): - self.marionette.restart(in_app=False, clean=True) super().tearDown() - def bootstrap(self): - with self.marionette.using_context("chrome"): - self.marionette.execute_async_script( - """ - const { TorConnect, TorConnectTopics } = ChromeUtils.importESModule( - "resource://gre/modules/TorConnect.sys.mjs" - ); - const [resolve] = arguments; - - function waitForBootstrap() { - const topic = TorConnectTopics.BootstrapComplete; - Services.obs.addObserver(function observer() { - Services.obs.removeObserver(observer, topic); - resolve(); - }, topic); - TorConnect.beginBootstrapping(); - } - - const stageTopic = TorConnectTopics.StageChange; - function stageObserver() { - if (TorConnect.canBeginNormalBootstrap) { - Services.obs.removeObserver(stageObserver, stageTopic); - waitForBootstrap(); - } - } - Services.obs.addObserver(stageObserver, stageTopic); - stageObserver(); - """, - script_timeout=TOR_BOOTSTRAP_TIMEOUT, - ) - def extract_from_check_tpo(self): # Fetch the IP from check.torproject.org. # In addition to that, since we are loading this page, we ===================================== testing/tor/test_network_check.py ===================================== @@ -1,69 +1,11 @@ -from marionette_driver import By, Wait, errors -from marionette_driver.localization import L10n -from marionette_harness import MarionetteTestCase +from marionette_harness import MarionetteTestCase, TorBrowserMixin NETWORK_CHECK_URL = "https://check.torproject.org/" -TOR_BOOTSTRAP_TIMEOUT = 30 # 30s -STRINGS_LOCATION = "chrome://torbutton/locale/torConnect.properties" - - -class TestNetworkCheck(MarionetteTestCase): - def setUp(self): - MarionetteTestCase.setUp(self) - - self.l10n = L10n(self.marionette) - - def tearDown(self): - self.marionette.restart(in_app=False, clean=True) - super().tearDown() - - def attemptConnection(self, tries=1): - if tries > 3: - self.assertTrue(False, "Failed to connect to Tor after 3 attempts") - - connectBtn = self.marionette.find_element(By.ID, "connectButton") - Wait(self.marionette, timeout=10).until( - lambda _: connectBtn.is_displayed(), - message="Timed out waiting for tor connect button to show up.", - ) - connectBtn.click() - - try: - - def check(m): - if not m.get_url().startswith("about:torconnect"): - # We have finished connecting and have been redirected. - return True - - try: - heading = self.marionette.find_element(By.ID, "tor-connect-heading") - except errors.NoSuchElementException: - # Page is probably redirecting. - return False - - if heading.text not in [ - self.l10n.localize_property( - [STRINGS_LOCATION], "torConnect.torConnecting" - ), - self.l10n.localize_property( - [STRINGS_LOCATION], "torConnect.torConnected" - ), - ]: - raise ValueError("Tor connect page is not connecting or connected") - - return False - - Wait(self.marionette, timeout=TOR_BOOTSTRAP_TIMEOUT).until(check) - except (errors.TimeoutException, ValueError): - cancelBtn = self.marionette.find_element(By.ID, "cancelButton") - if cancelBtn.is_displayed(): - cancelBtn.click() - - self.attemptConnection(tries + 1) +class TestNetworkCheck(MarionetteTestCase, TorBrowserMixin): def test_network_check(self): - self.attemptConnection() + self.bootstrap() self.marionette.navigate(NETWORK_CHECK_URL) self.assertRegex( self.marionette.title, View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/70bab416... -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/70bab416... You're receiving this email because of your account on gitlab.torproject.org. Manage all notifications: https://gitlab.torproject.org/-/profile/notifications | Help: https://gitlab.torproject.org/help
participants (1)
-
brizental (@brizental)