mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-27 23:02:20 +00:00
Bug 1619198 - add mach commands for condprofs r=Bebe
Refactored condprof so we can drive it with mach Differential Revision: https://phabricator.services.mozilla.com/D64962 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
c8f4578a7f
commit
0165728187
@ -58,6 +58,7 @@ MACH_MODULES = [
|
||||
'remote/mach_commands.py',
|
||||
'taskcluster/mach_commands.py',
|
||||
'testing/awsy/mach_commands.py',
|
||||
'testing/condprofile/mach_commands.py',
|
||||
'testing/firefox-ui/mach_commands.py',
|
||||
'testing/geckodriver/mach_commands.py',
|
||||
'testing/mach_commands.py',
|
||||
|
@ -52,7 +52,7 @@ jobs:
|
||||
using: run-task
|
||||
command: >-
|
||||
cd %CONDPROF_ROOT% &&
|
||||
python3.exe condprof/runner.py --geckodriver z:/%USERNAME%/fetches/bin/geckodriver.exe --firefox firefox/firefox.exe z:/%USERNAME%/archive
|
||||
python3.exe condprof/main.py --geckodriver z:/%USERNAME%/fetches/bin/geckodriver.exe --firefox firefox/firefox.exe z:/%USERNAME%/archive
|
||||
worker:
|
||||
artifacts:
|
||||
- name: public/condprof
|
||||
@ -80,7 +80,7 @@ jobs:
|
||||
$CONDPROF_ROOT/virtualenv/virtualenv.py -p python3.7 $CONDPROF_ROOT &&
|
||||
cd $CONDPROF_ROOT &&
|
||||
export PATH="$PATH:$MOZ_FETCHES_DIR/bin" &&
|
||||
bin/python3.7 condprof/runner.py --firefox $MOZ_FETCHES_DIR/firefox/firefox-bin $CONDPROF_ARCHIVES
|
||||
bin/python3.7 condprof/main.py --firefox $MOZ_FETCHES_DIR/firefox/firefox-bin $CONDPROF_ARCHIVES
|
||||
worker:
|
||||
docker-image: {in-tree: condprof}
|
||||
artifacts:
|
||||
@ -109,7 +109,7 @@ jobs:
|
||||
$CONDPROF_ROOT/virtualenv/virtualenv.py -p python3 $CONDPROF_ROOT &&
|
||||
export PATH="$PATH:$MOZ_FETCHES_DIR/bin" &&
|
||||
cd $CONDPROF_ROOT &&
|
||||
bin/python3 condprof/runner.py --firefox $MOZ_FETCHES_DIR/target.dmg ../../archive
|
||||
bin/python3 condprof/main.py --firefox $MOZ_FETCHES_DIR/target.dmg ../../archive
|
||||
worker:
|
||||
artifacts:
|
||||
- name: public/condprof
|
||||
@ -141,7 +141,7 @@ jobs:
|
||||
$CONDPROF_ROOT/virtualenv/virtualenv.py -p python3 $CONDPROF_ROOT &&
|
||||
cd $CONDPROF_ROOT &&
|
||||
export PATH="$PATH:$MOZ_FETCHES_DIR/bin" &&
|
||||
bin/python3 condprof/runner.py --device-name g5 --firefox org.mozilla.geckoview_example ../../archive
|
||||
bin/python3 condprof/main.py --device-name g5 --firefox org.mozilla.geckoview_example ../../archive
|
||||
worker:
|
||||
artifacts:
|
||||
- name: public/condprof
|
||||
@ -171,7 +171,7 @@ jobs:
|
||||
$CONDPROF_ROOT/virtualenv/virtualenv.py -p python3 $CONDPROF_ROOT &&
|
||||
cd $CONDPROF_ROOT &&
|
||||
export PATH="$PATH:$MOZ_FETCHES_DIR/bin" &&
|
||||
bin/python3 condprof/runner.py --device-name g5 --firefox org.mozilla.fenix.performancetest ../../archive
|
||||
bin/python3 condprof/main.py --device-name g5 --firefox org.mozilla.fenix.performancetest ../../archive
|
||||
worker:
|
||||
artifacts:
|
||||
- name: public/condprof
|
||||
@ -201,7 +201,7 @@ jobs:
|
||||
$CONDPROF_ROOT/virtualenv/virtualenv.py -p python3 $CONDPROF_ROOT &&
|
||||
cd $CONDPROF_ROOT &&
|
||||
export PATH="$PATH:$MOZ_FETCHES_DIR/bin" &&
|
||||
bin/python3 condprof/runner.py --device-name p2_aarch64 --firefox org.mozilla.fenix.performancetest ../../archive
|
||||
bin/python3 condprof/main.py --device-name p2_aarch64 --firefox org.mozilla.fenix.performancetest ../../archive
|
||||
worker:
|
||||
artifacts:
|
||||
- name: public/condprof
|
||||
@ -233,7 +233,7 @@ jobs:
|
||||
$CONDPROF_ROOT/virtualenv/virtualenv.py -p python3 $CONDPROF_ROOT &&
|
||||
cd $CONDPROF_ROOT &&
|
||||
export PATH="$PATH:$MOZ_FETCHES_DIR/bin" &&
|
||||
bin/python3 condprof/runner.py --device-name p2_aarch64 --firefox org.mozilla.geckoview_example ../../archive
|
||||
bin/python3 condprof/main.py --device-name p2_aarch64 --firefox org.mozilla.geckoview_example ../../archive
|
||||
worker:
|
||||
artifacts:
|
||||
- name: public/condprof
|
||||
@ -263,7 +263,7 @@ jobs:
|
||||
$CONDPROF_ROOT/virtualenv/virtualenv.py -p python3 $CONDPROF_ROOT &&
|
||||
cd $CONDPROF_ROOT &&
|
||||
export PATH="$PATH:$MOZ_FETCHES_DIR/bin" &&
|
||||
bin/python3 condprof/runner.py --device-name p2_aarch64 --firefox org.mozilla.fennec_aurora ../../archive
|
||||
bin/python3 condprof/main.py --device-name p2_aarch64 --firefox org.mozilla.fennec_aurora ../../archive
|
||||
worker:
|
||||
artifacts:
|
||||
- name: public/condprof
|
||||
|
@ -29,17 +29,52 @@ For each combination of scenario, customization and platform:
|
||||
|
||||
It's based on the Arsenic webdriver client https://github.com/HDE/arsenic
|
||||
|
||||
A client that wants to use a profile can download it from the indexed artifacts
|
||||
by using a simple HTTP client or the provided client in **condprof.client**.
|
||||
The project provides two **Mach** commands to interact with the conditioned
|
||||
profile:
|
||||
|
||||
- **fetch-condprofile**: downloads a conditioned profile and deecompress it
|
||||
- **run-condprofile**: runs on or all conditioned profiles scenarii locally
|
||||
|
||||
Scenario
|
||||
========
|
||||
How to download a conditioned profile
|
||||
=====================================
|
||||
|
||||
From your mozilla-central root, run:
|
||||
|
||||
::
|
||||
|
||||
$ ./mach fetch-condprofile
|
||||
|
||||
This will grab the latest conditioned profile for your platform. But
|
||||
you can also grab a specific profile built from any scenario or platform.
|
||||
|
||||
You can look at all the options with --help
|
||||
|
||||
How to run a conditioned profile
|
||||
================================
|
||||
|
||||
If you want to play a scenario locally to modify it, run for example:
|
||||
|
||||
::
|
||||
|
||||
$ ./mach run-condprofile --scenario settled --visible /path/to/generated/profile
|
||||
|
||||
The project will run a webdriver session against Firefox and generate the profile.
|
||||
You can look at all the options with --help
|
||||
|
||||
Architecture
|
||||
============
|
||||
|
||||
The conditioned profile project is organized into webdriver **scenarii** and
|
||||
**customization** files.
|
||||
|
||||
Scenarii
|
||||
--------
|
||||
|
||||
Scenarii are coroutines registered under a unique name in condprof/scenarii/__init__.py.
|
||||
|
||||
Scenarii are coroutines registered under a unique name in condprof/scenarii.
|
||||
They get a **session** object and some **options**.
|
||||
|
||||
The scenario can do whatever it wants with the browser, through the session
|
||||
The scenario can do whatever it wants with the browser, through the webdriver session
|
||||
instance.
|
||||
|
||||
See Arsenic's `API documentation <https://arsenic.readthedocs.io/en/latest/reference/session.html>`_ for the session class.
|
||||
@ -49,7 +84,7 @@ and register it in condprof/scenarii/__init__.py
|
||||
|
||||
|
||||
Customization
|
||||
=============
|
||||
-------------
|
||||
|
||||
A customization is a configuration file that can be used to set some
|
||||
prefs in the browser and install some webextensions.
|
||||
@ -78,34 +113,3 @@ In the example below, we install uBlock, set a pref, and pass the
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Getting conditioned profiles
|
||||
============================
|
||||
|
||||
Unlike the profile creator, the client is Python 2 and 3 compatible.
|
||||
|
||||
You can grab a conditioned profile using the client API::
|
||||
|
||||
>>> from condprof.client import get_profile
|
||||
>>> get_profile(".", "win64", "settled", "default")
|
||||
|
||||
or the **cp-client** script that gets install when you run the
|
||||
conditioned profile installer.
|
||||
|
||||
Running locally
|
||||
===============
|
||||
|
||||
Unfortunately, we can't hook the conditioned profile builder into mach
|
||||
at this point. We need to wait for everything in the tree to be fully
|
||||
Python 3 compatible.
|
||||
|
||||
Until then, if you want to build profiles locally, to try out one
|
||||
of your scenario for instance, you can install a local Python 3
|
||||
virtual env and use the script from there.
|
||||
|
||||
Get a mozilla-central source clone and do the following::
|
||||
|
||||
$ cd testing/condprofile
|
||||
$ virtualenv .
|
||||
|
||||
From there you can trigger profiles creation using **bin/cp-creator**.
|
||||
|
@ -60,29 +60,41 @@ def install_reqs():
|
||||
|
||||
return False
|
||||
except Exception:
|
||||
if not os.path.exists(os.path.join(TOPDIR, "mozfile")):
|
||||
req_file = PY3 and "local-requirements.txt" or "local-py2-requirements.txt"
|
||||
# we're detecting here that this is running in Taskcluster
|
||||
# by checking for the presence of the mozfile directory
|
||||
# that was decompressed from target.condprof.tests.tar.gz
|
||||
run_in_ci = os.path.exists(os.path.join(TOPDIR, "mozfile"))
|
||||
|
||||
# On Python 2 we only install what's required for condprof.client
|
||||
# On Python 3 it's the full thing
|
||||
if not run_in_ci:
|
||||
req_files = PY3 and ["base.txt", "local.txt"] or ["local-client.txt"]
|
||||
else:
|
||||
req_file = PY3 and "requirements.txt" or "py2-requirements.txt"
|
||||
req_files = PY3 and ["base.txt", "ci.txt"] or ["ci-client.txt"]
|
||||
|
||||
req_file = os.path.join(TOPDIR, req_file)
|
||||
for req_file in req_files:
|
||||
req_file = os.path.join(TOPDIR, "requirements", req_file)
|
||||
|
||||
with open(req_file) as f:
|
||||
reqs = [req for req in f.read().split("\n") if req.strip() != ""]
|
||||
for req in reqs:
|
||||
subprocess.check_call(
|
||||
[
|
||||
sys.executable,
|
||||
"-m",
|
||||
"pip",
|
||||
"install",
|
||||
"--no-cache-dir",
|
||||
"--isolated",
|
||||
"--find-links",
|
||||
"https://pypi.pub.build.mozilla.org/pub",
|
||||
req,
|
||||
]
|
||||
)
|
||||
with open(req_file) as f:
|
||||
reqs = [
|
||||
req
|
||||
for req in f.read().split("\n")
|
||||
if req.strip() != "" and not req.startswith("#")
|
||||
]
|
||||
for req in reqs:
|
||||
subprocess.check_call(
|
||||
[
|
||||
sys.executable,
|
||||
"-m",
|
||||
"pip",
|
||||
"install",
|
||||
"--no-cache-dir",
|
||||
"--isolated",
|
||||
"--find-links",
|
||||
"https://pypi.pub.build.mozilla.org/pub",
|
||||
req,
|
||||
]
|
||||
)
|
||||
|
||||
return True
|
||||
|
||||
|
@ -138,17 +138,3 @@ def read_changelog(platform, repo="mozilla-central"):
|
||||
shutil.rmtree(download_dir)
|
||||
raise ProfileNotFoundError(changelog_url)
|
||||
return Changelog(download_dir)
|
||||
|
||||
|
||||
def main():
|
||||
# XXX demo. download an older version of a profile, given a task id
|
||||
# plat = get_current_platform()
|
||||
older_change = read_changelog("win64").history()[0]
|
||||
task_id = older_change["TASK_ID"]
|
||||
target_dir = tempfile.mkdtemp()
|
||||
filename = get_profile(target_dir, "win64", "settled", "default", task_id)
|
||||
print("Profile downloaded and extracted at %s" % filename)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
77
testing/condprofile/condprof/main.py
Normal file
77
testing/condprofile/condprof/main.py
Normal file
@ -0,0 +1,77 @@
|
||||
# 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/.
|
||||
""" Script that launches profiles creation.
|
||||
"""
|
||||
import os
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
# easier than setting PYTHONPATH in various platforms
|
||||
if __name__ == "__main__":
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), ".."))
|
||||
|
||||
from condprof.check_install import check # NOQA
|
||||
|
||||
if "MANUAL_MACH_RUN" not in os.environ:
|
||||
check()
|
||||
|
||||
from condprof.runner import run # NOQA
|
||||
|
||||
|
||||
def main(args=sys.argv[1:]):
|
||||
parser = argparse.ArgumentParser(description="Profile Creator")
|
||||
parser.add_argument("archive", help="Archives Dir", type=str, default=None)
|
||||
parser.add_argument("--firefox", help="Firefox Binary", type=str, default=None)
|
||||
parser.add_argument("--scenario", help="Scenario to use", type=str, default="all")
|
||||
parser.add_argument(
|
||||
"--profile", help="Existing profile Dir", type=str, default=None
|
||||
)
|
||||
parser.add_argument(
|
||||
"--customization", help="Profile customization to use", type=str, default="all"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--visible", help="Don't use headless mode", action="store_true", default=False
|
||||
)
|
||||
parser.add_argument(
|
||||
"--archives-dir", help="Archives local dir", type=str, default="/tmp/archives"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--force-new", help="Create from scratch", action="store_true", default=False
|
||||
)
|
||||
parser.add_argument(
|
||||
"--strict",
|
||||
help="Errors out immediatly on a scenario failure",
|
||||
action="store_true",
|
||||
default=True,
|
||||
)
|
||||
parser.add_argument(
|
||||
"--geckodriver",
|
||||
help="Path to the geckodriver binary",
|
||||
type=str,
|
||||
default=sys.platform.startswith("win") and "geckodriver.exe" or "geckodriver",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--device-name", help="Name of the device", type=str, default=None
|
||||
)
|
||||
|
||||
args = parser.parse_args(args=args)
|
||||
|
||||
run(
|
||||
args.archive,
|
||||
args.firefox,
|
||||
args.scenario,
|
||||
args.profile,
|
||||
args.customization,
|
||||
args.visible,
|
||||
args.archives_dir,
|
||||
args.force_new,
|
||||
args.strict,
|
||||
args.geckodriver,
|
||||
args.device_name,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -4,155 +4,145 @@
|
||||
""" Script that launches profiles creation.
|
||||
"""
|
||||
import os
|
||||
import argparse
|
||||
import asyncio
|
||||
import sys
|
||||
import shutil
|
||||
import asyncio
|
||||
|
||||
# easier than setting PYTHONPATH in various platforms
|
||||
if __name__ == "__main__":
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), ".."))
|
||||
|
||||
from condprof.check_install import check # NOQA
|
||||
|
||||
check() # NOQA
|
||||
|
||||
from condprof.creator import ProfileCreator # NOQA
|
||||
from condprof.desktop import DesktopEnv # NOQA
|
||||
from condprof.android import AndroidEnv # NOQA
|
||||
from condprof.changelog import Changelog # NOQA
|
||||
from condprof.scenarii import scenarii # NOQA
|
||||
from condprof.creator import ProfileCreator
|
||||
from condprof.desktop import DesktopEnv
|
||||
from condprof.android import AndroidEnv
|
||||
from condprof.changelog import Changelog
|
||||
from condprof.scenarii import scenarii
|
||||
from condprof.util import (
|
||||
logger,
|
||||
get_version,
|
||||
get_current_platform,
|
||||
extract_from_dmg,
|
||||
) # NOQA
|
||||
from condprof.customization import get_customizations, find_customization # NOQA
|
||||
from condprof.client import read_changelog, ProfileNotFoundError # NOQA
|
||||
)
|
||||
from condprof.customization import get_customizations, find_customization
|
||||
from condprof.client import read_changelog, ProfileNotFoundError
|
||||
|
||||
|
||||
def main(args=sys.argv[1:]):
|
||||
parser = argparse.ArgumentParser(description="Profile Creator")
|
||||
parser.add_argument("archive", help="Archives Dir", type=str, default=None)
|
||||
parser.add_argument("--firefox", help="Firefox Binary", type=str, default=None)
|
||||
parser.add_argument("--scenario", help="Scenario to use", type=str, default="all")
|
||||
parser.add_argument(
|
||||
"--profile", help="Existing profile Dir", type=str, default=None
|
||||
)
|
||||
parser.add_argument(
|
||||
"--customization", help="Profile customization to use", type=str, default="all"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--visible", help="Don't use headless mode", action="store_true", default=False
|
||||
)
|
||||
parser.add_argument(
|
||||
"--archives-dir", help="Archives local dir", type=str, default="/tmp/archives"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--force-new", help="Create from scratch", action="store_true", default=False
|
||||
)
|
||||
parser.add_argument(
|
||||
"--strict",
|
||||
help="Errors out immediatly on a scenario failure",
|
||||
action="store_true",
|
||||
default=True,
|
||||
)
|
||||
parser.add_argument(
|
||||
"--geckodriver",
|
||||
help="Path to the geckodriver binary",
|
||||
type=str,
|
||||
default=sys.platform.startswith("win") and "geckodriver.exe" or "geckodriver",
|
||||
)
|
||||
class Runner:
|
||||
def __init__(
|
||||
self,
|
||||
profile,
|
||||
firefox,
|
||||
geckodriver,
|
||||
archive,
|
||||
device_name,
|
||||
strict,
|
||||
force_new,
|
||||
visible,
|
||||
):
|
||||
self.force_new = force_new
|
||||
self.profile = profile
|
||||
self.geckodriver = geckodriver
|
||||
self.archive = archive
|
||||
self.device_name = device_name
|
||||
self.strict = strict
|
||||
self.visible = visible
|
||||
# unpacking a dmg
|
||||
# XXX do something similar if we get an apk (but later)
|
||||
# XXX we want to do
|
||||
# adb install -r target.apk
|
||||
# and get the installed app name
|
||||
if firefox is not None and firefox.endswith("dmg"):
|
||||
target = os.path.join(os.path.dirname(firefox), "firefox.app")
|
||||
extract_from_dmg(firefox, target)
|
||||
firefox = os.path.join(target, "Contents", "MacOS", "firefox")
|
||||
self.firefox = firefox
|
||||
self.android = self.firefox is not None and self.firefox.startswith(
|
||||
"org.mozilla"
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--device-name", help="Name of the device", type=str, default=None
|
||||
)
|
||||
def prepare(self, scenario, customization):
|
||||
self.scenario = scenario
|
||||
self.customization = customization
|
||||
|
||||
args = parser.parse_args(args=args)
|
||||
# early checks to avoid extra work
|
||||
if self.customization != "all":
|
||||
if find_customization(self.customization) is None:
|
||||
raise IOError("Cannot find customization %r" % self.customization)
|
||||
|
||||
# unpacking a dmg
|
||||
# XXX do something similar if we get an apk (but later)
|
||||
# XXX we want to do
|
||||
# adb install -r target.apk
|
||||
# and get the installed app name
|
||||
if args.firefox is not None and args.firefox.endswith("dmg"):
|
||||
target = os.path.join(os.path.dirname(args.firefox), "firefox.app")
|
||||
extract_from_dmg(args.firefox, target)
|
||||
args.firefox = os.path.join(target, "Contents", "MacOS", "firefox")
|
||||
if self.scenario != "all" and self.scenario not in scenarii:
|
||||
raise IOError("Cannot find scenario %r" % self.scenario)
|
||||
|
||||
args.android = args.firefox is not None and args.firefox.startswith("org.mozilla")
|
||||
if not self.android and self.firefox is not None:
|
||||
logger.info("Verifying Desktop Firefox binary")
|
||||
# we want to verify we do have a firefox binary
|
||||
# XXX so lame
|
||||
if not os.path.exists(self.firefox):
|
||||
if "MOZ_FETCHES_DIR" in os.environ:
|
||||
target = os.path.join(os.environ["MOZ_FETCHES_DIR"], self.firefox)
|
||||
if os.path.exists(target):
|
||||
self.firefox = target
|
||||
|
||||
# early checks to avoid extra work
|
||||
if args.customization != "all":
|
||||
if find_customization(args.customization) is None:
|
||||
raise IOError("Cannot find customization %r" % args.customization)
|
||||
if not os.path.exists(self.firefox):
|
||||
raise IOError("Cannot find %s" % self.firefox)
|
||||
|
||||
if args.scenario != "all" and args.scenario not in scenarii:
|
||||
raise IOError("Cannot find scenario %r" % args.scenario)
|
||||
version = get_version(self.firefox)
|
||||
logger.info("Working with Firefox %s" % version)
|
||||
|
||||
if not args.android and args.firefox is not None:
|
||||
logger.info("Verifying Desktop Firefox binary")
|
||||
# we want to verify we do have a firefox binary
|
||||
# XXX so lame
|
||||
if not os.path.exists(args.firefox):
|
||||
if "MOZ_FETCHES_DIR" in os.environ:
|
||||
target = os.path.join(os.environ["MOZ_FETCHES_DIR"], args.firefox)
|
||||
if os.path.exists(target):
|
||||
args.firefox = target
|
||||
logger.info(os.environ)
|
||||
self.archive = os.path.abspath(self.archive)
|
||||
logger.info("Archives directory is %s" % self.archive)
|
||||
if not os.path.exists(self.archive):
|
||||
os.makedirs(self.archive, exist_ok=True)
|
||||
|
||||
if not os.path.exists(args.firefox):
|
||||
raise IOError("Cannot find %s" % args.firefox)
|
||||
logger.info("Verifying Geckodriver binary presence")
|
||||
if shutil.which(self.geckodriver) is None and not os.path.exists(
|
||||
self.geckodriver
|
||||
):
|
||||
raise IOError("Cannot find %s" % self.geckodriver)
|
||||
|
||||
version = get_version(args.firefox)
|
||||
logger.info("Working with Firefox %s" % version)
|
||||
try:
|
||||
if self.android:
|
||||
plat = "%s-%s" % (
|
||||
self.device_name,
|
||||
self.firefox.split("org.mozilla.")[-1],
|
||||
)
|
||||
else:
|
||||
plat = get_current_platform()
|
||||
self.changelog = read_changelog(plat)
|
||||
logger.info("Got the changelog from TaskCluster")
|
||||
except ProfileNotFoundError:
|
||||
logger.info("changelog not found on TaskCluster, creating a local one.")
|
||||
self.changelog = Changelog(self.archive)
|
||||
|
||||
logger.info(os.environ)
|
||||
args.archive = os.path.abspath(args.archive)
|
||||
logger.info("Archives directory is %s" % args.archive)
|
||||
if not os.path.exists(args.archive):
|
||||
os.makedirs(args.archive, exist_ok=True)
|
||||
|
||||
logger.info("Verifying Geckodriver binary presence")
|
||||
if shutil.which(args.geckodriver) is None and not os.path.exists(args.geckodriver):
|
||||
raise IOError("Cannot find %s" % args.geckodriver)
|
||||
|
||||
try:
|
||||
if args.android:
|
||||
plat = "%s-%s" % (args.device_name, args.firefox.split("org.mozilla.")[-1])
|
||||
def _create_env(self):
|
||||
if self.android:
|
||||
klass = AndroidEnv
|
||||
else:
|
||||
plat = get_current_platform()
|
||||
changelog = read_changelog(plat)
|
||||
logger.info("Got the changelog from TaskCluster")
|
||||
except ProfileNotFoundError:
|
||||
logger.info("changelog not found on TaskCluster, creating a local one.")
|
||||
changelog = Changelog(args.archive)
|
||||
loop = asyncio.get_event_loop()
|
||||
klass = DesktopEnv
|
||||
|
||||
async def one_run(scenario, customization):
|
||||
if args.android:
|
||||
env = AndroidEnv(
|
||||
args.profile,
|
||||
args.firefox,
|
||||
args.geckodriver,
|
||||
args.archive,
|
||||
args.device_name,
|
||||
)
|
||||
else:
|
||||
env = DesktopEnv(
|
||||
args.profile,
|
||||
args.firefox,
|
||||
args.geckodriver,
|
||||
args.archive,
|
||||
args.device_name,
|
||||
)
|
||||
return klass(
|
||||
self.profile,
|
||||
self.firefox,
|
||||
self.geckodriver,
|
||||
self.archive,
|
||||
self.device_name,
|
||||
)
|
||||
|
||||
def display_error(self, scenario, customization):
|
||||
logger.error("%s x %s failed." % (scenario, customization), exc_info=True)
|
||||
if self.strict:
|
||||
raise
|
||||
|
||||
async def one_run(self, scenario, customization):
|
||||
"""Runs one single conditioned profile.
|
||||
|
||||
Create an instance of the environment and run the ProfileCreator.
|
||||
"""
|
||||
env = self._create_env()
|
||||
return await ProfileCreator(
|
||||
scenario, customization, args.archive, changelog, args.force_new, env
|
||||
).run(not args.visible)
|
||||
scenario, customization, self.archive, self.changelog, self.force_new, env
|
||||
).run(not self.visible)
|
||||
|
||||
async def run_all(args):
|
||||
if args.scenario != "all":
|
||||
selected_scenario = [args.scenario]
|
||||
async def run_all(self):
|
||||
"""Runs the conditioned profile builders
|
||||
"""
|
||||
if self.scenario != "all":
|
||||
selected_scenario = [self.scenario]
|
||||
else:
|
||||
selected_scenario = scenarii.keys()
|
||||
|
||||
@ -160,40 +150,53 @@ def main(args=sys.argv[1:]):
|
||||
# for the current platform when "all" is selected
|
||||
res = []
|
||||
failures = 0
|
||||
|
||||
def display_error(scenario, customization):
|
||||
logger.error("%s x %s failed." % (scenario, customization), exc_info=True)
|
||||
|
||||
for scenario in selected_scenario:
|
||||
if args.customization != "all":
|
||||
if self.customization != "all":
|
||||
try:
|
||||
res.append(await one_run(scenario, args.customization))
|
||||
res.append(await self.one_run(scenario, self.customization))
|
||||
except Exception:
|
||||
failures += 1
|
||||
display_error(scenario, args.customization)
|
||||
if args.strict:
|
||||
raise
|
||||
self.display_error(scenario, self.customization)
|
||||
else:
|
||||
for customization in get_customizations():
|
||||
logger.info("Customization %s" % customization)
|
||||
try:
|
||||
res.append(await one_run(scenario, customization))
|
||||
res.append(await self.one_run(scenario, customization))
|
||||
except Exception:
|
||||
failures += 1
|
||||
display_error(scenario, customization)
|
||||
if args.strict:
|
||||
raise
|
||||
self.display_error(scenario, customization)
|
||||
|
||||
return failures, [one_res for one_res in res if one_res]
|
||||
|
||||
def save(self):
|
||||
self.changelog.save(self.archive)
|
||||
|
||||
|
||||
def run(
|
||||
archive,
|
||||
firefox=None,
|
||||
scenario="all",
|
||||
profile=None,
|
||||
customization="all",
|
||||
visible=False,
|
||||
archives_dir="/tmp/archives",
|
||||
force_new=False,
|
||||
strict=True,
|
||||
geckodriver="geckodriver",
|
||||
device_name=None,
|
||||
):
|
||||
runner = Runner(
|
||||
profile, firefox, geckodriver, archive, device_name, strict, force_new, visible
|
||||
)
|
||||
|
||||
runner.prepare(scenario, customization)
|
||||
loop = asyncio.get_event_loop()
|
||||
|
||||
try:
|
||||
failures, results = loop.run_until_complete(run_all(args))
|
||||
logger.info("Saving changelog in %s" % args.archive)
|
||||
changelog.save(args.archive)
|
||||
failures, results = loop.run_until_complete(runner.run_all())
|
||||
logger.info("Saving changelog in %s" % archive)
|
||||
runner.save()
|
||||
if failures > 0:
|
||||
raise Exception("At least one scenario failed")
|
||||
finally:
|
||||
loop.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
@ -1,9 +0,0 @@
|
||||
../mozbase/mozfile
|
||||
../mozbase/mozprofile
|
||||
../mozbase/mozdevice
|
||||
../mozbase/mozlog
|
||||
|
||||
aiohttp==3.5.4
|
||||
https://pypi.pub.build.mozilla.org/pub/arsenic-19.1-py3-none-any.whl
|
||||
requests==2.22.0
|
||||
pyyaml==5.1.2
|
97
testing/condprofile/mach_commands.py
Normal file
97
testing/condprofile/mach_commands.py
Normal file
@ -0,0 +1,97 @@
|
||||
# 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 sys
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
from mach.decorators import CommandArgument, CommandProvider, Command
|
||||
from mozbuild.base import MachCommandBase
|
||||
|
||||
requirements = os.path.join(os.path.dirname(__file__), "requirements", "base.txt")
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class CondprofileCommandProvider(MachCommandBase):
|
||||
def _init(self):
|
||||
self._activate_virtualenv()
|
||||
self.virtualenv_manager.install_pip_requirements(
|
||||
requirements, require_hashes=False
|
||||
)
|
||||
|
||||
@Command("fetch-condprofile", category="testing")
|
||||
@CommandArgument("--target-dir", default=None, help="Target directory")
|
||||
@CommandArgument("--platform", default=None, help="Platform")
|
||||
@CommandArgument("--scenario", default="full", help="Scenario") # grab choices
|
||||
@CommandArgument("--customization", default="default", help="Customization") # same
|
||||
@CommandArgument("--task-id", default=None, help="Task ID")
|
||||
@CommandArgument("--download-cache", action="store_true", default=True)
|
||||
@CommandArgument(
|
||||
"--repo",
|
||||
default="mozilla-central",
|
||||
choices=["mozilla-central", "try"],
|
||||
help="Repository",
|
||||
)
|
||||
def fetch(
|
||||
self,
|
||||
target_dir,
|
||||
platform,
|
||||
scenario,
|
||||
customization,
|
||||
task_id,
|
||||
download_cache,
|
||||
repo,
|
||||
):
|
||||
self._init()
|
||||
from condprof.client import get_profile
|
||||
from condprof.util import get_current_platform
|
||||
|
||||
if platform is None:
|
||||
platform = get_current_platform()
|
||||
|
||||
if target_dir is None:
|
||||
target_dir = tempfile.mkdtemp()
|
||||
|
||||
get_profile(
|
||||
target_dir, platform, scenario, customization, task_id, download_cache, repo
|
||||
)
|
||||
|
||||
@Command("run-condprofile", category="testing")
|
||||
@CommandArgument("archive", help="Archives Dir", type=str, default=None)
|
||||
@CommandArgument("--firefox", help="Firefox Binary", type=str, default=None)
|
||||
@CommandArgument("--scenario", help="Scenario to use", type=str, default="all")
|
||||
@CommandArgument("--profile", help="Existing profile Dir", type=str, default=None)
|
||||
@CommandArgument(
|
||||
"--customization", help="Profile customization to use", type=str, default="all"
|
||||
)
|
||||
@CommandArgument(
|
||||
"--visible", help="Don't use headless mode", action="store_true", default=False
|
||||
)
|
||||
@CommandArgument(
|
||||
"--archives-dir", help="Archives local dir", type=str, default="/tmp/archives"
|
||||
)
|
||||
@CommandArgument(
|
||||
"--force-new", help="Create from scratch", action="store_true", default=False
|
||||
)
|
||||
@CommandArgument(
|
||||
"--strict",
|
||||
help="Errors out immediatly on a scenario failure",
|
||||
action="store_true",
|
||||
default=True,
|
||||
)
|
||||
@CommandArgument(
|
||||
"--geckodriver",
|
||||
help="Path to the geckodriver binary",
|
||||
type=str,
|
||||
default=sys.platform.startswith("win") and "geckodriver.exe" or "geckodriver",
|
||||
)
|
||||
@CommandArgument("--device-name", help="Name of the device", type=str, default=None)
|
||||
def run(self, **kw):
|
||||
os.environ["MANUAL_MACH_RUN"] = "1"
|
||||
self._init()
|
||||
|
||||
if kw["firefox"] is None:
|
||||
kw["firefox"] = self.get_binary_path()
|
||||
from condprof.runner import run
|
||||
|
||||
run(**kw)
|
@ -1,6 +0,0 @@
|
||||
./mozfile
|
||||
./mozlog
|
||||
./mozprofile
|
||||
|
||||
requests==2.22.0
|
||||
pyyaml==5.1.2
|
@ -1,8 +1,3 @@
|
||||
./mozfile
|
||||
./mozlog
|
||||
./mozprofile
|
||||
./mozdevice
|
||||
|
||||
aiohttp==3.5.4
|
||||
https://pypi.pub.build.mozilla.org/pub/arsenic-19.1-py3-none-any.whl
|
||||
requests==2.22.0
|
10
testing/condprofile/requirements/ci-client.txt
Normal file
10
testing/condprofile/requirements/ci-client.txt
Normal file
@ -0,0 +1,10 @@
|
||||
# pulled when running in TaskCluster for python 2 only
|
||||
# we just pull dependencies required by condprof.client
|
||||
requests==2.22.0
|
||||
pyyaml==5.1.2
|
||||
|
||||
# the target.condprof.tests.tar.gz archive pulls those dependencies
|
||||
# directly into the condprof project root
|
||||
./mozfile
|
||||
./mozprofile
|
||||
./mozlog
|
7
testing/condprofile/requirements/ci.txt
Normal file
7
testing/condprofile/requirements/ci.txt
Normal file
@ -0,0 +1,7 @@
|
||||
# pulled when running in TaskCluster
|
||||
# the target.condprof.tests.tar.gz archive pulls those dependencies
|
||||
# directly into the condprof project root.
|
||||
./mozfile
|
||||
./mozprofile
|
||||
./mozdevice
|
||||
./mozlog
|
6
testing/condprofile/requirements/local-client.txt
Normal file
6
testing/condprofile/requirements/local-client.txt
Normal file
@ -0,0 +1,6 @@
|
||||
./mozbase/mozfile
|
||||
./mozbase/mozprofile
|
||||
./mozbase/mozlog
|
||||
|
||||
requests==2.22.0
|
||||
pyyaml==5.1.2
|
@ -1,6 +1,5 @@
|
||||
# pulled when running locally
|
||||
../mozbase/mozfile
|
||||
../mozbase/mozprofile
|
||||
../mozbase/mozdevice
|
||||
../mozbase/mozlog
|
||||
|
||||
requests==2.22.0
|
||||
pyyaml==5.1.2
|
8
testing/condprofile/requirements/tox.txt
Normal file
8
testing/condprofile/requirements/tox.txt
Normal file
@ -0,0 +1,8 @@
|
||||
# pulled when running tox locally
|
||||
-r requirements/local.txt
|
||||
|
||||
pytest
|
||||
pytest-cov
|
||||
pytest-random-order
|
||||
coveralls
|
||||
responses
|
@ -7,7 +7,7 @@ PY3 = sys.version_info.major == 3
|
||||
if PY3:
|
||||
entry_points = """
|
||||
[console_scripts]
|
||||
cp-creator = condprof.runner:main
|
||||
cp-creator = condprof.main:main
|
||||
cp-client = condprof.client:main
|
||||
"""
|
||||
else:
|
||||
|
@ -1,5 +0,0 @@
|
||||
pytest
|
||||
pytest-cov
|
||||
pytest-random-order
|
||||
coveralls
|
||||
responses
|
@ -4,8 +4,7 @@ envlist = py36,flake8
|
||||
|
||||
[testenv]
|
||||
passenv = TRAVIS TRAVIS_JOB_ID TRAVIS_BRANCH
|
||||
deps = -rtox-requirements.txt
|
||||
-rlocal-requirements.txt
|
||||
deps = -rrequirements/tox.txt
|
||||
commands =
|
||||
pytest --random-order-bucket=global -sv --cov-report= --cov-config .coveragerc --cov condprof condprof/tests
|
||||
- coverage report -m
|
||||
|
Loading…
Reference in New Issue
Block a user