icecat: add release icecat-140.8.0-2 for aramo
This commit is contained in:
parent
d9a6c0aa96
commit
d570f39e11
616 changed files with 39955 additions and 33937 deletions
|
|
@ -2,30 +2,131 @@
|
|||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, # You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
import json
|
||||
import logging
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from dataclasses import dataclass
|
||||
from os import environ, makedirs
|
||||
from pathlib import Path
|
||||
from platform import uname
|
||||
from shutil import copytree, unpack_archive
|
||||
|
||||
import mozinfo
|
||||
import mozinstall
|
||||
import requests
|
||||
from gecko_taskgraph.transforms.update_test import ReleaseType
|
||||
from mach.decorators import Command, CommandArgument
|
||||
from mozbuild.base import BinaryNotFoundException
|
||||
from mozlog.structured import commandline
|
||||
from mozrelease.update_verify import UpdateVerifyConfig
|
||||
|
||||
TEST_UPDATE_CHANNEL = "release-localtest"
|
||||
if TEST_UPDATE_CHANNEL.startswith("release"):
|
||||
MAR_CHANNEL = "icecat-mozilla-release"
|
||||
elif TEST_UPDATE_CHANNEL.startswith("beta"):
|
||||
MAR_CHANNEL = "icecat-mozilla-beta"
|
||||
else:
|
||||
MAR_CHANNEL = "icecat-mozilla-central"
|
||||
TEST_REGION = "en-US"
|
||||
TEST_SOURCE_VERSION = "135.0.1"
|
||||
FX_DOWNLOAD_DIR_URL = "https://archive.mozilla.org/pub/icecat/releases/"
|
||||
APP_DIR_NAME = "fx_test"
|
||||
STAGING_POLICY_PAYLOAD = {
|
||||
"policies": {
|
||||
"AppUpdateURL": "https://stage.balrog.nonprod.cloudops.mozgcp.net/update/6/IceCat/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%SYSTEM_CAPABILITIES%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/update.xml"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@dataclass
|
||||
class UpdateTestConfig:
|
||||
"""Track all needed test config"""
|
||||
|
||||
channel: str = "release-localtest"
|
||||
mar_channel: str = "icecat-mozilla-release"
|
||||
app_dir_name: str = "fx_test"
|
||||
manifest_loc: str = "testing/update/manifest.toml"
|
||||
# Where in the list of allowable source versions should we default to testing
|
||||
source_version_position: int = -3
|
||||
# How many major versions back can we test?
|
||||
major_version_range: int = 3
|
||||
locale: str = "en-US"
|
||||
update_verify_file: str = "update-verify.cfg"
|
||||
update_verify_config = None
|
||||
config_source = None
|
||||
release_type: ReleaseType = ReleaseType.release
|
||||
esr_version = None
|
||||
staging_update = False
|
||||
|
||||
def __post_init__(self):
|
||||
if environ.get("UPLOAD_DIR"):
|
||||
self.artifact_dir = Path(environ.get("UPLOAD_DIR"), "update-test")
|
||||
makedirs(self.artifact_dir, exist_ok=True)
|
||||
self.version_info_path = Path(
|
||||
self.artifact_dir, environ.get("VERSION_LOG_FILENAME")
|
||||
)
|
||||
|
||||
else:
|
||||
self.version_info_path = None
|
||||
|
||||
def set_channel(self, new_channel, esr_version=None):
|
||||
self.channel = new_channel
|
||||
if self.channel.startswith("release"):
|
||||
self.mar_channel = "icecat-mozilla-release"
|
||||
self.release_type = ReleaseType.release
|
||||
elif self.channel.startswith("beta"):
|
||||
self.mar_channel = "icecat-mozilla-beta,icecat-mozilla-release"
|
||||
self.release_type = ReleaseType.beta
|
||||
elif self.channel.startswith("esr"):
|
||||
self.mar_channel = "icecat-mozilla-esr,icecat-mozilla-release"
|
||||
self.release_type = ReleaseType.esr
|
||||
self.esr_version = esr_version
|
||||
else:
|
||||
self.mar_channel = "icecat-mozilla-central"
|
||||
self.release_type = ReleaseType.other
|
||||
|
||||
def set_ftp_info(self):
|
||||
"""Get server URL and template for downloading application/installer"""
|
||||
# The %release% string will be replaced by a version number later
|
||||
platform, executable_name = get_fx_executable_name("%release%")
|
||||
if self.update_verify_config:
|
||||
full_info_release = next(
|
||||
r for r in self.update_verify_config.releases if r.get("from")
|
||||
)
|
||||
executable_name = Path(full_info_release["from"]).name
|
||||
release_number = full_info_release["from"].split("/")[3]
|
||||
executable_name = executable_name.replace(release_number, "%release%")
|
||||
executable_name = executable_name.replace(".bz2", ".xz")
|
||||
executable_name = executable_name.replace(".pkg", ".dmg")
|
||||
executable_name = executable_name.replace(".msi", ".exe")
|
||||
template = (
|
||||
f"https://archive.mozilla.org/pub/icecat/releases/%release%/{platform}/{self.locale}/"
|
||||
+ executable_name
|
||||
)
|
||||
|
||||
self.ftp_server = template.split("%release%")[0]
|
||||
self.url_template = template
|
||||
|
||||
def add_update_verify_config(self, filename=None):
|
||||
"""Parse update-verify.cfg. Obtain a copy if not found in dep/commandline"""
|
||||
if not filename:
|
||||
platform, _ = get_fx_executable_name("")
|
||||
config_route = (
|
||||
"https://icecat-ci-tc.services.mozilla.com/api/"
|
||||
"index/v1/task/gecko.v2.mozilla-central.latest.icecat."
|
||||
f"update-verify-config-icecat-{platform}-{self.channel}"
|
||||
"/artifacts/public%2Fbuild%2Fupdate-verify.cfg"
|
||||
)
|
||||
resp = requests.get(config_route)
|
||||
try:
|
||||
resp.raise_for_status()
|
||||
filename = Path(self.tempdir, self.update_verify_file)
|
||||
with open(filename, "wb") as fh:
|
||||
fh.write(resp.content)
|
||||
self.config_source = "route"
|
||||
except requests.exceptions.HTTPError:
|
||||
return None
|
||||
|
||||
uv_config = UpdateVerifyConfig()
|
||||
uv_config.read(filename)
|
||||
self.update_verify_config = uv_config
|
||||
# Beta display version example "140.0 Beta 3", Release just like "140.0"
|
||||
if "Beta" in uv_config.to_display_version:
|
||||
major, beta = uv_config.to_display_version.split(" Beta ")
|
||||
self.target_version = f"{major}b{beta}"
|
||||
else:
|
||||
self.target_version = uv_config.to_display_version
|
||||
|
||||
|
||||
def setup_update_argument_parser():
|
||||
|
|
@ -39,50 +140,179 @@ def setup_update_argument_parser():
|
|||
|
||||
|
||||
def get_fx_executable_name(version):
|
||||
u = uname()
|
||||
|
||||
if u.system == "Darwin":
|
||||
platform = "mac"
|
||||
"""Given a version string, get the expected downloadable name for the os"""
|
||||
if mozinfo.os == "mac":
|
||||
executable_platform = "mac"
|
||||
executable_name = f"IceCat {version}.dmg"
|
||||
|
||||
if u.system == "Linux":
|
||||
if "64" in u.machine:
|
||||
platform = "linux-x86_64"
|
||||
else:
|
||||
platform = "linux-x86_64"
|
||||
if int(version.split(".")[0]) < 135:
|
||||
if mozinfo.os == "linux":
|
||||
executable_platform = "linux-x86_64"
|
||||
try:
|
||||
assert int(version.split(".")[0]) < 135
|
||||
executable_name = f"icecat-{version}.tar.bz2"
|
||||
else:
|
||||
except (AssertionError, ValueError):
|
||||
executable_name = f"icecat-{version}.tar.xz"
|
||||
|
||||
if u.system == "Windows":
|
||||
if u.machine == "ARM64":
|
||||
platform = "win64-aarch64"
|
||||
elif "64" in u.machine:
|
||||
platform = "win64"
|
||||
if mozinfo.os == "win":
|
||||
if mozinfo.arch == "aarch64":
|
||||
executable_platform = "win64-aarch64"
|
||||
elif mozinfo.bits == "64":
|
||||
executable_platform = "win64"
|
||||
else:
|
||||
platform = "win32"
|
||||
executable_platform = "win32"
|
||||
executable_name = f"IceCat Setup {version}.exe"
|
||||
|
||||
return platform, executable_name.replace(" ", "%20")
|
||||
return executable_platform, executable_name.replace(" ", "%20")
|
||||
|
||||
|
||||
def get_binary_path(tempdir, **kwargs) -> str:
|
||||
def get_valid_source_versions(config):
|
||||
"""
|
||||
Get a list of versions to update from, based on config.
|
||||
For beta, this means a list of betas, not releases.
|
||||
For ESR, this means a list of ESR versions where major version matches target.
|
||||
"""
|
||||
ftp_content = requests.get(config.ftp_server).content.decode()
|
||||
# All versions start with e.g. 140.0, so beta and release can be int'ed
|
||||
ver_head, ver_tail = config.target_version.split(".", 1)
|
||||
latest_version = int(ver_head)
|
||||
latest_minor_str = ""
|
||||
# Versions like 130.10.1 and 130.0 are possible, capture the minor number
|
||||
for c in ver_tail:
|
||||
try:
|
||||
int(c)
|
||||
latest_minor_str = latest_minor_str + c
|
||||
except ValueError:
|
||||
break
|
||||
|
||||
valid_versions: list[str] = []
|
||||
for major in range(latest_version - config.major_version_range, latest_version + 1):
|
||||
minor_versions = []
|
||||
if config.release_type == ReleaseType.esr and major != latest_version:
|
||||
continue
|
||||
for minor in range(0, 11):
|
||||
if (
|
||||
config.release_type == ReleaseType.release
|
||||
and f"/{major}.{minor}/" in ftp_content
|
||||
):
|
||||
if f"{major}.{minor}" == config.target_version:
|
||||
break
|
||||
minor_versions.append(minor)
|
||||
valid_versions.append(f"{major}.{minor}")
|
||||
elif config.release_type == ReleaseType.esr and re.compile(
|
||||
rf"/{major}\.{minor}.*/"
|
||||
).search(ftp_content):
|
||||
minor_versions.append(minor)
|
||||
if f"/{major}.{minor}esr" in ftp_content:
|
||||
valid_versions.append(f"{major}.{minor}")
|
||||
elif config.release_type == ReleaseType.beta and minor == 0:
|
||||
# Release 1xx.0 is not available, but 1xx.0b1 is:
|
||||
minor_versions.append(minor)
|
||||
|
||||
sep = "b" if config.release_type == ReleaseType.beta else "."
|
||||
|
||||
for minor in minor_versions:
|
||||
for dot in range(0, 15):
|
||||
if f"{major}.{minor}{sep}{dot}" == config.target_version:
|
||||
break
|
||||
if config.release_type == ReleaseType.esr:
|
||||
if f"/{major}.{minor}{sep}{dot}esr/" in ftp_content:
|
||||
valid_versions.append(f"{major}.{minor}{sep}{dot}")
|
||||
elif f"/{major}.{minor}{sep}{dot}/" in ftp_content:
|
||||
valid_versions.append(f"{major}.{minor}{sep}{dot}")
|
||||
|
||||
# Only test beta versions if channel is beta
|
||||
if config.release_type == ReleaseType.beta:
|
||||
valid_versions = [ver for ver in valid_versions if "b" in ver]
|
||||
elif config.release_type == ReleaseType.esr:
|
||||
valid_versions = [
|
||||
f"{ver}esr" if not ver.endswith("esr") else ver for ver in valid_versions
|
||||
]
|
||||
valid_versions.sort()
|
||||
while len(valid_versions) < 5:
|
||||
valid_versions.insert(0, valid_versions[0])
|
||||
return valid_versions
|
||||
|
||||
|
||||
def get_binary_path(config: UpdateTestConfig, **kwargs) -> str:
|
||||
# Install correct Fx and return executable location
|
||||
platform, executable_name = get_fx_executable_name(TEST_SOURCE_VERSION)
|
||||
if not config.source_version:
|
||||
if config.update_verify_config:
|
||||
# In future, we can modify this for watershed logic
|
||||
source_versions = get_valid_source_versions(config)
|
||||
else:
|
||||
response = requests.get(
|
||||
"https://product-details.mozilla.org/1.0/icecat_versions.json"
|
||||
)
|
||||
response.raise_for_status()
|
||||
product_details = response.json()
|
||||
if config.release_type == ReleaseType.beta:
|
||||
target_channel = "LATEST_ICECAT_RELEASED_DEVEL_VERSION"
|
||||
elif config.release_type == ReleaseType.esr:
|
||||
current_esr = product_details.get("ICECAT_ESR").split(".")[0]
|
||||
if config.esr_version == current_esr:
|
||||
target_channel = "ICECAT_ESR"
|
||||
else:
|
||||
target_channel = f"ICECAT_ESR{config.esr_version}"
|
||||
else:
|
||||
target_channel = "LATEST_ICECAT_VERSION"
|
||||
|
||||
executable_url = rf"{FX_DOWNLOAD_DIR_URL}{TEST_SOURCE_VERSION}/{platform}/{TEST_REGION}/{executable_name}"
|
||||
target_version = product_details.get(target_channel)
|
||||
config.target_version = target_version
|
||||
source_versions = get_valid_source_versions(config)
|
||||
|
||||
installer_filename = Path(tempdir, Path(executable_url).name)
|
||||
installed_app_dir = Path(tempdir, APP_DIR_NAME)
|
||||
# NB below: value 0 will get you the oldest acceptable version, not the newest
|
||||
source_version = source_versions[config.source_version_position]
|
||||
config.source_version = source_version
|
||||
platform, executable_name = get_fx_executable_name(config.source_version)
|
||||
|
||||
os_edition = f"{mozinfo.os} {mozinfo.os_version}"
|
||||
if config.version_info_path:
|
||||
# Only write the file on non-local runs
|
||||
print(f"Writing source info to {config.version_info_path.resolve()}...")
|
||||
with config.version_info_path.open("a") as fh:
|
||||
fh.write(f"Test Type: {kwargs.get('test_type')}\n")
|
||||
fh.write(f"UV Config Source: {config.config_source}\n")
|
||||
fh.write(f"Region: {config.locale}\n")
|
||||
fh.write(f"Source Version: {config.source_version}\n")
|
||||
fh.write(f"Platform: {os_edition}\n")
|
||||
with config.version_info_path.open() as fh:
|
||||
print("".join(fh.readlines()))
|
||||
else:
|
||||
print(
|
||||
f"Region: {config.locale}\nSource Version: {source_version}\nPlatform: {os_edition}"
|
||||
)
|
||||
|
||||
executable_url = config.url_template.replace("%release%", config.source_version)
|
||||
|
||||
installer_filename = Path(config.tempdir, Path(executable_url).name)
|
||||
installed_app_dir = Path(config.tempdir, config.app_dir_name)
|
||||
print(f"Downloading Fx from {executable_url}...")
|
||||
response = requests.get(executable_url)
|
||||
if 199 < response.status_code < 300:
|
||||
print(f"Download successful, status {response.status_code}")
|
||||
with open(installer_filename, "wb") as fh:
|
||||
response.raise_for_status()
|
||||
print(f"Download successful, status {response.status_code}")
|
||||
with installer_filename.open("wb") as fh:
|
||||
fh.write(response.content)
|
||||
fx_location = mozinstall.install(installer_filename, installed_app_dir)
|
||||
print(f"IceCat installed to {fx_location}")
|
||||
|
||||
if config.staging_update:
|
||||
print("Writing enterprise policy for update server")
|
||||
fx_path = Path(fx_location)
|
||||
policy_path = None
|
||||
if mozinfo.os in ["linux", "win"]:
|
||||
policy_path = fx_path / "distribution"
|
||||
elif mozinfo.os == "mac":
|
||||
policy_path = fx_path / "Contents" / "Resources" / "distribution"
|
||||
else:
|
||||
raise ValueError("Invalid OS.")
|
||||
makedirs(policy_path)
|
||||
policy_loc = policy_path / "policies.json"
|
||||
print(f"Creating {policy_loc}...")
|
||||
with policy_loc.open("w") as fh:
|
||||
json.dump(STAGING_POLICY_PAYLOAD, fh, indent=2)
|
||||
with policy_loc.open() as fh:
|
||||
print(fh.read())
|
||||
|
||||
return fx_location
|
||||
|
||||
|
||||
|
|
@ -93,18 +323,97 @@ def get_binary_path(tempdir, **kwargs) -> str:
|
|||
description="Test if the version can be updated to the latest patch successfully,",
|
||||
parser=setup_update_argument_parser,
|
||||
)
|
||||
@CommandArgument("--binary_path", help="IceCat executable path is needed")
|
||||
@CommandArgument("--binary-path", help="IceCat executable path is needed")
|
||||
@CommandArgument("--test-type", default="Base", help="Base/Background")
|
||||
@CommandArgument("--source-version", help="IceCat build version to update from")
|
||||
@CommandArgument(
|
||||
"--source-versions-back",
|
||||
help="Update from the version of Fx $N releases before current",
|
||||
)
|
||||
@CommandArgument("--source-locale", help="IceCat build locale to update from")
|
||||
@CommandArgument("--channel", default="release-localtest", help="Update channel to use")
|
||||
@CommandArgument(
|
||||
"--esr-version",
|
||||
help="ESR version, if set with --channel=esr, will only update within ESR major version",
|
||||
)
|
||||
@CommandArgument("--uv-config-file", help="Update Verify config file")
|
||||
@CommandArgument(
|
||||
"--use-balrog-staging", action="store_true", help="Update from staging, not prod"
|
||||
)
|
||||
def build(command_context, binary_path, **kwargs):
|
||||
config = UpdateTestConfig()
|
||||
|
||||
fetches = environ.get("MOZ_FETCHES_DIR")
|
||||
if fetches:
|
||||
config_file = Path(fetches, config.update_verify_file)
|
||||
if kwargs.get("uv_config_file"):
|
||||
config.config_source = "commandline"
|
||||
elif config_file.is_file():
|
||||
kwargs["uv_config_file"] = config_file
|
||||
config.config_source = "kind_dependency"
|
||||
|
||||
if not kwargs.get("uv_config_file"):
|
||||
config.add_update_verify_config()
|
||||
else:
|
||||
config.add_update_verify_config(kwargs["uv_config_file"])
|
||||
# TODO: update tests to check against config version, not update server resp
|
||||
# kwargs["to_display_version"] = uv_config.to_display_version
|
||||
|
||||
if kwargs.get("source_locale"):
|
||||
config.locale = kwargs["source_locale"]
|
||||
|
||||
if kwargs.get("source_versions_back"):
|
||||
config.source_version_position = -int(kwargs["source_versions_back"])
|
||||
|
||||
if kwargs.get("source_version"):
|
||||
config.source_version = kwargs["source_version"]
|
||||
else:
|
||||
config.source_version = None
|
||||
|
||||
config.set_ftp_info()
|
||||
|
||||
tempdir = tempfile.TemporaryDirectory()
|
||||
# If we have a symlink to the tmp directory, resolve it
|
||||
tempdir_name = str(Path(tempdir.name).resolve())
|
||||
config.tempdir = tempdir_name
|
||||
test_type = kwargs.get("test_type")
|
||||
|
||||
if kwargs.get("use_balrog_staging"):
|
||||
config.staging_update = True
|
||||
|
||||
# Select update channel
|
||||
if kwargs.get("channel"):
|
||||
config.set_channel(kwargs["channel"], kwargs.get("esr_version"))
|
||||
# if (config.beta and not config.update_verify_config):
|
||||
# logging.error("Non-release testing on local machines is not supported.")
|
||||
# sys.exit(1)
|
||||
|
||||
# Run the specified test in the suite
|
||||
with open(config.manifest_loc) as f:
|
||||
old_content = f.read()
|
||||
|
||||
with open(config.manifest_loc, "w") as f:
|
||||
f.write("[DEFAULT]\n\n")
|
||||
if test_type.lower() == "base":
|
||||
f.write('["test_apply_update.py"]')
|
||||
elif test_type.lower() == "background":
|
||||
f.write('["test_background_update.py"]')
|
||||
else:
|
||||
logging.ERROR("Invalid test type")
|
||||
sys.exit(1)
|
||||
|
||||
config.dir = command_context.topsrcdir
|
||||
|
||||
if mozinfo.os == "win":
|
||||
config.log_file_path = bits_pretest()
|
||||
try:
|
||||
kwargs["binary"] = set_up(
|
||||
binary_path or get_binary_path(tempdir_name, **kwargs), tempdir=tempdir_name
|
||||
)
|
||||
return run_tests(
|
||||
topsrcdir=command_context.topsrcdir, tempdir=tempdir_name, **kwargs
|
||||
binary_path or get_binary_path(config, **kwargs), config
|
||||
)
|
||||
# TODO: change tests to check against config, not update server response
|
||||
# if not kwargs.get("to_display_version"):
|
||||
# kwargs["to_display_version"] = config.target_version
|
||||
return run_tests(config, **kwargs)
|
||||
except BinaryNotFoundException as e:
|
||||
command_context.log(
|
||||
logging.ERROR,
|
||||
|
|
@ -115,16 +424,20 @@ def build(command_context, binary_path, **kwargs):
|
|||
command_context.log(logging.INFO, "update-test", {"help": e.help()}, "{help}")
|
||||
return 1
|
||||
finally:
|
||||
with open(config.manifest_loc, "w") as f:
|
||||
f.write(old_content)
|
||||
if mozinfo.os == "win":
|
||||
bits_posttest(config)
|
||||
tempdir.cleanup()
|
||||
|
||||
|
||||
def run_tests(binary=None, topsrcdir=None, tempdir=None, **kwargs):
|
||||
def run_tests(config, **kwargs):
|
||||
from argparse import Namespace
|
||||
|
||||
from marionette_harness.runtests import MarionetteHarness, MarionetteTestRunner
|
||||
|
||||
args = Namespace()
|
||||
args.binary = binary
|
||||
args.binary = kwargs["binary"]
|
||||
args.logger = kwargs.pop("log", None)
|
||||
if not args.logger:
|
||||
args.logger = commandline.setup_logging(
|
||||
|
|
@ -136,8 +449,8 @@ def run_tests(binary=None, topsrcdir=None, tempdir=None, **kwargs):
|
|||
|
||||
args.tests = [
|
||||
Path(
|
||||
topsrcdir,
|
||||
"testing/update/manifest.toml",
|
||||
config.dir,
|
||||
config.manifest_loc,
|
||||
)
|
||||
]
|
||||
args.gecko_log = "-"
|
||||
|
|
@ -146,22 +459,25 @@ def run_tests(binary=None, topsrcdir=None, tempdir=None, **kwargs):
|
|||
parser.verify_usage(args)
|
||||
|
||||
failed = MarionetteHarness(MarionetteTestRunner, args=vars(args)).run()
|
||||
if config.version_info_path:
|
||||
with config.version_info_path.open("a") as fh:
|
||||
fh.write(f"Status: {'failed' if failed else 'passed'}\n")
|
||||
if failed > 0:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
def copy_macos_channelprefs(tempdir) -> str:
|
||||
def copy_macos_channelprefs(config) -> str:
|
||||
# Copy ChannelPrefs.framework to the correct location on MacOS,
|
||||
# return the location of the Fx executable
|
||||
installed_app_dir = Path(tempdir, APP_DIR_NAME)
|
||||
installed_app_dir = Path(config.tempdir, config.app_dir_name)
|
||||
|
||||
bz_channelprefs_link = "https://bugzilla.mozilla.org/attachment.cgi?id=9417387"
|
||||
|
||||
resp = requests.get(bz_channelprefs_link)
|
||||
download_target = Path(tempdir, "channelprefs.zip")
|
||||
download_target = Path(config.tempdir, "channelprefs.zip")
|
||||
unpack_target = str(download_target).rsplit(".", 1)[0]
|
||||
with open(download_target, "wb") as fh:
|
||||
with download_target.open("wb") as fh:
|
||||
fh.write(resp.content)
|
||||
|
||||
unpack_archive(download_target, unpack_target)
|
||||
|
|
@ -169,8 +485,8 @@ def copy_macos_channelprefs(tempdir) -> str:
|
|||
f"Downloaded channelprefs.zip to {download_target} and unpacked to {unpack_target}"
|
||||
)
|
||||
|
||||
src = Path(tempdir, "channelprefs", TEST_UPDATE_CHANNEL)
|
||||
dst = Path(installed_app_dir, "Contents", "Frameworks")
|
||||
src = Path(config.tempdir, "channelprefs", config.channel)
|
||||
dst = Path(installed_app_dir, "IceCat.app", "Contents", "Frameworks")
|
||||
|
||||
Path(installed_app_dir, "IceCat.app").chmod(455) # rwx for all users
|
||||
|
||||
|
|
@ -188,20 +504,72 @@ def copy_macos_channelprefs(tempdir) -> str:
|
|||
return str(fx_executable)
|
||||
|
||||
|
||||
def set_up(binary_path, tempdir):
|
||||
def set_up(binary_path, config):
|
||||
# Set channel prefs for all OS targets
|
||||
binary_path_str = mozinstall.get_binary(binary_path, "IceCat")
|
||||
print(f"Binary path: {binary_path_str}")
|
||||
binary_dir = Path(binary_path_str).absolute().parent
|
||||
|
||||
if uname().system == "Darwin":
|
||||
return copy_macos_channelprefs(tempdir)
|
||||
if mozinfo.os == "mac":
|
||||
return copy_macos_channelprefs(config)
|
||||
else:
|
||||
with Path(binary_dir, "update-settings.ini").open("w") as f:
|
||||
f.write("[Settings]\n")
|
||||
f.write(f"ACCEPTED_MAR_CHANNEL_IDS={MAR_CHANNEL}")
|
||||
f.write(f"ACCEPTED_MAR_CHANNEL_IDS={config.mar_channel}")
|
||||
|
||||
with Path(binary_dir, "defaults", "pref", "channel-prefs.js").open("w") as f:
|
||||
f.write(f'pref("app.update.channel", "{TEST_UPDATE_CHANNEL}");')
|
||||
f.write(f'pref("app.update.channel", "{config.channel}");')
|
||||
|
||||
return binary_path_str
|
||||
|
||||
|
||||
def bits_pretest():
|
||||
# Check that BITS is enabled
|
||||
for line in subprocess.check_output(["sc", "qc", "BITS"], text=True).split("\n"):
|
||||
if "START_TYPE" in line:
|
||||
assert "DISABLED" not in line
|
||||
# Write all logs to a file to check for results later
|
||||
log_file = tempfile.NamedTemporaryFile(mode="wt", delete=False)
|
||||
sys.stdout = log_file
|
||||
return log_file
|
||||
|
||||
|
||||
def bits_posttest(config):
|
||||
if config.staging_update:
|
||||
# If we are in try, we didn't run the full test and BITS will fail.
|
||||
return None
|
||||
config.log_file_path.close()
|
||||
sys.stdout = sys.__stdout__
|
||||
|
||||
failed = 0
|
||||
try:
|
||||
# Check that all the expected logs are present
|
||||
downloader_regex = r"UpdateService:makeBitsRequest - Starting BITS download with url: https?:\/\/.+, updateDir: .+, filename: .+"
|
||||
bits_download_regex = (
|
||||
r"Downloader:downloadUpdate - BITS download running. BITS ID: {.+}"
|
||||
)
|
||||
|
||||
with open(config.log_file_path.name, errors="ignore") as f:
|
||||
logs = f.read()
|
||||
assert re.search(downloader_regex, logs)
|
||||
assert re.search(bits_download_regex, logs)
|
||||
assert (
|
||||
"AUS:SVC Downloader:_canUseBits - Not using BITS because it was already tried"
|
||||
not in logs
|
||||
)
|
||||
assert (
|
||||
"AUS:SVC Downloader:downloadUpdate - Starting nsIIncrementalDownload with url:"
|
||||
not in logs
|
||||
)
|
||||
except (UnicodeDecodeError, AssertionError) as e:
|
||||
failed = 1
|
||||
logging.error(e.__traceback__)
|
||||
finally:
|
||||
Path(config.log_file_path.name).unlink()
|
||||
|
||||
if config.version_info_path:
|
||||
with config.version_info_path.open("a") as fh:
|
||||
fh.write(f"BITS: {'failed' if failed else 'passed'}\n")
|
||||
|
||||
if failed:
|
||||
sys.exit(1)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
import xml.etree.ElementTree as ET
|
||||
from os import environ
|
||||
from pathlib import Path
|
||||
|
||||
import requests
|
||||
from marionette_driver import expected
|
||||
from marionette_driver.by import By
|
||||
from marionette_driver.wait import Wait
|
||||
|
|
@ -11,18 +16,59 @@ class TestApplyUpdate(MarionetteTestCase):
|
|||
|
||||
def test_update_is_applied(self):
|
||||
self.marionette.set_pref("app.update.disabledForTesting", False)
|
||||
self.marionette.set_pref("remote.system-access-check.enabled", False)
|
||||
self.marionette.set_pref("app.update.log", True)
|
||||
self.marionette.set_pref("remote.log.level", "Trace")
|
||||
self.marionette.set_pref("remote.system-access-check.enabled", False)
|
||||
self.marionette.navigate(self.about_fx_url)
|
||||
|
||||
self.marionette.set_context(self.marionette.CONTEXT_CHROME)
|
||||
update_url = self.marionette.execute_async_script(
|
||||
"""
|
||||
(async function() {
|
||||
const checker = Cc["@mozilla.org/updates/update-checker;1"].getService(Ci.nsIUpdateChecker);
|
||||
let url = await checker.wrappedJSObject.getUpdateURL(checker.BACKGROUND_CHECK);
|
||||
return url;
|
||||
})().then(arguments[0]);
|
||||
"""
|
||||
)
|
||||
|
||||
response = requests.get(f"{update_url}?force=1")
|
||||
response.raise_for_status()
|
||||
|
||||
# Get the target version
|
||||
root = ET.fromstring(response.text)
|
||||
target_ver = root[0].get("appVersion")
|
||||
|
||||
if environ.get("UPLOAD_DIR"):
|
||||
version_info_log = Path(
|
||||
environ.get("UPLOAD_DIR"), environ.get("VERSION_LOG_FILENAME")
|
||||
)
|
||||
if version_info_log.is_file():
|
||||
with version_info_log.open("a") as fh:
|
||||
fh.write(f"Target version: {target_ver}\n")
|
||||
|
||||
self.marionette.set_context(self.marionette.CONTEXT_CONTENT)
|
||||
initial_ver = self.marionette.find_element(By.ID, "version").text
|
||||
|
||||
# Try runs build unsigned updates, releases can't update on unsigned MARs
|
||||
# ...so we're just going to check that balrog gives a reasonably-named file that exists
|
||||
if environ.get("BALROG_STAGING"):
|
||||
print("staging")
|
||||
patch_url = root[0][0].get("URL")
|
||||
assert (
|
||||
f"{target_ver}" in patch_url
|
||||
), f"{target_ver} not in patch url: {patch_url}"
|
||||
patch_response = requests.get(patch_url)
|
||||
patch_response.raise_for_status()
|
||||
return True
|
||||
|
||||
Wait(self.marionette, timeout=10).until(
|
||||
expected.element_displayed(By.ID, "downloadAndInstallButton")
|
||||
)
|
||||
self.marionette.find_element(By.ID, "downloadAndInstallButton").click()
|
||||
|
||||
Wait(self.marionette, timeout=200).until(
|
||||
# Long timeouts are a known issue - Bug 2000040
|
||||
Wait(self.marionette, timeout=240).until(
|
||||
expected.element_displayed(By.ID, "updateButton")
|
||||
)
|
||||
|
||||
|
|
@ -31,13 +77,31 @@ class TestApplyUpdate(MarionetteTestCase):
|
|||
)
|
||||
|
||||
self.marionette.set_pref("app.update.disabledForTesting", False)
|
||||
self.marionette.set_pref("remote.system-access-check.enabled", False)
|
||||
self.marionette.set_pref("app.update.log", True)
|
||||
self.marionette.set_pref("remote.log.level", "Trace")
|
||||
self.marionette.set_pref("remote.system-access-check.enabled", False)
|
||||
self.marionette.navigate(self.about_fx_url)
|
||||
Wait(self.marionette, timeout=200).until(
|
||||
|
||||
Wait(self.marionette, timeout=240).until(
|
||||
expected.element_displayed(By.ID, "noUpdatesFound")
|
||||
)
|
||||
|
||||
# Mini smoke test
|
||||
try:
|
||||
print(f"Updated from {initial_ver} to {target_ver}")
|
||||
except UnicodeEncodeError:
|
||||
print(f"Updated to {target_ver}")
|
||||
version_text = self.marionette.find_element(By.ID, "version").text
|
||||
assert target_ver in version_text
|
||||
assert len(self.marionette.window_handles) == 1
|
||||
self.marionette.open("tab")
|
||||
Wait(self.marionette, timeout=20).until(
|
||||
lambda _: len(self.marionette.window_handles) == 2
|
||||
)
|
||||
self.marionette.close()
|
||||
Wait(self.marionette, timeout=20).until(
|
||||
lambda _: len(self.marionette.window_handles) == 1
|
||||
)
|
||||
|
||||
def tearDown(self):
|
||||
MarionetteTestCase.tearDown(self)
|
||||
|
|
|
|||
147
icecat/testing/update/test_background_update.py
Normal file
147
icecat/testing/update/test_background_update.py
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
import xml.etree.ElementTree as ET
|
||||
from os import environ
|
||||
from pathlib import Path
|
||||
|
||||
import requests
|
||||
from marionette_driver import expected
|
||||
from marionette_driver.by import By
|
||||
from marionette_driver.wait import Wait
|
||||
from marionette_harness import MarionetteTestCase
|
||||
|
||||
|
||||
def get_update_server_response(update_url, force: int):
|
||||
response = requests.get(f"{update_url}?force={force}")
|
||||
if response.status_code != 200:
|
||||
raise Exception(
|
||||
f"Tried to fetch update.xml but got response code {response.status_code}"
|
||||
)
|
||||
|
||||
return ET.fromstring(response.text)
|
||||
|
||||
|
||||
def get_possible_target_versions(update_url):
|
||||
"""If throttled to a lower target version, return both possible versions"""
|
||||
versions = []
|
||||
for n in range(2):
|
||||
# Get the target version
|
||||
root = get_update_server_response(update_url, n)
|
||||
versions.append(root[0].get("appVersion"))
|
||||
|
||||
return list(set(versions))
|
||||
|
||||
|
||||
class TestBackgroundUpdate(MarionetteTestCase):
|
||||
def setUp(self):
|
||||
MarionetteTestCase.setUp(self)
|
||||
self.about_fx_url = "chrome://browser/content/aboutDialog.xhtml"
|
||||
|
||||
def test_background_update_is_applied(self):
|
||||
self.marionette.set_pref("app.update.disabledForTesting", False)
|
||||
self.marionette.set_pref("remote.system-access-check.enabled", False)
|
||||
self.marionette.set_pref("app.update.log", True)
|
||||
self.marionette.set_pref("remote.log.level", "Trace")
|
||||
self.marionette.set_pref("app.update.interval", 5)
|
||||
self.marionette.navigate(self.about_fx_url)
|
||||
|
||||
self.marionette.set_context(self.marionette.CONTEXT_CHROME)
|
||||
update_url = self.marionette.execute_async_script(
|
||||
"""
|
||||
(async function() {
|
||||
let { UpdateUtils } = ChromeUtils.importESModule(
|
||||
"resource://gre/modules/UpdateUtils.sys.mjs"
|
||||
);
|
||||
let url = await UpdateUtils.formatUpdateURL(Services.appinfo.updateURL);
|
||||
return url;
|
||||
})().then(arguments[0]);
|
||||
"""
|
||||
)
|
||||
|
||||
target_vers = get_possible_target_versions(update_url)
|
||||
|
||||
if environ.get("UPLOAD_DIR"):
|
||||
version_info_log = Path(
|
||||
environ.get("UPLOAD_DIR"), environ.get("VERSION_LOG_FILENAME")
|
||||
)
|
||||
if version_info_log.is_file():
|
||||
with version_info_log.open("a") as fh:
|
||||
fh.write(f"Target version options: {', '.join(target_vers)}\n")
|
||||
|
||||
# Wait for the background update to be ready by checking for popup
|
||||
# Long timeouts are a known issue - Bug 2000040
|
||||
Wait(self.marionette, timeout=100).until(
|
||||
lambda _: self.marionette.find_elements(By.ID, "appMenu-notification-popup")
|
||||
)
|
||||
|
||||
# Try runs build unsigned updates, releases can't update on unsigned MARs
|
||||
# ...so we're just going to check that balrog gives a reasonably-named file that exists
|
||||
# We run the code here to maximize what gets run in try.
|
||||
if environ.get("BALROG_STAGING"):
|
||||
root = get_update_server_response(update_url, 1)
|
||||
patch_url = root[0][0].get("URL")
|
||||
assert (
|
||||
f"/{target_vers[-1]}esr-candidates" in patch_url
|
||||
), f'"/{target_vers[-1]}esr-candidates not in patch url: {patch_url}'
|
||||
patch_response = requests.get(patch_url)
|
||||
patch_response.raise_for_status()
|
||||
return True
|
||||
|
||||
# Dismiss the popup
|
||||
self.marionette.find_element(By.ID, "urlbar-input").click()
|
||||
self.marionette.find_element(By.ID, "PanelUI-menu-button").click()
|
||||
self.marionette.find_element(By.ID, "urlbar-input").click()
|
||||
self.marionette.find_element(By.ID, "PanelUI-menu-button").click()
|
||||
|
||||
# Check that there is a green badge on hamburger menu
|
||||
Wait(self.marionette, timeout=100).until(
|
||||
lambda _: self.marionette.find_element(
|
||||
By.ID, "PanelUI-menu-button"
|
||||
).get_attribute("badge-status")
|
||||
== "update-available"
|
||||
)
|
||||
|
||||
# Click the update button in hamburger menu to download the update
|
||||
self.marionette.find_element(By.ID, "PanelUI-menu-button").click()
|
||||
self.marionette.find_element(By.ID, "appMenu-update-banner").click()
|
||||
|
||||
# Make sure that the download is finished
|
||||
self.marionette.set_context(self.marionette.CONTEXT_CONTENT)
|
||||
Wait(self.marionette, timeout=200).until(
|
||||
expected.element_displayed(By.ID, "updateButton")
|
||||
)
|
||||
initial_ver = self.marionette.find_element(By.ID, "version").text
|
||||
|
||||
# Restart normally
|
||||
self.marionette.restart()
|
||||
|
||||
self.marionette.set_pref("app.update.disabledForTesting", False)
|
||||
self.marionette.set_pref("remote.system-access-check.enabled", False)
|
||||
self.marionette.set_pref("app.update.log", True)
|
||||
self.marionette.set_pref("remote.log.level", "Trace")
|
||||
self.marionette.navigate(self.about_fx_url)
|
||||
Wait(self.marionette, timeout=100).until(
|
||||
expected.element_displayed(By.ID, "version")
|
||||
)
|
||||
|
||||
# Mini smoke test
|
||||
target_ver_verified = False
|
||||
version_text = self.marionette.find_element(By.ID, "version").text
|
||||
for target_ver in target_vers:
|
||||
if target_ver in version_text:
|
||||
target_ver_verified = True
|
||||
try:
|
||||
print(f"Updated from {initial_ver} to {target_ver}")
|
||||
except UnicodeEncodeError:
|
||||
print(f"Updated to {target_ver}")
|
||||
assert target_ver_verified
|
||||
assert len(self.marionette.window_handles) == 1
|
||||
self.marionette.open("tab")
|
||||
Wait(self.marionette, timeout=20).until(
|
||||
lambda _: len(self.marionette.window_handles) == 2
|
||||
)
|
||||
self.marionette.close()
|
||||
Wait(self.marionette, timeout=20).until(
|
||||
lambda _: len(self.marionette.window_handles) == 1
|
||||
)
|
||||
|
||||
def tearDown(self):
|
||||
MarionetteTestCase.tearDown(self)
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
[replaceState-inside-back-handler-infinite.optional.html]
|
||||
expected: TIMEOUT
|
||||
bug: 2013022
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
[activation-reload.html]
|
||||
disabled:
|
||||
if os == "mac": https://bugzilla.mozilla.org/show_bug.cgi?id=1971005
|
||||
expected:
|
||||
if os == "mac": [ERROR, CRASH]
|
||||
CRASH
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
<!doctype html>
|
||||
<title>Variable substitution with missing closing parenthesis</title>
|
||||
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=2013337">
|
||||
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
|
||||
<link rel="author" title="Mozilla" href="https://mozilla.com">
|
||||
<div
|
||||
style="box-shadow:0px 0px 3px 1px var(--token-62be83f1-0097-4872-b224-94c7b2aa11d6, nullpx nullpx nullpx nullpx rgb(245, 245, 245), 0px 0px 4px 2px var(--token-63fea906-5b5e-4ed0-9785-37e4c202cb5f, nullpx nullpx nullpx undefinedpx rgb(1, 255, 148)"
|
||||
></div>
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<!doctype html>
|
||||
<title>Variable substitution with missing closing parenthesis</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=2013337">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-variables/">
|
||||
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
|
||||
<link rel="author" title="Mozilla" href="https://mozilla.com">
|
||||
<div
|
||||
style="box-shadow:var(--token-62be83f1-0097-4872-b224-94c7b2aa11d6, 10px 10px 10px 10px rgb(245, 245, 245), 0px 0px 4px 2px var(--token-63fea906-5b5e-4ed0-9785-37e4c202cb5f, rgb(1, 255, 148)"
|
||||
></div>
|
||||
<script>
|
||||
test(function() {
|
||||
assert_equals(
|
||||
getComputedStyle(document.querySelector("div")).boxShadow,
|
||||
"rgb(245, 245, 245) 10px 10px 10px 10px, rgb(1, 255, 148) 0px 0px 4px 2px",
|
||||
"Should substitute correctly"
|
||||
);
|
||||
});
|
||||
</script>
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
<script>
|
||||
test(function () {
|
||||
assert_throws_dom("SecurityError", function () {
|
||||
for (let i = 0; i < 500; i++) {
|
||||
for (let i = 0; i < 5000; i++) {
|
||||
window.history.pushState(null, null, i);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
<script>
|
||||
test(function () {
|
||||
assert_throws_dom("SecurityError", function () {
|
||||
for (let i = 0; i < 500; i++) {
|
||||
for (let i = 0; i < 5000; i++) {
|
||||
window.history.replaceState(null, null, i);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3,13 +3,14 @@ import pytest
|
|||
URL = "https://f1tv.formula1.com/"
|
||||
|
||||
SUPPORTED_TEXT = "Watch now"
|
||||
UNSUPPORTED_TEXT = "Unsupported Browser"
|
||||
UNSUPPORTED_TEXT = "browser is not supported"
|
||||
USE_APP_TEXT = "Use F1 TV App"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.with_interventions
|
||||
async def test_enabled(client):
|
||||
await client.navigate(URL)
|
||||
await client.navigate(URL, wait="none")
|
||||
assert client.await_text(SUPPORTED_TEXT, is_displayed=True)
|
||||
assert not client.find_text(UNSUPPORTED_TEXT, is_displayed=True)
|
||||
|
||||
|
|
@ -17,6 +18,13 @@ async def test_enabled(client):
|
|||
@pytest.mark.asyncio
|
||||
@pytest.mark.without_interventions
|
||||
async def test_disabled(client):
|
||||
await client.navigate(URL)
|
||||
assert client.await_text(UNSUPPORTED_TEXT, is_displayed=True)
|
||||
await client.navigate(URL, wait="none")
|
||||
use_app, unsupported = client.await_first_element_of(
|
||||
[
|
||||
client.text(USE_APP_TEXT),
|
||||
client.text(UNSUPPORTED_TEXT),
|
||||
],
|
||||
is_displayed=True,
|
||||
)
|
||||
assert use_app or unsupported
|
||||
assert not client.find_text(SUPPORTED_TEXT, is_displayed=True)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue