1
0
Fork 0
firefox/testing/update/mach_commands.py
Daniel Baumann 5e9a113729
Adding upstream version 140.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-25 09:37:52 +02:00

207 lines
6.6 KiB
Python

# This Source Code Form is subject to the terms of the Mozilla Public
# 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 logging
import sys
import tempfile
from pathlib import Path
from platform import uname
from shutil import copytree, unpack_archive
import mozinstall
import requests
from mach.decorators import Command, CommandArgument
from mozbuild.base import BinaryNotFoundException
from mozlog.structured import commandline
TEST_UPDATE_CHANNEL = "release-localtest"
if TEST_UPDATE_CHANNEL.startswith("release"):
MAR_CHANNEL = "firefox-mozilla-release"
elif TEST_UPDATE_CHANNEL.startswith("beta"):
MAR_CHANNEL = "firefox-mozilla-beta"
else:
MAR_CHANNEL = "firefox-mozilla-central"
TEST_REGION = "en-US"
TEST_SOURCE_VERSION = "135.0.1"
FX_DOWNLOAD_DIR_URL = "https://archive.mozilla.org/pub/firefox/releases/"
APP_DIR_NAME = "fx_test"
def setup_update_argument_parser():
from marionette_harness.runtests import MarionetteArguments
from mozlog.structured import commandline
parser = MarionetteArguments()
commandline.add_logging_group(parser)
return parser
def get_fx_executable_name(version):
u = uname()
if u.system == "Darwin":
platform = "mac"
executable_name = f"Firefox {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:
executable_name = f"firefox-{version}.tar.bz2"
else:
executable_name = f"firefox-{version}.tar.xz"
if u.system == "Windows":
if u.machine == "ARM64":
platform = "win64-aarch64"
elif "64" in u.machine:
platform = "win64"
else:
platform = "win32"
executable_name = f"Firefox Setup {version}.exe"
return platform, executable_name.replace(" ", "%20")
def get_binary_path(tempdir, **kwargs) -> str:
# Install correct Fx and return executable location
platform, executable_name = get_fx_executable_name(TEST_SOURCE_VERSION)
executable_url = rf"{FX_DOWNLOAD_DIR_URL}{TEST_SOURCE_VERSION}/{platform}/{TEST_REGION}/{executable_name}"
installer_filename = Path(tempdir, Path(executable_url).name)
installed_app_dir = Path(tempdir, 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:
fh.write(response.content)
fx_location = mozinstall.install(installer_filename, installed_app_dir)
print(f"Firefox installed to {fx_location}")
return fx_location
@Command(
"update-test",
category="testing",
virtualenv_name="update",
description="Test if the version can be updated to the latest patch successfully,",
parser=setup_update_argument_parser,
)
@CommandArgument("--binary_path", help="Firefox executable path is needed")
def build(command_context, binary_path, **kwargs):
tempdir = tempfile.TemporaryDirectory()
# If we have a symlink to the tmp directory, resolve it
tempdir_name = str(Path(tempdir.name).resolve())
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
)
except BinaryNotFoundException as e:
command_context.log(
logging.ERROR,
"update-test",
{"error": str(e)},
"ERROR: {error}",
)
command_context.log(logging.INFO, "update-test", {"help": e.help()}, "{help}")
return 1
finally:
tempdir.cleanup()
def run_tests(binary=None, topsrcdir=None, tempdir=None, **kwargs):
from argparse import Namespace
from marionette_harness.runtests import MarionetteHarness, MarionetteTestRunner
args = Namespace()
args.binary = binary
args.logger = kwargs.pop("log", None)
if not args.logger:
args.logger = commandline.setup_logging(
"Update Tests", args, {"mach": sys.stdout}
)
for k, v in kwargs.items():
setattr(args, k, v)
args.tests = [
Path(
topsrcdir,
"testing/update/manifest.toml",
)
]
args.gecko_log = "-"
parser = setup_update_argument_parser()
parser.verify_usage(args)
failed = MarionetteHarness(MarionetteTestRunner, args=vars(args)).run()
if failed > 0:
return 1
return 0
def copy_macos_channelprefs(tempdir) -> 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)
bz_channelprefs_link = "https://bugzilla.mozilla.org/attachment.cgi?id=9417387"
resp = requests.get(bz_channelprefs_link)
download_target = Path(tempdir, "channelprefs.zip")
unpack_target = str(download_target).rsplit(".", 1)[0]
with open(download_target, "wb") as fh:
fh.write(resp.content)
unpack_archive(download_target, unpack_target)
print(
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")
Path(installed_app_dir, "Firefox.app").chmod(455) # rwx for all users
print(f"Copying ChannelPrefs.framework from {src} to {dst}")
copytree(
Path(src, "ChannelPrefs.framework"),
Path(dst, "ChannelPrefs.framework"),
dirs_exist_ok=True,
)
# test against the binary that was copied to local
fx_executable = Path(
installed_app_dir, "Firefox.app", "Contents", "MacOS", "firefox"
)
return str(fx_executable)
def set_up(binary_path, tempdir):
# Set channel prefs for all OS targets
binary_path_str = mozinstall.get_binary(binary_path, "Firefox")
print(f"Binary path: {binary_path_str}")
binary_dir = Path(binary_path_str).absolute().parent
if uname().system == "Darwin":
return copy_macos_channelprefs(tempdir)
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}")
with Path(binary_dir, "defaults", "pref", "channel-prefs.js").open("w") as f:
f.write(f'pref("app.update.channel", "{TEST_UPDATE_CHANNEL}");')
return binary_path_str