Bug 1445944 - [mozrunner] Create a base BlinkRuntimeRunner and add a ChromeRunner to the runners list
This allows consumers to bootstrap Chrome with mozrunner. For now the profile implementation
is just an empty class but this will be expanded in a future commit.
MozReview-Commit-ID: 1Z14FudH0JJ
--- a/testing/mozbase/docs/mozrunner.rst
+++ b/testing/mozbase/docs/mozrunner.rst
@@ -148,16 +148,22 @@ BaseRunner
:members:
GeckoRuntimeRunner
~~~~~~~~~~~~~~~~~~
.. autoclass:: mozrunner.base.GeckoRuntimeRunner
:show-inheritance:
:members:
+BlinkRuntimeRunner
+~~~~~~~~~~~~~~~~~~
+.. autoclass:: mozrunner.base.BlinkRuntimeRunner
+ :show-inheritance:
+ :members:
+
DeviceRunner
~~~~~~~~~~~~
.. autoclass:: mozrunner.base.DeviceRunner
:show-inheritance:
:members:
Device API Documentation
------------------------
--- a/testing/mozbase/mozrunner/mozrunner/application.py
+++ b/testing/mozbase/mozrunner/mozrunner/application.py
@@ -15,20 +15,23 @@ from mozprofile import (
FirefoxProfile,
ThunderbirdProfile
)
here = os.path.abspath(os.path.dirname(__file__))
def get_app_context(appname):
- context_map = {'default': DefaultContext,
- 'firefox': FirefoxContext,
- 'thunderbird': ThunderbirdContext,
- 'fennec': FennecContext}
+ context_map = {
+ 'chrome': ChromeContext,
+ 'default': DefaultContext,
+ 'fennec': FennecContext,
+ 'firefox': FirefoxContext,
+ 'thunderbird': ThunderbirdContext,
+ }
if appname not in context_map:
raise KeyError("Application '%s' not supported!" % appname)
return context_map[appname]
class DefaultContext(object):
profile_class = Profile
@@ -126,8 +129,16 @@ class FennecContext(RemoteContext):
class FirefoxContext(object):
profile_class = FirefoxProfile
class ThunderbirdContext(object):
profile_class = ThunderbirdProfile
+
+
+class ChromeProfile(object):
+ """Dummy profile class until a proper one is implemented in mozprofile"""
+
+
+class ChromeContext(object):
+ profile_class = ChromeProfile
--- a/testing/mozbase/mozrunner/mozrunner/base/__init__.py
+++ b/testing/mozbase/mozrunner/mozrunner/base/__init__.py
@@ -1,7 +1,6 @@
+# flake8: noqa
from __future__ import absolute_import
from .runner import BaseRunner
from .device import DeviceRunner, FennecRunner
-from .browser import GeckoRuntimeRunner
-
-__all__ = ['BaseRunner', 'DeviceRunner', 'FennecRunner', 'GeckoRuntimeRunner']
+from .browser import GeckoRuntimeRunner, BlinkRuntimeRunner
--- a/testing/mozbase/mozrunner/mozrunner/base/browser.py
+++ b/testing/mozbase/mozrunner/mozrunner/base/browser.py
@@ -72,8 +72,24 @@ class GeckoRuntimeRunner(BaseRunner):
self.env["MOZ_CRASHREPORTER_DISABLE"] = "1"
else:
if not self.show_crash_reporter:
# hide the crash reporter window
self.env["MOZ_CRASHREPORTER_NO_REPORT"] = "1"
self.env["MOZ_CRASHREPORTER"] = "1"
BaseRunner.start(self, *args, **kwargs)
+
+
+class BlinkRuntimeRunner(BaseRunner):
+ """A base runner class for running apps like Google Chrome or Chromium."""
+ def __init__(self, binary, cmdargs=None, **runner_args):
+ super(BlinkRuntimeRunner, self).__init__(**runner_args)
+ self.binary = binary
+ self.cmdargs = cmdargs or []
+
+ @property
+ def command(self):
+ cmd = self.cmdargs[:]
+ return [self.binary] + cmd
+
+ def check_for_crashes(self, *args, **kwargs):
+ raise NotImplementedError
--- a/testing/mozbase/mozrunner/mozrunner/runners.py
+++ b/testing/mozbase/mozrunner/mozrunner/runners.py
@@ -6,17 +6,17 @@
"""
This module contains a set of shortcut methods that create runners for commonly
used Mozilla applications, such as Firefox, Firefox for Android or Thunderbird.
"""
from __future__ import absolute_import
from .application import get_app_context
-from .base import GeckoRuntimeRunner, FennecRunner
+from .base import GeckoRuntimeRunner, FennecRunner, BlinkRuntimeRunner
from .devices import EmulatorAVD
def Runner(*args, **kwargs):
"""
Create a generic GeckoRuntime runner.
:param binary: Path to binary.
@@ -69,16 +69,27 @@ def ThunderbirdRunner(*args, **kwargs):
:param show_crash_reporter: allow the crash reporter window to pop up.
Defaults to False.
:returns: A GeckoRuntimeRunner for Thunderbird.
"""
kwargs['app_ctx'] = get_app_context('thunderbird')()
return GeckoRuntimeRunner(*args, **kwargs)
+def ChromeRunner(*args, **kwargs):
+ """
+ Create a desktop Google Chrome runner.
+
+ :param binary: Path to Chrome binary.
+ :param cmdargs: Arguments to pass into the binary.
+ """
+ kwargs['app_ctx'] = get_app_context('chrome')()
+ return BlinkRuntimeRunner(*args, **kwargs)
+
+
def FennecEmulatorRunner(avd='mozemulator-4.3',
adb_path=None,
avd_home=None,
logdir=None,
serial=None,
binary=None,
app='org.mozilla.fennec',
**kwargs):
@@ -108,13 +119,14 @@ def FennecEmulatorRunner(avd='mozemulato
'serial': serial,
'logdir': logdir}
return FennecRunner(device_class=EmulatorAVD,
device_args=device_args,
**kwargs)
runners = {
+ 'chrome': ChromeRunner,
'default': Runner,
'firefox': FirefoxRunner,
+ 'fennec': FennecEmulatorRunner,
'thunderbird': ThunderbirdRunner,
- 'fennec': FennecEmulatorRunner
}
--- a/testing/mozbase/mozrunner/tests/conftest.py
+++ b/testing/mozbase/mozrunner/tests/conftest.py
@@ -3,47 +3,56 @@
# You can obtain one at http://mozilla.org/MPL/2.0/.
from __future__ import absolute_import
import os
import threading
from time import sleep
-import mozprofile
import mozrunner
import pytest
from moztest.selftest import fixtures
-@pytest.fixture
-def profile():
- return mozprofile.FirefoxProfile()
-
-
-@pytest.fixture
+@pytest.fixture(scope='session')
def get_binary():
if 'BROWSER_PATH' in os.environ:
os.environ['GECKO_BINARY_PATH'] = os.environ['BROWSER_PATH']
def inner(app):
- if app != 'firefox':
+ if app not in ('chrome', 'firefox'):
pytest.xfail(reason="{} support not implemented".format(app))
- binary = fixtures.binary()
+ if app == 'firefox':
+ binary = fixtures.binary()
+ elif app == 'chrome':
+ binary = os.environ.get('CHROME_BINARY_PATH')
+
if not binary:
pytest.skip("could not find a {} binary".format(app))
return binary
return inner
-@pytest.fixture
-def runner(profile, get_binary):
- binary = get_binary('firefox')
- return mozrunner.FirefoxRunner(binary, profile=profile)
+@pytest.fixture(params=['firefox', 'chrome'])
+def runner(request, get_binary):
+ app = request.param
+ binary = get_binary(app)
+
+ cmdargs = ['--headless']
+ if app == 'chrome':
+ # prevents headless chrome from exiting after loading the page
+ cmdargs.append('--remote-debugging-port=9222')
+ # only needed on Windows, but no harm in specifying it everywhere
+ cmdargs.append('--disable-gpu')
+ runner = mozrunner.runners[app](binary, cmdargs=cmdargs)
+ runner.app = app
+ yield runner
+ runner.stop()
class RunnerThread(threading.Thread):
def __init__(self, runner, start=False, timeout=1):
threading.Thread.__init__(self)
self.runner = runner
self.timeout = timeout
self.do_start = start
--- a/testing/mozbase/mozrunner/tests/test_crash.py
+++ b/testing/mozbase/mozrunner/tests/test_crash.py
@@ -8,16 +8,19 @@ from __future__ import absolute_import
from mock import patch
import mozunit
import pytest
@pytest.mark.parametrize('logger', [True, False])
def test_crash_count_with_or_without_logger(runner, logger):
+ if runner.app == 'chrome':
+ pytest.xfail("crash checking not implemented for ChromeRunner")
+
if not logger:
runner.logger = None
fn = 'check_for_crashes'
else:
fn = 'log_crashes'
with patch('mozcrash.{}'.format(fn), return_value=2) as mock:
assert runner.crashed == 0