207 lines
6.6 KiB
Python
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
|