diff options
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.py | 227 |
1 files changed, 227 insertions, 0 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 new file mode 100644 index 0000000..ffbe081 --- /dev/null +++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/manager_worker_broker_unittest.py @@ -0,0 +1,227 @@ +# Copyright (C) 2010 Google Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import optparse +import Queue +import sys +import unittest + +try: + import multiprocessing +except ImportError: + multiprocessing = None + + +from webkitpy.common.system import outputcapture + +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 + + +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 + + def handle_stop(self, src): + self._stopped = True + + def handle_test(self, src, an_int, a_str): + assert an_int == 1 + assert a_str == "hello, world" + self._broker_connection.post_message('test', 2, 'hi, everybody') + + def is_done(self): + return self._stopped + + def name(self): + return self._name + + def start(self): + pass + + def run(self, port): + try: + self._broker_connection.run_message_loop() + self._broker_connection.yield_to_broker() + self._broker_connection.post_message('done') + except Exception, e: + self._broker_connection.post_message('exception', (type(e), str(e), None)) + + +def get_options(worker_model): + option_list = manager_worker_broker.runtime_options() + parser = optparse.OptionParser(option_list=option_list) + options, args = parser.parse_args(args=['--worker-model', 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): + self.assertTrue(make_broker(self, 'inline') is not None) + + def test_get__threads(self): + self.assertTrue(make_broker(self, 'threads') is not None) + + def test_get__processes(self): + if multiprocessing: + self.assertTrue(make_broker(self, 'processes') is not None) + else: + self.assertRaises(ValueError, make_broker, self, 'processes') + + def test_get__unknown(self): + self.assertRaises(ValueError, make_broker, self, 'unknown') + + +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 + + def handle_test(self, src, an_int, a_str): + self._an_int = an_int + self._a_str = a_str + + def handle_exception(self, src, exc_info): + self._exception = exc_info + self._done = True + + # + # Testing helper methods + # + def setUp(self): + self._an_int = None + self._a_str = None + self._broker = None + self._done = False + self._exception = None + self._worker_model = None + + def make_broker(self): + self._broker = make_broker(self, self._worker_model) + + # + # 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() + self.assertTrue(self.is_done()) + self.assertEqual(self._an_int, 2) + self.assertEqual(self._a_str, 'hi, everybody') + + 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() + + self.assertTrue(self.is_done()) + self.assertEquals(self._exception[0], ValueError) + self.assertEquals(self._exception[1], + "TestWorker/0: received message 'unknown' it couldn't handle") + + +class InlineBrokerTests(_TestsMixin, unittest.TestCase): + def setUp(self): + _TestsMixin.setUp(self) + self._worker_model = 'inline' + + +class MultiProcessBrokerTests(_TestsMixin, unittest.TestCase): + def setUp(self): + _TestsMixin.setUp(self) + if multiprocessing: + self._worker_model = 'processes' + else: + self._worker_model = None + + def queue(self): + return multiprocessing.Queue() + + +class ThreadedBrokerTests(_TestsMixin, unittest.TestCase): + def setUp(self): + _TestsMixin.setUp(self) + self._worker_model = 'threads' + + +class FunctionsTest(unittest.TestCase): + def test_runtime_options(self): + option_list = manager_worker_broker.runtime_options() + parser = optparse.OptionParser(option_list=option_list) + options, args = parser.parse_args([]) + self.assertTrue(options) + + +class InterfaceTest(unittest.TestCase): + # These tests mostly exist to pacify coverage. + + # FIXME: There must be a better way to do this and also verify + # that classes do implement every abstract method in an interface. + def test_managerconnection_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._ManagerConnection(broker._broker, None, self, None) + self.assertRaises(NotImplementedError, obj.start_worker, 0) + + +if __name__ == '__main__': + unittest.main() |