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)