Bug 1316622 - New timeouts inteface in Marionette Python client; r=automatedtester

Introduce a new interface for managing timeouts in the Marionette
Python client.

MozReview-Commit-ID: JHojs7rWBz5

--HG--
extra : rebase_source : 388b8b3f30f07b95bf40edc57d13ffe5a7d5c502
This commit is contained in:
Andreas Tolfsen 2016-11-10 21:00:23 +00:00
Родитель 0db3d11874
Коммит 57db3d8819
4 изменённых файлов: 140 добавлений и 43 удалений

Просмотреть файл

@ -17,18 +17,18 @@ from contextlib import contextmanager
from decorators import do_process_check
from keys import Keys
import geckoinstance
import errors
import geckoinstance
import transport
from timeout import Timeouts
WEBELEMENT_KEY = "ELEMENT"
W3C_WEBELEMENT_KEY = "element-6066-11e4-a52e-4f735466cecf"
class HTMLElement(object):
"""
Represents a DOM Element.
"""
"""Represents a DOM Element."""
def __init__(self, marionette, id):
self.marionette = marionette
@ -537,31 +537,44 @@ class Alert(object):
class Marionette(object):
"""Represents a Marionette connection to a browser or device."""
CONTEXT_CHROME = 'chrome' # non-browser content: windows, dialogs, etc.
CONTEXT_CONTENT = 'content' # browser content: iframes, divs, etc.
CONTEXT_CHROME = "chrome" # non-browser content: windows, dialogs, etc.
CONTEXT_CONTENT = "content" # browser content: iframes, divs, etc.
DEFAULT_SOCKET_TIMEOUT = 60
DEFAULT_STARTUP_TIMEOUT = 120
DEFAULT_SHUTDOWN_TIMEOUT = 65 # Firefox will kill hanging threads after 60s
def __init__(self, host='localhost', port=2828, app=None, bin=None,
def __init__(self, host="localhost", port=2828, app=None, bin=None,
baseurl=None, timeout=None, socket_timeout=DEFAULT_SOCKET_TIMEOUT,
startup_timeout=None, **instance_args):
"""
:param host: address for Marionette connection
:param port: integer port for Marionette connection
:param baseurl: where to look for files served from Marionette's www directory
:param startup_timeout: seconds to wait for a connection with binary
:param timeout: time to wait for page load, scripts, search
:param socket_timeout: timeout for Marionette socket operations
:param bin: path to app binary; if any truthy value is given this will
attempt to start a gecko instance with the specified `app`
:param app: type of instance_class to use for managing app instance.
See marionette_driver.geckoinstance
:param instance_args: args to pass to instance_class
"""Construct a holder for the Marionette connection.
Remember to call ``start_session`` in order to initiate the
connection and start a Marionette session.
:param host: Host where the Marionette server listens.
Defaults to localhost.
:param port: Port where the Marionette server listens.
Defaults to port 2828.
:param baseurl: Where to look for files served from Marionette's
www directory.
:param timeout: Dictionary of default page load, script, and
implicit wait timeouts. Timeouts in the session are reset
to these values whenever ``reset_timeouts`` is called.
:param socket_timeout: Timeout for Marionette socket operations.
:param startup_timeout: Seconds to wait for a connection with
binary.
:param bin: Path to browser binary. If any truthy value is given
this will attempt to start a Gecko instance with the specified
`app`.
:param app: Type of ``instance_class`` to use for managing app
instance. See ``marionette_driver.geckoinstance``.
:param instance_args: Arguments to pass to ``instance_class``.
"""
self.host = host
self.port = self.local_port = int(port)
self.bin = bin
self.default_timeouts = timeout
self.instance = None
self.session = None
self.session_id = None
@ -569,7 +582,6 @@ class Marionette(object):
self.chrome_window = None
self.baseurl = baseurl
self._test_name = None
self.timeout = timeout
self.socket_timeout = socket_timeout
self.crashed = 0
@ -579,6 +591,8 @@ class Marionette(object):
self.instance.start()
self.raise_for_port(timeout=startup_timeout)
self.timeout = Timeouts(self)
def _create_instance(self, app, instance_args):
if not Marionette.is_port_available(self.port, host=self.host):
ex_msg = "{0}:{1} is unavailable.".format(self.host, self.port)
@ -751,21 +765,20 @@ class Marionette(object):
raise errors.lookup(error)(message, stacktrace=stacktrace)
def reset_timeouts(self):
"""Resets timeouts to their defaults to the `self.timeout`
attribute. If unset, only the page load timeout is reset to
30 seconds.
"""Resets timeouts to their defaults to the
`self.default_timeouts` attribute. If unset, only the page load
timeout is reset to 30 seconds.
"""
setters = {"search": "implicit",
"script": "script",
"page load": "page_load"}
timeout_types = {"search": self.set_search_timeout,
"script": self.set_script_timeout,
"page load": self.set_page_load_timeout}
if self.timeout is not None:
for typ, ms in self.timeout:
timeout_types[typ](ms)
if self.default_timeouts is not None:
for typ, ms in self.default_timeouts:
setattr(self.timeout, setters[typ], ms)
else:
self.set_page_load_timeout(30000)
self.timeout.page_load = 30
def check_for_crash(self):
"""Check if the process crashed.
@ -1813,7 +1826,7 @@ class Marionette(object):
::
marionette.set_script_timeout(10000) # set timeout period of 10 seconds
marionette.timeout.script = 10
result = self.marionette.execute_async_script('''
// this script waits 5 seconds, and then returns the number 1
setTimeout(function() {
@ -1843,7 +1856,7 @@ class Marionette(object):
An HTMLElement instance may be used to call other methods on the
element, such as click(). If no element is immediately found, the
attempt to locate an element will be repeated for up to the amount of
time set by set_search_timeout(). If multiple elements match the given
time set by ``timeout.implicit``. If multiple elements match the given
criteria, only the first is returned. If no element matches, a
NoSuchElementException will be raised.
@ -1870,7 +1883,7 @@ class Marionette(object):
An HTMLElement instance may be used to call other methods on the
element, such as click(). If no element is immediately found,
the attempt to locate an element will be repeated for up to the
amount of time set by set_search_timeout().
amount of time set by ``timeout.implicit``.
:param method: The method to use to locate the elements; one
of: "id", "name", "class name", "tag name", "css selector",

Просмотреть файл

@ -0,0 +1,87 @@
# 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 errors
class Timeouts(object):
"""Manage timeout settings in the Marionette session.
Usage::
marionette = Marionette(...)
marionette.start_session()
marionette.timeout.page_load = 10
marionette.timeout.page_load
# => 10
"""
def __init__(self, marionette):
self._marionette = marionette
def _set(self, name, sec):
ms = sec * 1000
try:
self._marionette._send_message("setTimeouts", {name: ms})
except errors.UnknownCommandException:
# remove when 55 is stable
self._marionette._send_message("timeouts", {"type": name, "ms": ms})
def _get(self, name):
ms = self._marionette._send_message("getTimeouts", key=name)
return ms / 1000
@property
def script(self):
"""Get the session's script timeout. This specifies the time
to wait for injected scripts to finished before interrupting
them. It is by default 30 seconds.
"""
return self._get("script")
@script.setter
def script(self, sec):
"""Set the session's script timeout. This specifies the time
to wait for injected scripts to finish before interrupting them.
"""
self._set("script", sec)
@property
def page_load(self):
"""Get the session's page load timeout. This specifies the time
to wait for the page loading to complete. It is by default 5
minutes (or 300 seconds).
"""
return self._get("page load")
@page_load.setter
def page_load(self, sec):
"""Set the session's page load timeout. This specifies the time
to wait for the page loading to complete.
"""
self._set("page load", sec)
@property
def implicit(self):
"""Get the session's implicit wait timeout. This specifies the
time to wait for the implicit element location strategy when
retrieving elements. It is by default disabled (0 seconds).
"""
return self._get("implicit")
@implicit.setter
def implicit(self, sec):
"""Set the session's implicit wait timeout. This specifies the
time to wait for the implicit element location strategy when
retrieving elements.
"""
self._set("implicit", sec)

Просмотреть файл

@ -71,8 +71,12 @@ class Wait(object):
"""
self.marionette = marionette
self.timeout = timeout or (self.marionette.timeout and
self.marionette.timeout / 1000.0) or DEFAULT_TIMEOUT
self.timeout = timeout
if self.timeout is None:
if self.marionette.default_timeouts is not None:
self.timeout = self.marionette.default_timeouts.get("search")
else:
self.timeout = DEFAULT_TIMEOUT
self.clock = clock or SystemClock()
self.end = self.clock.now + self.timeout
self.interval = interval

Просмотреть файл

@ -68,13 +68,6 @@ class TestTimeouts(MarionetteTestCase):
setTimeout(function() { callback(true); }, 500);
"""))
def test_invalid_timeout_types(self):
for val in [3.14, True, [], {}, "foo"]:
print "testing %s" % type(val)
self.assertRaises(InvalidArgumentException, self.marionette.set_search_timeout, val)
self.assertRaises(InvalidArgumentException, self.marionette.set_script_timeout, val)
self.assertRaises(InvalidArgumentException, self.marionette.set_page_load_timeout, val)
def test_compat_input_types(self):
# When using the spec-incompatible input format which we have
# for backwards compatibility, it should be possible to send ms