summaryrefslogtreecommitdiffstats
path: root/Tools/Scripts/webkitpy/layout_tests/layout_package/manager_worker_broker_unittest.py
diff options
context:
space:
mode:
Diffstat (limited to 'Tools/Scripts/webkitpy/layout_tests/layout_package/manager_worker_broker_unittest.py')
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/manager_worker_broker_unittest.py128
1 files changed, 93 insertions, 35 deletions
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/manager_worker_broker_unittest.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/manager_worker_broker_unittest.py
index ffbe081..c32f880 100644
--- a/Tools/Scripts/webkitpy/layout_tests/layout_package/manager_worker_broker_unittest.py
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/manager_worker_broker_unittest.py
@@ -43,14 +43,34 @@ from webkitpy.layout_tests import port
from webkitpy.layout_tests.layout_package import manager_worker_broker
from webkitpy.layout_tests.layout_package import message_broker2
+# In order to reliably control when child workers are starting and stopping,
+# we use a pair of global variables to hold queues used for messaging. Ideally
+# we wouldn't need globals, but we can't pass these through a lexical closure
+# because those can't be Pickled and sent to a subprocess, and we'd prefer not
+# to have to pass extra arguments to the worker in the start_worker() call.
+starting_queue = None
+stopping_queue = None
+
+
+def make_broker(manager, worker_model, start_queue=None, stop_queue=None):
+ global starting_queue
+ global stopping_queue
+ starting_queue = start_queue
+ stopping_queue = stop_queue
+ options = get_options(worker_model)
+ return manager_worker_broker.get(port.get("test"), options, manager, _TestWorker)
+
-class TestWorker(manager_worker_broker.AbstractWorker):
+class _TestWorker(manager_worker_broker.AbstractWorker):
def __init__(self, broker_connection, worker_number, options):
self._broker_connection = broker_connection
self._options = options
self._worker_number = worker_number
self._name = 'TestWorker/%d' % worker_number
self._stopped = False
+ self._canceled = False
+ self._starting_queue = starting_queue
+ self._stopping_queue = stopping_queue
def handle_stop(self, src):
self._stopped = True
@@ -61,15 +81,20 @@ class TestWorker(manager_worker_broker.AbstractWorker):
self._broker_connection.post_message('test', 2, 'hi, everybody')
def is_done(self):
- return self._stopped
+ return self._stopped or self._canceled
def name(self):
return self._name
- def start(self):
- pass
+ def cancel(self):
+ self._canceled = True
def run(self, port):
+ if self._starting_queue:
+ self._starting_queue.put('')
+
+ if self._stopping_queue:
+ self._stopping_queue.get()
try:
self._broker_connection.run_message_loop()
self._broker_connection.yield_to_broker()
@@ -85,11 +110,6 @@ def get_options(worker_model):
return options
-def make_broker(manager, worker_model):
- options = get_options(worker_model)
- return manager_worker_broker.get(port.get("test"), options, manager,
- TestWorker)
-
class FunctionTests(unittest.TestCase):
def test_get__inline(self):
@@ -99,6 +119,10 @@ class FunctionTests(unittest.TestCase):
self.assertTrue(make_broker(self, 'threads') is not None)
def test_get__processes(self):
+ # This test sometimes fails on Windows. See <http://webkit.org/b/55087>.
+ if sys.platform in ('cygwin', 'win32'):
+ return
+
if multiprocessing:
self.assertTrue(make_broker(self, 'processes') is not None)
else:
@@ -112,18 +136,12 @@ class _TestsMixin(object):
"""Mixin class that implements a series of tests to enforce the
contract all implementations must follow."""
- #
- # Methods to implement the Manager side of the ClientInterface
- #
def name(self):
return 'Tester'
def is_done(self):
return self._done
- #
- # Handlers for the messages the TestWorker may send.
- #
def handle_done(self, src):
self._done = True
@@ -135,9 +153,6 @@ class _TestsMixin(object):
self._exception = exc_info
self._done = True
- #
- # Testing helper methods
- #
def setUp(self):
self._an_int = None
self._a_str = None
@@ -146,33 +161,58 @@ class _TestsMixin(object):
self._exception = None
self._worker_model = None
- def make_broker(self):
- self._broker = make_broker(self, self._worker_model)
+ def make_broker(self, starting_queue=None, stopping_queue=None):
+ self._broker = make_broker(self, self._worker_model, starting_queue,
+ stopping_queue)
+
+ def test_cancel(self):
+ self.make_broker()
+ worker = self._broker.start_worker(0)
+ worker.cancel()
+ self._broker.post_message('test', 1, 'hello, world')
+ worker.join(0.5)
+ self.assertFalse(worker.is_alive())
- #
- # Actual unit tests
- #
def test_done(self):
- if not self._worker_model:
- return
self.make_broker()
worker = self._broker.start_worker(0)
self._broker.post_message('test', 1, 'hello, world')
self._broker.post_message('stop')
self._broker.run_message_loop()
+ worker.join(0.5)
+ self.assertFalse(worker.is_alive())
self.assertTrue(self.is_done())
self.assertEqual(self._an_int, 2)
self.assertEqual(self._a_str, 'hi, everybody')
+ def test_log_wedged_worker(self):
+ starting_queue = self.queue()
+ stopping_queue = self.queue()
+ self.make_broker(starting_queue, stopping_queue)
+ oc = outputcapture.OutputCapture()
+ oc.capture_output()
+ try:
+ worker = self._broker.start_worker(0)
+ starting_queue.get()
+ worker.log_wedged_worker('test_name')
+ stopping_queue.put('')
+ self._broker.post_message('stop')
+ self._broker.run_message_loop()
+ worker.join(0.5)
+ self.assertFalse(worker.is_alive())
+ self.assertTrue(self.is_done())
+ finally:
+ oc.restore_output()
+
def test_unknown_message(self):
- if not self._worker_model:
- return
self.make_broker()
worker = self._broker.start_worker(0)
self._broker.post_message('unknown')
self._broker.run_message_loop()
+ worker.join(0.5)
self.assertTrue(self.is_done())
+ self.assertFalse(worker.is_alive())
self.assertEquals(self._exception[0], ValueError)
self.assertEquals(self._exception[1],
"TestWorker/0: received message 'unknown' it couldn't handle")
@@ -183,17 +223,22 @@ class InlineBrokerTests(_TestsMixin, unittest.TestCase):
_TestsMixin.setUp(self)
self._worker_model = 'inline'
+ def test_log_wedged_worker(self):
+ self.make_broker()
+ worker = self._broker.start_worker(0)
+ self.assertRaises(AssertionError, worker.log_wedged_worker, None)
-class MultiProcessBrokerTests(_TestsMixin, unittest.TestCase):
- def setUp(self):
- _TestsMixin.setUp(self)
- if multiprocessing:
+
+# FIXME: https://bugs.webkit.org/show_bug.cgi?id=54520.
+if multiprocessing and sys.platform not in ('cygwin', 'win32'):
+
+ class MultiProcessBrokerTests(_TestsMixin, unittest.TestCase):
+ def setUp(self):
+ _TestsMixin.setUp(self)
self._worker_model = 'processes'
- else:
- self._worker_model = None
- def queue(self):
- return multiprocessing.Queue()
+ def queue(self):
+ return multiprocessing.Queue()
class ThreadedBrokerTests(_TestsMixin, unittest.TestCase):
@@ -201,6 +246,9 @@ class ThreadedBrokerTests(_TestsMixin, unittest.TestCase):
_TestsMixin.setUp(self)
self._worker_model = 'threads'
+ def queue(self):
+ return Queue.Queue()
+
class FunctionsTest(unittest.TestCase):
def test_runtime_options(self):
@@ -222,6 +270,16 @@ class InterfaceTest(unittest.TestCase):
obj = manager_worker_broker._ManagerConnection(broker._broker, None, self, None)
self.assertRaises(NotImplementedError, obj.start_worker, 0)
+ def test_workerconnection_is_abstract(self):
+ # Test that all the base class methods are abstract and have the
+ # signature we expect.
+ broker = make_broker(self, 'inline')
+ obj = manager_worker_broker._WorkerConnection(broker._broker, _TestWorker, 0, None)
+ self.assertRaises(NotImplementedError, obj.cancel)
+ self.assertRaises(NotImplementedError, obj.is_alive)
+ self.assertRaises(NotImplementedError, obj.join, None)
+ self.assertRaises(NotImplementedError, obj.log_wedged_worker, None)
+
if __name__ == '__main__':
unittest.main()