tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

test_background_update.py (5999B)


      1 import xml.etree.ElementTree as ET
      2 from os import environ
      3 from pathlib import Path
      4 
      5 import requests
      6 from marionette_driver import expected
      7 from marionette_driver.by import By
      8 from marionette_driver.wait import Wait
      9 from marionette_harness import MarionetteTestCase
     10 
     11 
     12 def get_update_server_response(update_url, force: int):
     13    response = requests.get(f"{update_url}?force={force}")
     14    if response.status_code != 200:
     15        raise Exception(
     16            f"Tried to fetch update.xml but got response code {response.status_code}"
     17        )
     18 
     19    return ET.fromstring(response.text)
     20 
     21 
     22 def get_possible_target_versions(update_url):
     23    """If throttled to a lower target version, return both possible versions"""
     24    versions = []
     25    for n in range(2):
     26        # Get the target version
     27        root = get_update_server_response(update_url, n)
     28        versions.append(root[0].get("appVersion"))
     29 
     30    return list(set(versions))
     31 
     32 
     33 class TestBackgroundUpdate(MarionetteTestCase):
     34    def setUp(self):
     35        MarionetteTestCase.setUp(self)
     36        self.about_fx_url = "chrome://browser/content/aboutDialog.xhtml"
     37 
     38    def test_background_update_is_applied(self):
     39        self.marionette.set_pref("app.update.disabledForTesting", False)
     40        self.marionette.set_pref("remote.system-access-check.enabled", False)
     41        self.marionette.set_pref("app.update.log", True)
     42        self.marionette.set_pref("remote.log.level", "Trace")
     43        self.marionette.set_pref("app.update.interval", 5)
     44        self.marionette.navigate(self.about_fx_url)
     45 
     46        self.marionette.set_context(self.marionette.CONTEXT_CHROME)
     47        update_url = self.marionette.execute_async_script(
     48            """
     49            (async function() {
     50                let { UpdateUtils } = ChromeUtils.importESModule(
     51                    "resource://gre/modules/UpdateUtils.sys.mjs"
     52                );
     53                let url = await UpdateUtils.formatUpdateURL(Services.appinfo.updateURL);
     54                return url;
     55            })().then(arguments[0]);
     56            """
     57        )
     58 
     59        target_vers = get_possible_target_versions(update_url)
     60 
     61        if environ.get("UPLOAD_DIR"):
     62            version_info_log = Path(
     63                environ.get("UPLOAD_DIR"), environ.get("VERSION_LOG_FILENAME")
     64            )
     65            if version_info_log.is_file():
     66                with version_info_log.open("a") as fh:
     67                    fh.write(f"Target version options: {', '.join(target_vers)}\n")
     68 
     69        # Wait for the background update to be ready by checking for popup
     70        # Long timeouts are a known issue - Bug 2000040
     71        Wait(self.marionette, timeout=100).until(
     72            lambda _: self.marionette.find_elements(By.ID, "appMenu-notification-popup")
     73        )
     74 
     75        # Try runs build unsigned updates, releases can't update on unsigned MARs
     76        # ...so we're just going to check that balrog gives a reasonably-named file that exists
     77        # We run the code here to maximize what gets run in try.
     78        if environ.get("BALROG_STAGING"):
     79            root = get_update_server_response(update_url, 1)
     80            patch_url = root[0][0].get("URL")
     81            assert f"/{target_vers[-1]}-candidates" in patch_url, (
     82                f'"/{target_vers[-1]}-candidates not in patch url: {patch_url}'
     83            )
     84            patch_response = requests.get(patch_url)
     85            patch_response.raise_for_status()
     86            return True
     87 
     88        # Dismiss the popup
     89        self.marionette.find_element(By.ID, "urlbar-input").click()
     90        self.marionette.find_element(By.ID, "PanelUI-menu-button").click()
     91        self.marionette.find_element(By.ID, "urlbar-input").click()
     92        self.marionette.find_element(By.ID, "PanelUI-menu-button").click()
     93 
     94        # Check that there is a green badge on hamburger menu
     95        Wait(self.marionette, timeout=100).until(
     96            lambda _: self.marionette.find_element(
     97                By.ID, "PanelUI-menu-button"
     98            ).get_attribute("badge-status")
     99            == "update-available"
    100        )
    101 
    102        # Click the update button in hamburger menu to download the update
    103        self.marionette.find_element(By.ID, "PanelUI-menu-button").click()
    104        self.marionette.find_element(By.ID, "appMenu-update-banner").click()
    105 
    106        # Make sure that the download is finished
    107        self.marionette.set_context(self.marionette.CONTEXT_CONTENT)
    108        Wait(self.marionette, timeout=200).until(
    109            expected.element_displayed(By.ID, "updateButton")
    110        )
    111        initial_ver = self.marionette.find_element(By.ID, "version").text
    112 
    113        # Restart normally
    114        self.marionette.restart()
    115 
    116        self.marionette.set_pref("app.update.disabledForTesting", False)
    117        self.marionette.set_pref("remote.system-access-check.enabled", False)
    118        self.marionette.set_pref("app.update.log", True)
    119        self.marionette.set_pref("remote.log.level", "Trace")
    120        self.marionette.navigate(self.about_fx_url)
    121        Wait(self.marionette, timeout=100).until(
    122            expected.element_displayed(By.ID, "version")
    123        )
    124 
    125        # Mini smoke test
    126        target_ver_verified = False
    127        version_text = self.marionette.find_element(By.ID, "version").text
    128        for target_ver in target_vers:
    129            if target_ver in version_text:
    130                target_ver_verified = True
    131                try:
    132                    print(f"Updated from {initial_ver} to {target_ver}")
    133                except UnicodeEncodeError:
    134                    print(f"Updated to {target_ver}")
    135        assert target_ver_verified
    136        assert len(self.marionette.window_handles) == 1
    137        self.marionette.open("tab")
    138        Wait(self.marionette, timeout=20).until(
    139            lambda _: len(self.marionette.window_handles) == 2
    140        )
    141        self.marionette.close()
    142        Wait(self.marionette, timeout=20).until(
    143            lambda _: len(self.marionette.window_handles) == 1
    144        )
    145 
    146    def tearDown(self):
    147        MarionetteTestCase.tearDown(self)