зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1628277 - Created the android layer r=acreskey
also, isolate the profile handling in its layer, added the --proxy and --profile options Differential Revision: https://phabricator.services.mozilla.com/D71044
This commit is contained in:
Родитель
ea156f7bf4
Коммит
43fca3ecc1
|
@ -2,13 +2,15 @@
|
|||
# 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/.
|
||||
from mozperftest.browser.browsertime import BrowsertimeRunner
|
||||
from mozperftest.browser.profile import Profile
|
||||
from mozperftest.layers import Layers
|
||||
|
||||
|
||||
def get_layers():
|
||||
return (BrowsertimeRunner,)
|
||||
return (Profile, BrowsertimeRunner)
|
||||
|
||||
|
||||
def pick_browser(env, flavor, mach_cmd):
|
||||
if flavor == "script":
|
||||
return BrowsertimeRunner(env, mach_cmd)
|
||||
return Layers(env, mach_cmd, get_layers())
|
||||
raise NotImplementedError(flavor)
|
||||
|
|
|
@ -67,7 +67,16 @@ class BrowsertimeRunner(NodeRunner):
|
|||
name = "browsertime (%s)" % NodeRunner.name
|
||||
|
||||
arguments = {
|
||||
"--cycles": {"type": int, "default": 1, "help": "Number of full cycles"}
|
||||
"--browser-cycles": {
|
||||
"type": int,
|
||||
"default": 1,
|
||||
"help": "Number of full cycles",
|
||||
},
|
||||
"--browser-binary": {
|
||||
"type": str,
|
||||
"default": None,
|
||||
"help": "Path to the desktop browser, or Android app name.",
|
||||
},
|
||||
}
|
||||
|
||||
def __init__(self, env, mach_cmd):
|
||||
|
@ -75,7 +84,6 @@ class BrowsertimeRunner(NodeRunner):
|
|||
self.topsrcdir = mach_cmd.topsrcdir
|
||||
self._mach_context = mach_cmd._mach_context
|
||||
self.virtualenv_manager = mach_cmd.virtualenv_manager
|
||||
self.proxy = None
|
||||
self._created_dirs = []
|
||||
|
||||
@property
|
||||
|
@ -409,19 +417,27 @@ class BrowsertimeRunner(NodeRunner):
|
|||
|
||||
return extra_args
|
||||
|
||||
def get_profile(self, metadata):
|
||||
# XXX we'll use conditioned profiles
|
||||
from mozprofile import create_profile
|
||||
def browsertime_android(self, metadata):
|
||||
app_name = self.get_arg("android-app-name")
|
||||
|
||||
profile = create_profile(app="firefox")
|
||||
prefs = metadata.get_browser_prefs()
|
||||
profile.set_preferences(prefs)
|
||||
self.info("Created profile at %s" % profile.profile)
|
||||
self._created_dirs.append(profile.profile)
|
||||
return profile
|
||||
args_list = [
|
||||
# "--browser", "firefox",
|
||||
"--android",
|
||||
# Work around a `selenium-webdriver` issue where Browsertime
|
||||
# fails to find a Firefox binary even though we're going to
|
||||
# actually do things on an Android device.
|
||||
# "--firefox.binaryPath", self.mach_cmd.get_binary_path(),
|
||||
"--firefox.android.package",
|
||||
app_name,
|
||||
]
|
||||
activity = self.get_arg("android-activity")
|
||||
if activity is not None:
|
||||
args_list += ["--firefox.android.activity", activity]
|
||||
|
||||
return args_list
|
||||
|
||||
def __call__(self, metadata):
|
||||
cycles = self.get_arg("cycles", 1)
|
||||
cycles = self.get_arg("browser-cycles", 1)
|
||||
for cycle in range(1, cycles + 1):
|
||||
metadata.run_hook("before_cycle", cycle=cycle)
|
||||
try:
|
||||
|
@ -431,9 +447,7 @@ class BrowsertimeRunner(NodeRunner):
|
|||
return metadata
|
||||
|
||||
def _one_cycle(self, metadata):
|
||||
# keep the object around
|
||||
# see https://bugzilla.mozilla.org/show_bug.cgi?id=1625118
|
||||
profile = self.get_profile(metadata)
|
||||
profile = self.get_arg("profile-directory")
|
||||
test_script = self.get_arg("tests")[0]
|
||||
output = self.get_arg("output")
|
||||
if output is not None:
|
||||
|
@ -451,7 +465,7 @@ class BrowsertimeRunner(NodeRunner):
|
|||
"--resultDir",
|
||||
result_dir,
|
||||
"--firefox.profileTemplate",
|
||||
profile.profile,
|
||||
profile,
|
||||
"--iterations",
|
||||
"1",
|
||||
test_script,
|
||||
|
@ -473,14 +487,12 @@ class BrowsertimeRunner(NodeRunner):
|
|||
args += ["--" + name, value]
|
||||
|
||||
firefox_args = ["--firefox.developer"]
|
||||
if self.get_arg("android"):
|
||||
args.extend(self.browsertime_android(metadata))
|
||||
|
||||
extra = self.extra_default_args(args=firefox_args)
|
||||
command = [self.browsertime_js] + extra + args
|
||||
self.info("Running browsertime with this command %s" % " ".join(command))
|
||||
self.node(command)
|
||||
metadata.set_result(result_dir)
|
||||
return metadata
|
||||
|
||||
def teardown(self):
|
||||
for dir in self._created_dirs:
|
||||
if os.path.exists(dir):
|
||||
shutil.rmtree(dir)
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
# 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 os
|
||||
import shutil
|
||||
|
||||
from mozperftest.layers import Layer
|
||||
from mozprofile import create_profile
|
||||
from mozprofile.prefs import Preferences
|
||||
|
||||
|
||||
HERE = os.path.dirname(__file__)
|
||||
|
||||
|
||||
class Profile(Layer):
|
||||
name = "profile"
|
||||
arguments = {
|
||||
"--profile-directory": {"type": str, "default": None, "help": "Profile to use"},
|
||||
"--profile-user-js": {"type": str, "default": None, "help": "Custom user.js"},
|
||||
}
|
||||
|
||||
def __init__(self, env, mach_cmd):
|
||||
super(Profile, self).__init__(env, mach_cmd)
|
||||
self._created_dirs = []
|
||||
|
||||
def setup(self):
|
||||
pass
|
||||
|
||||
def __call__(self, metadata):
|
||||
if self.get_arg("profile-directory") is not None:
|
||||
# no need to create one or load a conditioned one
|
||||
return
|
||||
# XXX we'll use conditioned profiles later
|
||||
#
|
||||
# XXX keeping a reference on self, otherwise mozprofile
|
||||
# silently deletes the dir in a __del__ call
|
||||
self.profile = profile = create_profile(app="firefox")
|
||||
prefs = metadata.get_browser_prefs()
|
||||
|
||||
if prefs == {}:
|
||||
prefs["mozperftest"] = "true"
|
||||
|
||||
# apply custom user prefs if any
|
||||
user_js = self.get_arg("profile-user-js")
|
||||
if user_js is not None:
|
||||
self.info("Applying use prefs from %s" % user_js)
|
||||
default_prefs = dict(Preferences.read_prefs(user_js))
|
||||
prefs.update(default_prefs)
|
||||
|
||||
profile.set_preferences(prefs)
|
||||
self.info("Created profile at %s" % profile.profile)
|
||||
self._created_dirs.append(profile.profile)
|
||||
self.set_arg("profile-directory", profile.profile)
|
||||
return metadata
|
||||
|
||||
def teardown(self):
|
||||
for dir in self._created_dirs:
|
||||
if os.path.exists(dir):
|
||||
shutil.rmtree(dir)
|
|
@ -35,13 +35,18 @@ class MachEnvironment:
|
|||
finally:
|
||||
self.unfreeze()
|
||||
|
||||
def _normalize(self, name):
|
||||
if name.startswith("--"):
|
||||
name = name[2:]
|
||||
return name.replace("-", "_")
|
||||
|
||||
def set_arg(self, name, value):
|
||||
"""Sets the argument"""
|
||||
# see if we want to restrict to existing keys
|
||||
self._mach_args[name] = value
|
||||
self._mach_args[self._normalize(name)] = value
|
||||
|
||||
def get_arg(self, name, default=None):
|
||||
return self._mach_args.get(name, default)
|
||||
return self._mach_args.get(self._normalize(name), default)
|
||||
|
||||
def get_layer(self, name):
|
||||
for layer in self.layers:
|
||||
|
|
|
@ -26,7 +26,7 @@ class ConsoleOutput(Layer):
|
|||
metadata.get_result(),
|
||||
self.warning,
|
||||
output=self.get_arg("output"),
|
||||
prefix=self.get_arg("prefix"),
|
||||
prefix=self.get_arg("perfherder-prefix"),
|
||||
)
|
||||
res = cm.get_standardized_data(
|
||||
group_name="firefox", transformer="SingleJsonRetriever"
|
||||
|
@ -34,7 +34,7 @@ class ConsoleOutput(Layer):
|
|||
_, results = res["file-output"], res["data"]
|
||||
|
||||
# Filter out unwanted metrics
|
||||
results = filter_metrics(results, self.get_arg("metrics"))
|
||||
results = filter_metrics(results, self.get_arg("perfherder-metrics"))
|
||||
if not results:
|
||||
self.warning("No results left after filtering")
|
||||
return metadata
|
||||
|
|
|
@ -19,12 +19,12 @@ class Perfherder(Layer):
|
|||
"default": False,
|
||||
"help": "Output data in the perfherder format.",
|
||||
},
|
||||
"--prefix": {
|
||||
"--perfherder-prefix": {
|
||||
"type": str,
|
||||
"default": "",
|
||||
"help": "Prefix the output files with this string.",
|
||||
},
|
||||
"--metrics": {
|
||||
"--perfherder-metrics": {
|
||||
"nargs": "*",
|
||||
"default": [],
|
||||
"help": "The metrics that should be retrieved from the data.",
|
||||
|
@ -56,7 +56,7 @@ class Perfherder(Layer):
|
|||
metadata.get_result(),
|
||||
self.warning,
|
||||
output=self.get_arg("output"),
|
||||
prefix=self.get_arg("prefix"),
|
||||
prefix=self.get_arg("perfherder-prefix"),
|
||||
)
|
||||
res = cm.get_standardized_data(
|
||||
group_name="firefox", transformer="SingleJsonRetriever"
|
||||
|
@ -64,7 +64,7 @@ class Perfherder(Layer):
|
|||
_, results = res["file-output"], res["data"]
|
||||
|
||||
# Filter out unwanted metrics
|
||||
results = filter_metrics(results, self.get_arg("metrics"))
|
||||
results = filter_metrics(results, self.get_arg("perfherder-metrics"))
|
||||
if not results:
|
||||
self.warning("No results left after filtering")
|
||||
return metadata
|
||||
|
|
|
@ -3,10 +3,11 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
from mozperftest.layers import Layers
|
||||
from mozperftest.system.proxy import ProxyRunner
|
||||
from mozperftest.system.android import AndroidDevice
|
||||
|
||||
|
||||
def get_layers():
|
||||
return (ProxyRunner,)
|
||||
return (ProxyRunner, AndroidDevice)
|
||||
|
||||
|
||||
def pick_system(env, flavor, mach_cmd):
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
# 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 os
|
||||
from mozdevice import ADBDevice
|
||||
from mozperftest.layers import Layer
|
||||
|
||||
HERE = os.path.dirname(__file__)
|
||||
|
||||
|
||||
class DeviceError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class AndroidDevice(Layer):
|
||||
name = "android"
|
||||
|
||||
arguments = {
|
||||
"--android": {
|
||||
"action": "store_true",
|
||||
"default": False,
|
||||
"help": "Use an android device via ADB",
|
||||
},
|
||||
"--android-intent": {"type": str, "default": None, "help": "Intent to use"},
|
||||
"--android-app-name": {"type": str, "default": None, "help": "App name"},
|
||||
"--android-activity": {"type": str, "default": None, "help": "Activity to use"},
|
||||
"--android-install-apk": {
|
||||
"nargs": "*",
|
||||
"default": [],
|
||||
"help": "APK to install to the device",
|
||||
},
|
||||
}
|
||||
|
||||
def __init__(self, env, mach_cmd):
|
||||
super(AndroidDevice, self).__init__(env, mach_cmd)
|
||||
self.android_activity = self.app_name = self.device = None
|
||||
|
||||
def setup(self):
|
||||
pass
|
||||
|
||||
def _setup_options(self, app_name="org.mozilla.firefox"):
|
||||
self.app_name = app_name
|
||||
try:
|
||||
self.device = ADBDevice(verbose=True)
|
||||
except AttributeError as e:
|
||||
self.error("Could not connect to the phone. Is it connected?")
|
||||
raise DeviceError(str(e))
|
||||
|
||||
# install APKs
|
||||
for apk in self.get_arg("android-install-apk"):
|
||||
self.info("Installing %s" % apk)
|
||||
self.device.install_app(apk, replace=True)
|
||||
self.info("Done.")
|
||||
|
||||
if self.android_activity is None:
|
||||
# guess the activity, given the app
|
||||
if "fenix" in app_name:
|
||||
self.android_activity = "org.mozilla.fenix.IntentReceiverActivity"
|
||||
elif "geckoview_example" in app_name:
|
||||
self.android_activity = (
|
||||
"org.mozilla.geckoview_example.GeckoViewActivity"
|
||||
)
|
||||
self.set_arg("android_activity", self.android_activity)
|
||||
|
||||
# checking that the app is installed
|
||||
if not self.device.is_app_installed(self.app_name):
|
||||
raise Exception("%s is not installed" % self.app_name)
|
||||
|
||||
self.info("Android environment:")
|
||||
self.info("\t- application name: %s" % self.app_name)
|
||||
self.info("\t- activity: %s" % self.android_activity)
|
||||
self.info("\t- intent: %s" % self.get_arg("android_intent"))
|
||||
|
||||
def teardown(self):
|
||||
pass
|
||||
|
||||
def __call__(self, metadata):
|
||||
android = self.get_arg("android")
|
||||
app_name = self.get_arg("android-app-name")
|
||||
if app_name is None:
|
||||
app_name = self.get_arg("browser-binary")
|
||||
if app_name is not None and app_name.startswith("org.mozilla.") and not android:
|
||||
self.set_arg("android", True)
|
||||
android = True
|
||||
if not android:
|
||||
return metadata
|
||||
if app_name is None:
|
||||
app_name = "org.mozilla.firefox"
|
||||
self.set_arg("android-app-name", app_name)
|
||||
self.metadata = metadata
|
||||
self._setup_options(app_name)
|
||||
return metadata
|
|
@ -25,6 +25,9 @@ class ProxyRunner(Layer):
|
|||
pass
|
||||
|
||||
def __call__(self, metadata):
|
||||
if not self.get_arg("proxy"):
|
||||
return metadata
|
||||
|
||||
self.metadata = metadata
|
||||
if not self.get_arg("proxy"):
|
||||
return metadata
|
||||
|
|
Загрузка…
Ссылка в новой задаче