new file mode 100644
--- /dev/null
+++ b/testing/marionette/harness/.flake8
@@ -0,0 +1,3 @@
+[flake8]
+max-line-length = 99
+exclude = __init__.py,disti/*,build/*,session/*,marionette/runner/mixins/*, marionette/tests/*
--- a/testing/marionette/harness/docs/conf.py
+++ b/testing/marionette/harness/docs/conf.py
@@ -6,94 +6,95 @@
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
-import sys, os
+import os
+import sys
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
-#sys.path.insert(0, os.path.abspath('.'))
+# sys.path.insert(0, os.path.abspath('.'))
here = os.path.dirname(os.path.abspath(__file__))
parent = os.path.dirname(here)
sys.path.insert(0, parent)
# -- General configuration -----------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
-#needs_sphinx = '1.0'
+# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
-#source_encoding = 'utf-8-sig'
+# source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'Marionette Python Client'
copyright = u'2013, Mozilla Automation and Tools and individual contributors'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
-#version = '0'
+# version = '0'
# The full version, including alpha/beta/rc tags.
-#release = '0'
+# release = '0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
-#language = None
+# language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
-#today = ''
+# today = ''
# Else, today_fmt is used as the format for a strftime call.
-#today_fmt = '%B %d, %Y'
+# today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
# The reST default role (used for this markup: `text`) to use for all documents.
-#default_role = None
+# default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
-#add_function_parentheses = True
+# add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
-#add_module_names = True
+# add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
-#show_authors = False
+# show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
-#modindex_common_prefix = []
+# modindex_common_prefix = []
# -- Options for HTML output ---------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'default'
@@ -107,152 +108,152 @@ if not on_rtd:
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
except ImportError:
pass
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
-#html_theme_options = {}
+# html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
-#html_theme_path = []
+# html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
-#html_title = None
+# html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
-#html_short_title = None
+# html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
-#html_logo = None
+# html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
-#html_favicon = None
+# html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
-#html_static_path = ['_static']
+# html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
-#html_last_updated_fmt = '%b %d, %Y'
+# html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
-#html_use_smartypants = True
+# html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
-#html_sidebars = {}
+# html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
-#html_additional_pages = {}
+# html_additional_pages = {}
# If false, no module index is generated.
-#html_domain_indices = True
+# html_domain_indices = True
# If false, no index is generated.
-#html_use_index = True
+# html_use_index = True
# If true, the index is split into individual pages for each letter.
-#html_split_index = False
+# html_split_index = False
# If true, links to the reST sources are added to the pages.
-#html_show_sourcelink = True
+# html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
-#html_show_sphinx = True
+# html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
-#html_show_copyright = True
+# html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
-#html_use_opensearch = ''
+# html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
-#html_file_suffix = None
+# html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'MarionettePythonClientdoc'
# -- Options for LaTeX output --------------------------------------------------
latex_elements = {
-# The paper size ('letterpaper' or 'a4paper').
-#'papersize': 'letterpaper',
+ # The paper size ('letterpaper' or 'a4paper').
+ # 'papersize': 'letterpaper',
-# The font size ('10pt', '11pt' or '12pt').
-#'pointsize': '10pt',
+ # The font size ('10pt', '11pt' or '12pt').
+ # 'pointsize': '10pt',
-# Additional stuff for the LaTeX preamble.
-#'preamble': '',
+ # Additional stuff for the LaTeX preamble.
+ # 'preamble': '',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
- ('index', 'MarionettePythonClient.tex', u'Marionette Python Client Documentation',
- u'Mozilla Automation and Tools team', 'manual'),
+ ('index', 'MarionettePythonClient.tex', u'Marionette Python Client Documentation',
+ u'Mozilla Automation and Tools team', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
-#latex_logo = None
+# latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
-#latex_use_parts = False
+# latex_use_parts = False
# If true, show page references after internal links.
-#latex_show_pagerefs = False
+# latex_show_pagerefs = False
# If true, show URL addresses after external links.
-#latex_show_urls = False
+# latex_show_urls = False
# Documents to append as an appendix to all manuals.
-#latex_appendices = []
+# latex_appendices = []
# If false, no module index is generated.
-#latex_domain_indices = True
+# latex_domain_indices = True
# -- Options for manual page output --------------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'marionettepythonclient', u'Marionette Python Client Documentation',
[u'Mozilla Automation and Tools team'], 1)
]
# If true, show URL addresses after external links.
-#man_show_urls = False
+# man_show_urls = False
# -- Options for Texinfo output ------------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
- ('index', 'MarionettePythonClient', u'Marionette Python Client Documentation',
- u'Mozilla Automation and Tools team', 'MarionettePythonClient', 'One line description of project.',
- 'Miscellaneous'),
+ ('index', 'MarionettePythonClient', 'Marionette Python Client Documentation',
+ 'Mozilla Automation and Tools team', 'MarionettePythonClient',
+ 'One line description of project.', 'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
-#texinfo_appendices = []
+# texinfo_appendices = []
# If false, no module index is generated.
-#texinfo_domain_indices = True
+# texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
-#texinfo_show_urls = 'footnote'
+# texinfo_show_urls = 'footnote'
--- a/testing/marionette/harness/marionette/marionette_test.py
+++ b/testing/marionette/harness/marionette/marionette_test.py
@@ -11,128 +11,131 @@ import socket
import time
import types
import unittest
import weakref
import warnings
from marionette_driver.errors import (
- MarionetteException, TimeoutException,
- JavascriptException, NoSuchElementException, NoSuchWindowException,
- StaleElementException, ScriptTimeoutException, ElementNotVisibleException,
- NoSuchFrameException, InvalidElementStateException, NoAlertPresentException,
- InvalidCookieDomainException, UnableToSetCookieException, InvalidSelectorException,
- MoveTargetOutOfBoundsException
- )
-from marionette_driver.marionette import Marionette
-from marionette_driver.wait import Wait
-from marionette_driver.expected import element_present, element_not_present
+ MarionetteException,
+ ScriptTimeoutException,
+ TimeoutException,
+)
from mozlog import get_default_logger
class SkipTest(Exception):
"""
Raise this exception in a test to skip it.
Usually you can use TestResult.skip() or one of the skipping decorators
instead of raising this directly.
"""
+
pass
+
class _ExpectedFailure(Exception):
"""
Raise this when a test is expected to fail.
This is an implementation detail.
"""
def __init__(self, exc_info):
super(_ExpectedFailure, self).__init__()
self.exc_info = exc_info
+
class _UnexpectedSuccess(Exception):
- """
- The test was supposed to fail, but it didn't!
- """
+ """The test was supposed to fail, but it didn't."""
+
pass
+
def skip(reason):
"""Unconditionally skip a test."""
def decorator(test_item):
if not isinstance(test_item, (type, types.ClassType)):
@functools.wraps(test_item)
def skip_wrapper(*args, **kwargs):
raise SkipTest(reason)
test_item = skip_wrapper
test_item.__unittest_skip__ = True
test_item.__unittest_skip_why__ = reason
return test_item
return decorator
+
def expectedFailure(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
try:
func(*args, **kwargs)
except Exception:
raise _ExpectedFailure(sys.exc_info())
raise _UnexpectedSuccess
return wrapper
+
def skip_if_chrome(target):
def wrapper(self, *args, **kwargs):
if self.marionette._send_message("getContext", key="value") == "chrome":
raise SkipTest("skipping test in chrome context")
return target(self, *args, **kwargs)
return wrapper
+
def skip_if_desktop(target):
def wrapper(self, *args, **kwargs):
if self.marionette.session_capabilities.get('browserName') == 'firefox':
raise SkipTest('skipping due to desktop')
return target(self, *args, **kwargs)
return wrapper
+
def skip_if_mobile(target):
def wrapper(self, *args, **kwargs):
if self.marionette.session_capabilities.get('browserName') == 'fennec':
raise SkipTest('skipping due to fennec')
return target(self, *args, **kwargs)
return wrapper
+
def skip_if_e10s(target):
def wrapper(self, *args, **kwargs):
with self.marionette.using_context('chrome'):
multi_process_browser = self.marionette.execute_script("""
try {
return Services.appinfo.browserTabsRemoteAutostart;
} catch (e) {
return false;
}""")
if multi_process_browser:
raise SkipTest('skipping due to e10s')
return target(self, *args, **kwargs)
return wrapper
+
def skip_unless_protocol(predicate):
- """Given a predicate passed the current protocol level, skip the
- test if the predicate does not match."""
+ """Skip the test if the predicate does not match the current protocol level."""
def decorator(test_item):
@functools.wraps(test_item)
def skip_wrapper(self):
level = self.marionette.client.protocol
if not predicate(level):
raise SkipTest('skipping because protocol level is %s' % level)
return test_item(self)
return skip_wrapper
return decorator
+
def skip_unless_browser_pref(pref, predicate=bool):
"""
Skip a test based on the value of a browser preference.
:param pref: the preference name
:param predicate: a function that should return false to skip the test.
The function takes one parameter, the preference value.
Defaults to the python built-in bool function.
@@ -154,18 +157,19 @@ def skip_unless_browser_pref(pref, predi
if value is None:
self.fail("No such browser preference: %r" % pref)
if not predicate(value):
raise SkipTest("browser preference %r: %r" % (pref, value))
return target(self, *args, **kwargs)
return wrapped
return wrapper
+
def parameterized(func_suffix, *args, **kwargs):
- """
+ r"""
A decorator that can generate methods given a base method and some data.
**func_suffix** is used as a suffix for the new created method and must be
unique given a base method. if **func_suffix** countains characters that
are not allowed in normal python function name, these characters will be
replaced with "_".
This decorator can be used more than once on a single base method. The class
@@ -190,19 +194,21 @@ def parameterized(func_suffix, *args, **
"""
def wrapped(func):
if not hasattr(func, 'metaparameters'):
func.metaparameters = []
func.metaparameters.append((func_suffix, args, kwargs))
return func
return wrapped
+
def with_parameters(parameters):
"""
A decorator that can generate methods given a base method and some data.
+
Acts like :func:`parameterized`, but define all methods in one call.
Example::
# This example will generate two methods:
#
# - MyTestCase.test_it_1
# - MyTestCase.test_it_2
@@ -218,50 +224,58 @@ def with_parameters(parameters):
:param parameters: list of tuples (**func_suffix**, **args**, **kwargs**)
defining parameters like in :func:`todo`.
"""
def wrapped(func):
func.metaparameters = parameters
return func
return wrapped
+
def wraps_parameterized(func, func_suffix, args, kwargs):
- """Internal: for MetaParameterized"""
+ """Internal: for MetaParameterized."""
def wrapper(self):
return func(self, *args, **kwargs)
wrapper.__name__ = func.__name__ + '_' + str(func_suffix)
wrapper.__doc__ = '[%s] %s' % (func_suffix, func.__doc__)
return wrapper
+
class MetaParameterized(type):
"""
- A metaclass that allow a class to use decorators like :func:`parameterized`
+ A metaclass that allow a class to use decorators.
+
+ It can be used like :func:`parameterized`
or :func:`with_parameters` to generate new methods.
"""
+
RE_ESCAPE_BAD_CHARS = re.compile(r'[\.\(\) -/]')
+
def __new__(cls, name, bases, attrs):
for k, v in attrs.items():
if callable(v) and hasattr(v, 'metaparameters'):
for func_suffix, args, kwargs in v.metaparameters:
func_suffix = cls.RE_ESCAPE_BAD_CHARS.sub('_', func_suffix)
wrapper = wraps_parameterized(v, func_suffix, args, kwargs)
if wrapper.__name__ in attrs:
raise KeyError("%s is already a defined method on %s" %
- (wrapper.__name__, name))
+ (wrapper.__name__, name))
attrs[wrapper.__name__] = wrapper
del attrs[k]
return type.__new__(cls, name, bases, attrs)
+
class JSTest:
head_js_re = re.compile(r"MARIONETTE_HEAD_JS(\s*)=(\s*)['|\"](.*?)['|\"];")
context_re = re.compile(r"MARIONETTE_CONTEXT(\s*)=(\s*)['|\"](.*?)['|\"];")
timeout_re = re.compile(r"MARIONETTE_TIMEOUT(\s*)=(\s*)(\d+);")
inactivity_timeout_re = re.compile(r"MARIONETTE_INACTIVITY_TIMEOUT(\s*)=(\s*)(\d+);")
+
class CommonTestCase(unittest.TestCase):
__metaclass__ = MetaParameterized
match_re = None
failureException = AssertionError
pydebugger = None
def __init__(self, methodName, **kwargs):
@@ -305,21 +319,21 @@ class CommonTestCase(unittest.TestCase):
startTestRun = getattr(result, 'startTestRun', None)
if startTestRun is not None:
startTestRun()
result.startTest(self)
testMethod = getattr(self, self._testMethodName)
if (getattr(self.__class__, "__unittest_skip__", False) or
- getattr(testMethod, "__unittest_skip__", False)):
+ getattr(testMethod, "__unittest_skip__", False)):
# If the class or method was skipped.
try:
- skip_why = (getattr(self.__class__, '__unittest_skip_why__', '')
- or getattr(testMethod, '__unittest_skip_why__', ''))
+ skip_why = (getattr(self.__class__, '__unittest_skip_why__', '') or
+ getattr(testMethod, '__unittest_skip_why__', ''))
self._addSkip(result, skip_why)
finally:
result.stopTest(self)
self.stop_time = time.time()
return
try:
success = False
try:
@@ -356,17 +370,18 @@ class CommonTestCase(unittest.TestCase):
raise
except _ExpectedFailure as e:
expected_failure(result, e.exc_info)
except _UnexpectedSuccess:
addUnexpectedSuccess = getattr(result, 'addUnexpectedSuccess', None)
if addUnexpectedSuccess is not None:
addUnexpectedSuccess(self)
else:
- warnings.warn("TestResult has no addUnexpectedSuccess method, reporting as failures",
+ warnings.warn("TestResult has no addUnexpectedSuccess method, "
+ "reporting as failures",
RuntimeWarning)
result.addFailure(self, sys.exc_info())
except SkipTest as e:
self._addSkip(result, str(e))
except:
self._enter_pm()
result.addError(self, sys.exc_info())
else:
@@ -397,31 +412,28 @@ class CommonTestCase(unittest.TestCase):
result.stopTest(self)
if orig_result is None:
stopTestRun = getattr(result, 'stopTestRun', None)
if stopTestRun is not None:
stopTestRun()
@classmethod
def match(cls, filename):
- """
- Determines if the specified filename should be handled by this
- test class; this is done by looking for a match for the filename
- using cls.match_re.
+ """Determine if the specified filename should be handled by this test class.
+
+ This is done by looking for a match for the filename using cls.match_re.
"""
if not cls.match_re:
return False
m = cls.match_re.match(filename)
return m is not None
@classmethod
def add_tests_to_suite(cls, mod_name, filepath, suite, testloader, marionette, testvars):
- """
- Adds all the tests in the specified file to the specified suite.
- """
+ """Add all the tests in the specified file to the specified suite."""
raise NotImplementedError
@property
def test_name(self):
if hasattr(self, 'jsFile'):
return os.path.basename(self.jsFile)
else:
return '%s.py %s.%s' % (self.__class__.__module__,
@@ -475,59 +487,59 @@ class CommonTestCase(unittest.TestCase):
self.marionette.client.close()
except socket.error:
pass
self.marionette = None
def setup_SpecialPowers_observer(self):
self.marionette.set_context("chrome")
self.marionette.execute_script("""
- let SECURITY_PREF = "security.turn_off_all_security_so_that_viruses_can_take_over_this_computer";
- Components.utils.import("resource://gre/modules/Preferences.jsm");
- Preferences.set(SECURITY_PREF, true);
+let SECURITY_PREF = "security.turn_off_all_security_so_that_viruses_can_take_over_this_computer";
+Components.utils.import("resource://gre/modules/Preferences.jsm");
+Preferences.set(SECURITY_PREF, true);
- if (!testUtils.hasOwnProperty("specialPowersObserver")) {
- let loader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
- .getService(Components.interfaces.mozIJSSubScriptLoader);
- loader.loadSubScript("chrome://specialpowers/content/SpecialPowersObserver.jsm",
- testUtils);
- testUtils.specialPowersObserver = new testUtils.SpecialPowersObserver();
- testUtils.specialPowersObserver.init();
- }
- """)
+if (!testUtils.hasOwnProperty("specialPowersObserver")) {
+ let loader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
+ .getService(Components.interfaces.mozIJSSubScriptLoader);
+ loader.loadSubScript("chrome://specialpowers/content/SpecialPowersObserver.jsm",
+ testUtils);
+ testUtils.specialPowersObserver = new testUtils.SpecialPowersObserver();
+ testUtils.specialPowersObserver.init();
+}
+""")
def run_js_test(self, filename, marionette=None):
- '''
- Run a JavaScript test file and collect its set of assertions
- into the current test's results.
+ """Run a JavaScript test file.
+
+ It collects its set of assertions into the current test's results.
:param filename: The path to the JavaScript test file to execute.
May be relative to the current script.
:param marionette: The Marionette object in which to execute the test.
Defaults to self.marionette.
- '''
+ """
marionette = marionette or self.marionette
if not os.path.isabs(filename):
# Find the caller's filename and make the path relative to that.
caller_file = sys._getframe(1).f_globals.get('__file__', '')
caller_file = os.path.abspath(caller_file)
filename = os.path.join(os.path.dirname(caller_file), filename)
self.assert_(os.path.exists(filename),
'Script "%s" must exist' % filename)
original_test_name = self.marionette.test_name
self.marionette.test_name = os.path.basename(filename)
f = open(filename, 'r')
js = f.read()
args = []
- head_js = JSTest.head_js_re.search(js);
+ head_js = JSTest.head_js_re.search(js)
if head_js:
head_js = head_js.group(3)
head = open(os.path.join(os.path.dirname(filename), head_js), 'r')
- js = head.read() + js;
+ js = head.read() + js
context = JSTest.context_re.search(js)
if context:
context = context.group(3)
else:
context = 'content'
if 'SpecialPowers' in js:
@@ -563,78 +575,81 @@ class CommonTestCase(unittest.TestCase):
try:
results = marionette.execute_js_script(
js,
args,
inactivity_timeout=inactivity_timeout,
filename=os.path.basename(filename)
)
- self.assertTrue(not 'timeout' in filename,
+ self.assertTrue('timeout' not in filename,
'expected timeout not triggered')
if 'fail' in filename:
self.assertTrue(len(results['failures']) > 0,
"expected test failures didn't occur")
else:
for failure in results['failures']:
diag = "" if failure.get('diag') is None else failure['diag']
- name = "got false, expected true" if failure.get('name') is None else failure['name']
+ name = ("got false, expected true" if failure.get('name') is None else
+ failure['name'])
self.logger.test_status(self.test_name, name, 'FAIL',
message=diag)
for failure in results['expectedFailures']:
diag = "" if failure.get('diag') is None else failure['diag']
- name = "got false, expected false" if failure.get('name') is None else failure['name']
+ name = ("got false, expected false" if failure.get('name') is None else
+ failure['name'])
self.logger.test_status(self.test_name, name, 'FAIL',
expected='FAIL', message=diag)
for failure in results['unexpectedSuccesses']:
diag = "" if failure.get('diag') is None else failure['diag']
- name = "got true, expected false" if failure.get('name') is None else failure['name']
+ name = ("got true, expected false" if failure.get('name') is None else
+ failure['name'])
self.logger.test_status(self.test_name, name, 'PASS',
expected='FAIL', message=diag)
self.assertEqual(0, len(results['failures']),
'%d tests failed' % len(results['failures']))
if len(results['unexpectedSuccesses']) > 0:
raise _UnexpectedSuccess('')
if len(results['expectedFailures']) > 0:
raise _ExpectedFailure((AssertionError, AssertionError(''), None))
- self.assertTrue(results['passed']
- + len(results['failures'])
- + len(results['expectedFailures'])
- + len(results['unexpectedSuccesses']) > 0,
+ self.assertTrue(results['passed'] +
+ len(results['failures']) +
+ len(results['expectedFailures']) +
+ len(results['unexpectedSuccesses']) > 0,
'no tests run')
except ScriptTimeoutException:
if 'timeout' in filename:
# expected exception
pass
else:
self.loglines = marionette.get_logs()
raise
self.marionette.test_name = original_test_name
-
class MarionetteTestCase(CommonTestCase):
match_re = re.compile(r"test_(.*)\.py$")
def __init__(self, marionette_weakref, methodName='runTest',
filepath='', **kwargs):
self._marionette_weakref = marionette_weakref
self.marionette = None
self.methodName = methodName
self.filepath = filepath
self.testvars = kwargs.pop('testvars', None)
self.test_container = kwargs.pop('test_container', None)
CommonTestCase.__init__(self, methodName, **kwargs)
@classmethod
- def add_tests_to_suite(cls, mod_name, filepath, suite, testloader, marionette, testvars, **kwargs):
+ def add_tests_to_suite(cls, mod_name, filepath, suite, testloader, marionette,
+ testvars, **kwargs):
# since we use imp.load_source to load test modules, if a module
# is loaded with the same name as another one the module would just be
# reloaded.
#
# We may end up by finding too many test in a module then since
# reload() only update the module dict (so old keys are still there!)
# see https://docs.python.org/2/library/functions.html#reload
#
@@ -644,17 +659,17 @@ class MarionetteTestCase(CommonTestCase)
if mod_name in sys.modules:
del sys.modules[mod_name]
test_mod = imp.load_source(mod_name, filepath)
for name in dir(test_mod):
obj = getattr(test_mod, name)
if (isinstance(obj, (type, types.ClassType)) and
- issubclass(obj, unittest.TestCase)):
+ issubclass(obj, unittest.TestCase)):
testnames = testloader.getTestCaseNames(obj)
for testname in testnames:
suite.addTest(obj(weakref.ref(marionette),
methodName=testname,
filepath=filepath,
testvars=testvars,
**kwargs))
@@ -691,30 +706,32 @@ class MarionetteTestCase(CommonTestCase)
while time.time() < timeout:
value = method(self.marionette)
if value:
return value
time.sleep(0.5)
else:
raise TimeoutException("wait_for_condition timed out")
+
class MarionetteJSTestCase(CommonTestCase):
match_re = re.compile(r"test_(.*)\.js$")
def __init__(self, marionette_weakref, methodName='runTest', jsFile=None, **kwargs):
assert(jsFile)
self.jsFile = jsFile
self._marionette_weakref = marionette_weakref
self.marionette = None
self.test_container = kwargs.pop('test_container', None)
CommonTestCase.__init__(self, methodName)
@classmethod
- def add_tests_to_suite(cls, mod_name, filepath, suite, testloader, marionette, testvars, **kwargs):
+ def add_tests_to_suite(cls, mod_name, filepath, suite, testloader, marionette,
+ testvars, **kwargs):
suite.addTest(cls(weakref.ref(marionette), jsFile=filepath, **kwargs))
def runTest(self):
if self.marionette.session is None:
self.marionette.start_session()
self.marionette.execute_script(
"log('TEST-START: %s');" % self.jsFile.replace('\\', '\\\\'),
sandbox="simpletest")
--- a/testing/marionette/harness/marionette/runner/base.py
+++ b/testing/marionette/harness/marionette/runner/base.py
@@ -28,19 +28,19 @@ from moztest.adapters.unit import Struct
from moztest.results import TestResultCollection, TestResult, relevant_line
import mozversion
import httpd
here = os.path.abspath(os.path.dirname(__file__))
+
def update_mozinfo(path=None):
- """walk up directories to find mozinfo.json and update the info"""
-
+ """Walk up directories to find mozinfo.json and update the info."""
path = path or here
dirs = set()
while path != os.path.expanduser('~'):
if path in dirs:
break
dirs.add(path)
path = os.path.split(path)[0]
@@ -53,26 +53,27 @@ class MarionetteTest(TestResult):
def test_name(self):
if self.test_class is not None:
return '%s.py %s.%s' % (self.test_class.split('.')[0],
self.test_class,
self.name)
else:
return self.name
+
class MarionetteTestResult(StructuredTestResult, TestResultCollection):
resultClass = MarionetteTest
def __init__(self, *args, **kwargs):
self.marionette = kwargs.pop('marionette')
TestResultCollection.__init__(self, 'MarionetteTest')
self.passed = 0
self.testsRun = 0
- self.result_modifiers = [] # used by mixins to modify the result
+ self.result_modifiers = [] # used by mixins to modify the result
StructuredTestResult.__init__(self, *args, **kwargs)
@property
def skipped(self):
return [t for t in self if t.result == 'SKIPPED']
@skipped.setter
def skipped(self, value):
@@ -128,33 +129,36 @@ class MarionetteTestResult(StructuredTes
name = str(test).split()[0]
test_class = get_class(test)
if hasattr(test, 'jsFile'):
name = os.path.basename(test.jsFile)
test_class = None
t = self.resultClass(name=name, test_class=test_class,
- time_start=test.start_time, result_expected=result_expected,
- context=context, **kwargs)
+ time_start=test.start_time, result_expected=result_expected,
+ context=context, **kwargs)
# call any registered result modifiers
for modifier in self.result_modifiers:
- result_expected, result_actual, output, context = modifier(t, result_expected, result_actual, output, context)
+ result_expected, result_actual, output, context = modifier(
+ t, result_expected, result_actual, output, context)
t.finish(result_actual,
time_end=time.time() if test.start_time else 0,
reason=relevant_line(output),
output=output)
self.append(t)
def addError(self, test, err):
- self.add_test_result(test, output=self._exc_info_to_string(err, test), result_actual='ERROR')
+ self.add_test_result(test, output=self._exc_info_to_string(err, test),
+ result_actual='ERROR')
super(MarionetteTestResult, self).addError(test, err)
def addFailure(self, test, err):
- self.add_test_result(test, output=self._exc_info_to_string(err, test), result_actual='UNEXPECTED-FAIL')
+ self.add_test_result(test, output=self._exc_info_to_string(err, test),
+ result_actual='UNEXPECTED-FAIL')
super(MarionetteTestResult, self).addFailure(test, err)
def addSuccess(self, test):
self.passed += 1
self.add_test_result(test, result_actual='PASS')
super(MarionetteTestResult, self).addSuccess(test)
def addExpectedFailure(self, test, err):
@@ -188,17 +192,17 @@ class MarionetteTestResult(StructuredTes
def printLogs(self, test):
for testcase in test._tests:
if hasattr(testcase, 'loglines') and testcase.loglines:
# Don't dump loglines to the console if they only contain
# TEST-START and TEST-END.
skip_log = True
for line in testcase.loglines:
str_line = ' '.join(line)
- if not 'TEST-END' in str_line and not 'TEST-START' in str_line:
+ if 'TEST-END' not in str_line and 'TEST-START' not in str_line:
skip_log = False
break
if skip_log:
return
self.logger.info('START LOG:')
for line in testcase.loglines:
self.logger.info(' '.join(line).encode('ascii', 'replace'))
self.logger.info('END LOG:')
@@ -255,126 +259,131 @@ class BaseMarionetteArguments(ArgumentPa
nargs='*',
default=[],
help='Tests to run. '
'One or more paths to test files (Python or JS), '
'manifest files (.ini) or directories. '
'When a directory is specified, '
'all test files in the directory will be run.')
self.add_argument('--binary',
- help='path to gecko executable to launch before running the test')
+ help='path to gecko executable to launch before running the test')
self.add_argument('--address',
- help='host:port of running Gecko instance to connect to')
+ help='host:port of running Gecko instance to connect to')
self.add_argument('--emulator',
- action='store_true',
- help='If no --address is given, then the harness will launch an emulator. (See Remote options group.) '
- 'If --address is given, then the harness assumes you are running an '
- 'emulator already, and will launch gecko app on that emulator.')
+ action='store_true',
+ help='If no --address is given, then the harness will launch an '
+ 'emulator. (See Remote options group.) '
+ 'If --address is given, then the harness assumes you are '
+ 'running an emulator already, and will launch gecko app '
+ 'on that emulator.')
self.add_argument('--app',
- help='application to use. see marionette_driver.geckoinstance')
+ help='application to use. see marionette_driver.geckoinstance')
self.add_argument('--app-arg',
- dest='app_args',
- action='append',
- default=[],
- help='specify a command line argument to be passed onto the application')
+ dest='app_args',
+ action='append',
+ default=[],
+ help='specify a command line argument to be passed onto the application')
self.add_argument('--profile',
- help='profile to use when launching the gecko process. If not passed, then a profile will be '
- 'constructed and used',
- type=dir_path)
+ help='profile to use when launching the gecko process. If not passed, '
+ 'then a profile will be constructed and used',
+ type=dir_path)
self.add_argument('--pref',
- action='append',
- dest='prefs_args',
- help=(" A preference to set. Must be a key-value pair"
- " separated by a ':'."))
+ action='append',
+ dest='prefs_args',
+ help="A preference to set. Must be a key-value pair separated by a ':'.")
self.add_argument('--preferences',
- action='append',
- dest='prefs_files',
- help=("read preferences from a JSON or INI file. For"
- " INI, use 'file.ini:section' to specify a"
- " particular section."))
+ action='append',
+ dest='prefs_files',
+ help="read preferences from a JSON or INI file. For INI, use "
+ "'file.ini:section' to specify a particular section.")
self.add_argument('--addon',
- action='append',
- help="addon to install; repeat for multiple addons.")
+ action='append',
+ help="addon to install; repeat for multiple addons.")
self.add_argument('--repeat',
- type=int,
- default=0,
- help='number of times to repeat the test(s)')
+ type=int,
+ default=0,
+ help='number of times to repeat the test(s)')
self.add_argument('--testvars',
- action='append',
- help='path to a json file with any test data required')
+ action='append',
+ help='path to a json file with any test data required')
self.add_argument('--symbols-path',
- help='absolute path to directory containing breakpad symbols, or the url of a zip file containing symbols')
+ help='absolute path to directory containing breakpad symbols, or the '
+ 'url of a zip file containing symbols')
self.add_argument('--timeout',
- type=int,
- help='if a --timeout value is given, it will set the default page load timeout, search timeout and script timeout to the given value. If not passed in, it will use the default values of 30000ms for page load, 0ms for search timeout and 10000ms for script timeout')
+ type=int,
+ help='if a --timeout value is given, it will set the default page load '
+ 'timeout, search timeout and script timeout to the given value. '
+ 'If not passed in, it will use the default values of 30000ms for '
+ 'page load, 0ms for search timeout and 10000ms for script timeout')
self.add_argument('--startup-timeout',
- type=int,
- default=60,
- help='the max number of seconds to wait for a Marionette connection after launching a binary')
+ type=int,
+ default=60,
+ help='the max number of seconds to wait for a Marionette connection '
+ 'after launching a binary')
self.add_argument('--shuffle',
- action='store_true',
- default=False,
- help='run tests in a random order')
+ action='store_true',
+ default=False,
+ help='run tests in a random order')
self.add_argument('--shuffle-seed',
- type=int,
- default=random.randint(0, sys.maxint),
- help='Use given seed to shuffle tests')
+ type=int,
+ default=random.randint(0, sys.maxint),
+ help='Use given seed to shuffle tests')
self.add_argument('--total-chunks',
- type=int,
- help='how many chunks to split the tests up into')
+ type=int,
+ help='how many chunks to split the tests up into')
self.add_argument('--this-chunk',
- type=int,
- help='which chunk to run')
+ type=int,
+ help='which chunk to run')
self.add_argument('--sources',
- help='path to sources.xml (Firefox OS only)')
+ help='path to sources.xml (Firefox OS only)')
self.add_argument('--server-root',
- help='url to a webserver or path to a document root from which content '
- 'resources are served (default: {}).'.format(os.path.join(
- os.path.dirname(here), 'www')))
+ help='url to a webserver or path to a document root from which content '
+ 'resources are served (default: {}).'.format(os.path.join(
+ os.path.dirname(here), 'www')))
self.add_argument('--gecko-log',
- help="Define the path to store log file. If the path is"
- " a directory, the real log file will be created"
- " given the format gecko-(timestamp).log. If it is"
- " a file, if will be used directly. '-' may be passed"
- " to write to stdout. Default: './gecko.log'")
+ help="Define the path to store log file. If the path is"
+ " a directory, the real log file will be created"
+ " given the format gecko-(timestamp).log. If it is"
+ " a file, if will be used directly. '-' may be passed"
+ " to write to stdout. Default: './gecko.log'")
self.add_argument('--logger-name',
- default='Marionette-based Tests',
- help='Define the name to associate with the logger used')
+ default='Marionette-based Tests',
+ help='Define the name to associate with the logger used')
self.add_argument('--jsdebugger',
- action='store_true',
- default=False,
- help='Enable the jsdebugger for marionette javascript.')
+ action='store_true',
+ default=False,
+ help='Enable the jsdebugger for marionette javascript.')
self.add_argument('--pydebugger',
- help='Enable python post-mortem debugger when a test fails.'
- ' Pass in the debugger you want to use, eg pdb or ipdb.')
+ help='Enable python post-mortem debugger when a test fails.'
+ ' Pass in the debugger you want to use, eg pdb or ipdb.')
self.add_argument('--socket-timeout',
- type=float,
- default=self.socket_timeout_default,
- help='Set the global timeout for marionette socket operations.')
+ type=float,
+ default=self.socket_timeout_default,
+ help='Set the global timeout for marionette socket operations.')
self.add_argument('--disable-e10s',
- action='store_false',
- dest='e10s',
- default=True,
- help='Disable e10s when running marionette tests.')
+ action='store_false',
+ dest='e10s',
+ default=True,
+ help='Disable e10s when running marionette tests.')
self.add_argument('--tag',
- action='append', dest='test_tags',
- default=None,
- help="Filter out tests that don't have the given tag. Can be "
- "used multiple times in which case the test must contain "
- "at least one of the given tags.")
+ action='append', dest='test_tags',
+ default=None,
+ help="Filter out tests that don't have the given tag. Can be "
+ "used multiple times in which case the test must contain "
+ "at least one of the given tags.")
self.add_argument('--workspace',
action='store',
default=None,
help="Path to directory for Marionette output. "
"(Default: .) (Default profile dest: TMP)",
type=dir_path)
self.add_argument('-v', '--verbose',
- action='count',
- help='Increase verbosity to include debug messages with -v, '
- 'and trace messages with -vv.')
+ action='count',
+ help='Increase verbosity to include debug messages with -v, '
+ 'and trace messages with -vv.')
self.register_argument_container(RemoteMarionetteArguments())
def register_argument_container(self, container):
group = self.add_argument_group(container.name)
for cli, kwargs in container.args:
group.add_argument(*cli, **kwargs)
@@ -383,19 +392,17 @@ class BaseMarionetteArguments(ArgumentPa
def parse_known_args(self, args=None, namespace=None):
args, remainder = ArgumentParser.parse_known_args(self, args, namespace)
for container in self.argument_containers:
if hasattr(container, 'parse_args_handler'):
container.parse_args_handler(args)
return (args, remainder)
def _get_preferences(self, prefs_files, prefs_args):
- """
- return user defined profile preferences as a dict
- """
+ """Return user defined profile preferences as a dict."""
# object that will hold the preferences
prefs = mozprofile.prefs.Preferences()
# add preferences files
if prefs_files:
for prefs_file in prefs_files:
prefs.add_file(prefs_file)
@@ -453,16 +460,17 @@ class BaseMarionetteArguments(ArgumentPa
})
for container in self.argument_containers:
if hasattr(container, 'verify_usage_handler'):
container.verify_usage_handler(args)
return args
+
class RemoteMarionetteArguments(object):
name = 'Remote (Emulator/Device)'
args = [
[['--emulator-binary'],
{'help': 'Path to emulator binary. By default mozrunner uses `which emulator`',
'dest': 'emulator_bin',
}],
[['--adb'],
@@ -483,27 +491,29 @@ class RemoteMarionetteArguments(object):
}],
[['--package'],
{'help': 'Name of Android package, e.g. org.mozilla.fennec',
'dest': 'package_name',
}],
]
+
class BaseMarionetteTestRunner(object):
textrunnerclass = MarionetteTextTestRunner
driverclass = Marionette
def __init__(self, address=None,
app=None, app_args=None, binary=None, profile=None,
logger=None, logdir=None,
repeat=0, testvars=None,
symbols_path=None, timeout=None,
- shuffle=False, shuffle_seed=random.randint(0, sys.maxint), this_chunk=1, total_chunks=1, sources=None,
+ shuffle=False, shuffle_seed=random.randint(0, sys.maxint), this_chunk=1,
+ total_chunks=1, sources=None,
server_root=None, gecko_log=None, result_callbacks=None,
prefs=None, test_tags=None,
socket_timeout=BaseMarionetteArguments.socket_timeout_default,
startup_timeout=None, addons=None, workspace=None,
verbose=0, e10s=True, emulator=False, **kwargs):
self.extra_kwargs = kwargs
self.test_kwargs = deepcopy(kwargs)
self.address = address
@@ -544,17 +554,18 @@ class BaseMarionetteTestRunner(object):
self.verbose = verbose
self.e10s = e10s
self._filename_pattern = None
def gather_debug(test, status):
rv = {}
marionette = test._marionette_weakref()
- # In the event we're gathering debug without starting a session, skip marionette commands
+ # In the event we're gathering debug without starting a session,
+ # skip marionette commands
if marionette.session is not None:
try:
with marionette.using_context(marionette.CONTEXT_CHROME):
rv['screenshot'] = marionette.screenshot()
with marionette.using_context(marionette.CONTEXT_CONTENT):
rv['source'] = marionette.page_source
except Exception:
logger = get_default_logger()
@@ -579,29 +590,30 @@ class BaseMarionetteTestRunner(object):
else:
self.gecko_log = gecko_log
self.results = []
@property
def filename_pattern(self):
if self._filename_pattern is None:
- self._filename_pattern = re.compile("^test(((_.+?)+?\.((py)|(js)))|(([A-Z].*?)+?\.js))$")
+ self._filename_pattern = re.compile(
+ "^test(((_.+?)+?\.((py)|(js)))|(([A-Z].*?)+?\.js))$")
return self._filename_pattern
@property
def testvars(self):
if self._testvars is not None:
return self._testvars
self._testvars = {}
def update(d, u):
- """ Update a dictionary that may contain nested dictionaries. """
+ """Update a dictionary that may contain nested dictionaries."""
for k, v in u.iteritems():
o = d.get(k, {})
if isinstance(v, dict) and isinstance(o, dict):
d[k] = update(d.get(k, {}), v)
else:
d[k] = u[k]
return d
@@ -662,18 +674,17 @@ class BaseMarionetteTestRunner(object):
return self._appName
@property
def bin(self):
return self._bin
@bin.setter
def bin(self, path):
- """
- Set binary and reset parts of runner accordingly
+ """Set binary and reset parts of runner accordingly.
Intended use: to change binary between calls to run_tests
"""
self._bin = path
self.tests = []
self.cleanup()
def reset_test_stats(self):
@@ -708,17 +719,17 @@ class BaseMarionetteTestRunner(object):
'gecko_log': self.gecko_log,
# ensure Marionette class takes care of starting gecko instance
'bin': True,
})
if self.bin:
kwargs.update({
'bin': self.bin,
- })
+ })
if self.emulator:
kwargs.update({
'avd_home': self.extra_kwargs.get('avd_home'),
'adb_path': self.extra_kwargs.get('adb_path'),
'emulator_binary': self.extra_kwargs.get('emulator_bin'),
'avd': self.extra_kwargs.get('avd'),
'package_name': self.extra_kwargs.get('package_name'),
@@ -731,35 +742,36 @@ class BaseMarionetteTestRunner(object):
'port': int(port),
})
if self.emulator:
kwargs.update({
'connect_to_running_emulator': True,
})
if not self.bin and not self.emulator:
try:
- #establish a socket connection so we can vertify the data come back
- connection = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
- connection.connect((host,int(port)))
+ # Establish a socket connection so we can vertify the data come back
+ connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ connection.connect((host, int(port)))
connection.close()
except Exception as e:
exc, val, tb = sys.exc_info()
msg = "Connection attempt to {0}:{1} failed with error: {2}"
raise exc, msg.format(host, port, e), tb
if self.workspace:
kwargs['workspace'] = self.workspace_path
return kwargs
def launch_test_container(self):
if self.marionette.session is None:
self.marionette.start_session()
self.marionette.set_context(self.marionette.CONTEXT_CONTENT)
result = self.marionette.execute_async_script("""
-if((navigator.mozSettings == undefined) || (navigator.mozSettings == null) || (navigator.mozApps == undefined) || (navigator.mozApps == null)) {
+if((navigator.mozSettings == undefined) || (navigator.mozSettings == null) ||
+ (navigator.mozApps == undefined) || (navigator.mozApps == null)) {
marionetteScriptFinished(false);
return;
}
let setReq = navigator.mozSettings.createLock().set({'lockscreen.enabled': false});
setReq.onsuccess = function() {
let appName = 'Test Container';
let activeApp = window.wrappedJSObject.Service.currentApp;
@@ -832,17 +844,18 @@ setReq.onerror = function() {
else:
self.marionette.baseurl = self.server_root
self.logger.info("using remote content from %s" % self.marionette.baseurl)
def _add_tests(self, tests):
for test in tests:
self.add_test(test)
- invalid_tests = [t['filepath'] for t in self.tests if not self._is_filename_valid(t['filepath'])]
+ invalid_tests = [t['filepath'] for t in self.tests
+ if not self._is_filename_valid(t['filepath'])]
if invalid_tests:
raise Exception("Test file names must be of the form "
"'test_something.py', 'test_something.js', or 'testSomething.js'."
" Invalid test names:\n %s"
% '\n '.join(invalid_tests))
def _is_filename_valid(self, filename):
filename = os.path.basename(filename)
@@ -868,34 +881,34 @@ setReq.onerror = function() {
device_info = None
if self.marionette.instance and self.emulator:
try:
device_info = self.marionette.instance.runner.device.dm.getInfo()
except Exception:
self.logger.warning('Could not get device info.')
- #TODO Get version_info in Fennec case
+ # TODO: Get version_info in Fennec case
version_info = None
if self.bin:
version_info = mozversion.get_version(binary=self.bin,
sources=self.sources)
self.logger.info("running with e10s: {}".format(self.e10s))
self.logger.suite_start(self.tests,
version_info=version_info,
device_info=device_info)
self._log_skipped_tests()
interrupted = None
try:
counter = self.repeat
- while counter >=0:
+ while counter >= 0:
round_num = self.repeat - counter
if round_num > 0:
self.logger.info('\nREPEAT %d\n-------' % round_num)
self.run_test_sets()
counter -= 1
except KeyboardInterrupt:
# in case of KeyboardInterrupt during the test execution
# we want to display current test results.
@@ -931,30 +944,31 @@ setReq.onerror = function() {
raise interrupted[0], interrupted[1], interrupted[2]
def _print_summary(self, tests):
self.logger.info('\nSUMMARY\n-------')
self.logger.info('passed: %d' % self.passed)
if self.unexpected_successes == 0:
self.logger.info('failed: %d' % self.failed)
else:
- self.logger.info('failed: %d (unexpected sucesses: %d)' % (self.failed, self.unexpected_successes))
+ self.logger.info('failed: %d (unexpected sucesses: %d)' %
+ (self.failed, self.unexpected_successes))
if self.skipped == 0:
self.logger.info('todo: %d' % self.todo)
else:
self.logger.info('todo: %d (skipped: %d)' % (self.todo, self.skipped))
if self.failed > 0:
self.logger.info('\nFAILED TESTS\n-------')
for failed_test in self.failures:
self.logger.info('%s' % failed_test[0])
def start_httpd(self, need_external_ip):
warnings.warn("start_httpd has been deprecated in favour of create_httpd",
- DeprecationWarning)
+ DeprecationWarning)
self.httpd = self.create_httpd(need_external_ip)
def create_httpd(self, need_external_ip):
host = "127.0.0.1"
if need_external_ip:
host = moznetwork.get_ip()
root = self.server_root or os.path.join(os.path.dirname(here), "www")
rv = httpd.FixtureServer(root, host=host)
@@ -972,39 +986,38 @@ setReq.onerror = function() {
" See --help for details.")
relpath = os.path.relpath(os.path.join(root, filename), filepath)
self.logger.warning(msg_tmpl.format(relpath, filepath))
elif self._is_filename_valid(filename):
test_file = os.path.join(root, filename)
self.add_test(test_file)
return
-
file_ext = os.path.splitext(os.path.split(filepath)[-1])[1]
if file_ext == '.ini':
manifest = TestManifest()
manifest.read(filepath)
filters = []
if self.test_tags:
filters.append(tags(self.test_tags))
- json_path = update_mozinfo(filepath)
+ update_mozinfo(filepath)
self.logger.info("mozinfo updated with the following: {}".format(None))
self.logger.info("mozinfo is: {}".format(mozinfo.info))
manifest_tests = manifest.active_tests(exists=False,
disabled=True,
filters=filters,
app=self.appName,
e10s=self.e10s,
**mozinfo.info)
if len(manifest_tests) == 0:
- self.logger.error("no tests to run using specified "
+ self.logger.error("No tests to run using specified "
"combination of filters: {}".format(
- manifest.fmt_filters()))
+ manifest.fmt_filters()))
target_tests = []
for test in manifest_tests:
if test.get('disabled'):
self.manifest_skipped_tests.append(test)
else:
target_tests.append(test)
@@ -1013,17 +1026,18 @@ setReq.onerror = function() {
raise IOError("test file: %s does not exist" % i["path"])
file_ext = os.path.splitext(os.path.split(i['path'])[-1])[-1]
test_container = None
self.add_test(i["path"], i["expected"], test_container)
return
- self.tests.append({'filepath': filepath, 'expected': expected, 'test_container': test_container})
+ self.tests.append({'filepath': filepath, 'expected': expected,
+ 'test_container': test_container})
def run_test(self, filepath, expected, test_container):
testloader = unittest.TestLoader()
suite = unittest.TestSuite()
self.test_kwargs['expected'] = expected
self.test_kwargs['test_container'] = test_container
mod_name = os.path.splitext(os.path.split(filepath)[-1])[0]
@@ -1051,22 +1065,24 @@ setReq.onerror = function() {
self.results.append(results)
self.failed += len(results.failures) + len(results.errors)
if hasattr(results, 'skipped'):
self.skipped += len(results.skipped)
self.todo += len(results.skipped)
self.passed += results.passed
for failure in results.failures + results.errors:
- self.failures.append((results.getInfo(failure), failure.output, 'TEST-UNEXPECTED-FAIL'))
+ self.failures.append((results.getInfo(failure), failure.output,
+ 'TEST-UNEXPECTED-FAIL'))
if hasattr(results, 'unexpectedSuccesses'):
self.failed += len(results.unexpectedSuccesses)
self.unexpected_successes += len(results.unexpectedSuccesses)
for failure in results.unexpectedSuccesses:
- self.failures.append((results.getInfo(failure), failure.output, 'TEST-UNEXPECTED-PASS'))
+ self.failures.append((results.getInfo(failure), failure.output,
+ 'TEST-UNEXPECTED-PASS'))
if hasattr(results, 'expectedFailures'):
self.todo += len(results.expectedFailures)
self.mixin_run_tests = []
for result in self.results:
result.result_modifiers = []
def run_test_set(self, tests):
--- a/testing/marionette/harness/marionette/runtests.py
+++ b/testing/marionette/harness/marionette/runtests.py
@@ -34,24 +34,25 @@ class MarionetteHarness(object):
testcase_class=MarionetteTestCase,
args=None):
self._runner_class = runner_class
self._parser_class = parser_class
self._testcase_class = testcase_class
self.args = args or self.parse_args()
def parse_args(self, logger_defaults=None):
- parser = self._parser_class(usage='%(prog)s [options] test_file_or_dir <test_file_or_dir> ...')
+ parser = self._parser_class(
+ usage='%(prog)s [options] test_file_or_dir <test_file_or_dir> ...')
parser.add_argument('--version', action='version',
- help="Show version information.",
- version="%(prog)s {version}"
- " (using marionette-driver: {driver_version}, ".format(
- version=__version__,
- driver_version=driver_version
- ))
+ help="Show version information.",
+ version="%(prog)s {version}"
+ " (using marionette-driver: {driver_version}, ".format(
+ version=__version__,
+ driver_version=driver_version
+ ))
mozlog.commandline.add_logging_group(parser)
args = parser.parse_args()
parser.verify_usage(args)
logger = mozlog.commandline.setup_logging(
args.logger_name, args, logger_defaults or {"tbpl": sys.stdout})
args.logger = logger
--- a/tools/lint/flake8.lint
+++ b/tools/lint/flake8.lint
@@ -126,16 +126,17 @@ def lint(files, **lintargs):
LINTER = {
'name': "flake8",
'description': "Python linter",
'include': [
'python/mozlint',
'taskcluster',
'testing/firefox-ui',
'testing/marionette/client',
+ 'testing/marionette/harness',
'testing/puppeteer',
'testing/talos/',
'tools/lint',
],
'exclude': [],
'extensions': EXTENSIONS,
'type': 'external',
'payload': lint,