Bug 1316622 - Remove wait utility dependency on Marionette default timeout; r?whimboo
This was an ugly hack in the first place, and this seems like a good
opportunity to rectify it.
MozReview-Commit-ID: IB6Y8SlOfRn
--- a/testing/marionette/client/marionette_driver/wait.py
+++ b/testing/marionette/client/marionette_driver/wait.py
@@ -7,33 +7,34 @@ import errors
import sys
import time
DEFAULT_TIMEOUT = 5
DEFAULT_INTERVAL = 0.1
class Wait(object):
+
"""An explicit conditional utility class for waiting until a condition
evaluates to true or not null.
This will repeatedly evaluate a condition in anticipation for a
truthy return value, or its timeout to expire, or its waiting
predicate to become true.
A `Wait` instance defines the maximum amount of time to wait for a
condition, as well as the frequency with which to check the
condition. Furthermore, the user may configure the wait to ignore
specific types of exceptions whilst waiting, such as
`errors.NoSuchElementException` when searching for an element on
the page.
"""
- def __init__(self, marionette, timeout=None,
+ def __init__(self, marionette, timeout=DEFAULT_TIMEOUT,
interval=DEFAULT_INTERVAL, ignored_exceptions=None,
clock=None):
"""Configure the Wait instance to have a custom timeout, interval, and
list of ignored exceptions. Optionally a different time
implementation than the one provided by the standard library
(time) can also be provided.
Sample usage::
@@ -43,18 +44,17 @@ class Wait(object):
wait = Wait(marionette, timeout=30, interval=5,
ignored_exceptions=errors.NoSuchWindowException)
window = wait.until(lambda m: m.switch_to_window(42))
:param marionette: The input value to be provided to
conditions, usually a Marionette instance.
:param timeout: How long to wait for the evaluated condition
- to become true. The default timeout is the `timeout`
- property on the `Marionette` object if set, or
+ to become true. The default timeout is
`wait.DEFAULT_TIMEOUT`.
:param interval: How often the condition should be evaluated.
In reality the interval may be greater as the cost of
evaluating the condition function. If that is not the case the
interval for the next condition function call is shortend to keep
the original interval sequence as best as possible.
The default polling interval is `wait.DEFAULT_INTERVAL`.
@@ -67,21 +67,16 @@ class Wait(object):
:param clock: Allows overriding the use of the runtime's
default time library. See `wait.SystemClock` for
implementation details.
"""
self.marionette = marionette
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
exceptions = []
if ignored_exceptions is not None:
if isinstance(ignored_exceptions, collections.Iterable):
exceptions.extend(iter(ignored_exceptions))
@@ -155,16 +150,17 @@ class Wait(object):
cause=last_exc)
def until_pred(clock, end):
return clock.now >= end
class SystemClock(object):
+
def __init__(self):
self._time = time
def sleep(self, duration):
self._time.sleep(duration)
@property
def now(self):
--- a/testing/marionette/harness/marionette/tests/unit/test_wait.py
+++ b/testing/marionette/harness/marionette/tests/unit/test_wait.py
@@ -8,46 +8,50 @@ import time
from marionette_driver import errors
from marionette_driver import wait
from marionette_driver.wait import Wait
from marionette import MarionetteTestCase
class TickingClock(object):
+
def __init__(self, incr=1):
self.ticks = 0
self.increment = incr
def sleep(self, dur=None):
dur = dur if dur is not None else self.increment
self.ticks += dur
@property
def now(self):
return self.ticks
+
class SequenceClock(object):
+
def __init__(self, times):
self.times = times
self.i = 0
@property
def now(self):
if len(self.times) > self.i:
self.i += 1
return self.times[self.i - 1]
def sleep(self, dur):
pass
+
class MockMarionette(object):
+
def __init__(self):
self.waited = 0
- self.timeout = None
def exception(self, e=None, wait=1):
self.wait()
if self.waited == wait:
if e is None:
e = Exception
raise e
@@ -69,40 +73,46 @@ class MockMarionette(object):
self.wait()
if self.waited == wait:
return value
return None
def wait(self):
self.waited += 1
+
def at_third_attempt(clock, end):
return clock.now == 2
+
def now(clock, end):
return True
+
class SystemClockTest(MarionetteTestCase):
+
def setUp(self):
super(SystemClockTest, self).setUp()
self.clock = wait.SystemClock()
def test_construction_initializes_time(self):
self.assertEqual(self.clock._time, time)
def test_sleep(self):
start = time.time()
self.clock.sleep(0.1)
end = time.time() - start
self.assertGreater(end, 0)
def test_time_now(self):
self.assertIsNotNone(self.clock.now)
+
class FormalWaitTest(MarionetteTestCase):
+
def setUp(self):
super(FormalWaitTest, self).setUp()
self.m = MockMarionette()
self.m.timeout = 123
def test_construction_with_custom_timeout(self):
wt = Wait(self.m, timeout=42)
self.assertEqual(wt.timeout, 42)
@@ -153,32 +163,32 @@ class FormalWaitTest(MarionetteTestCase)
def test_marionette_property(self):
wt = Wait(self.m)
self.assertEqual(wt.marionette, self.m)
def test_clock_property(self):
wt = Wait(self.m)
self.assertIsInstance(wt.clock, wait.SystemClock)
- def test_timeout_inherited_from_marionette(self):
- wt = Wait(self.m)
- self.assertEqual(wt.timeout * 1000.0, self.m.timeout)
-
def test_timeout_uses_default_if_marionette_timeout_is_none(self):
self.m.timeout = None
wt = Wait(self.m)
self.assertEqual(wt.timeout, wait.DEFAULT_TIMEOUT)
+
class PredicatesTest(MarionetteTestCase):
+
def test_until(self):
c = wait.SystemClock()
self.assertFalse(wait.until_pred(c, sys.maxint))
self.assertTrue(wait.until_pred(c, 0))
+
class WaitUntilTest(MarionetteTestCase):
+
def setUp(self):
super(WaitUntilTest, self).setUp()
self.m = MockMarionette()
self.clock = TickingClock()
self.wt = Wait(self.m, timeout=10, interval=1, clock=self.clock)
def test_true(self):
@@ -270,28 +280,30 @@ class WaitUntilTest(MarionetteTestCase):
def test_timeout_elapsed_interval_by_delayed_condition_return(self):
def callback(mn):
self.clock.sleep(11)
return mn.false()
with self.assertRaisesRegexp(errors.TimeoutException,
"Timed out after 11.0 seconds"):
self.wt.until(callback)
- # With a delayed conditional return > timeout, only 1 iteration is possible
+ # With a delayed conditional return > timeout, only 1 iteration is
+ # possible
self.assertEqual(self.m.waited, 1)
def test_timeout_with_delayed_condition_return(self):
def callback(mn):
self.clock.sleep(.5)
return mn.false()
with self.assertRaisesRegexp(errors.TimeoutException,
"Timed out after 10.0 seconds"):
self.wt.until(callback)
- # With a delayed conditional return < interval, 10 iterations should be possible
+ # With a delayed conditional return < interval, 10 iterations should be
+ # possible
self.assertEqual(self.m.waited, 10)
def test_timeout_interval_shorter_than_delayed_condition_return(self):
def callback(mn):
self.clock.sleep(2)
return mn.false()
with self.assertRaisesRegexp(errors.TimeoutException,