2011-02-11 Dirk Pranke <dpranke@chromium.org>
[WebKit-https.git] / Tools / Scripts / webkitpy / layout_tests / layout_package / manager_worker_broker_unittest.py
1 # Copyright (C) 2010 Google Inc. All rights reserved.
2 #
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions are
5 # met:
6 #
7 #     * Redistributions of source code must retain the above copyright
8 # notice, this list of conditions and the following disclaimer.
9 #     * Redistributions in binary form must reproduce the above
10 # copyright notice, this list of conditions and the following disclaimer
11 # in the documentation and/or other materials provided with the
12 # distribution.
13 #     * Neither the name of Google Inc. nor the names of its
14 # contributors may be used to endorse or promote products derived from
15 # this software without specific prior written permission.
16 #
17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29 import optparse
30 import Queue
31 import sys
32 import unittest
33
34 try:
35     import multiprocessing
36 except ImportError:
37     multiprocessing = None
38
39
40 from webkitpy.common.system import outputcapture
41
42 from webkitpy.layout_tests import port
43 from webkitpy.layout_tests.layout_package import manager_worker_broker
44 from webkitpy.layout_tests.layout_package import message_broker2
45
46
47 class TestWorker(manager_worker_broker.AbstractWorker):
48     def __init__(self, broker_connection, worker_number, options):
49         self._broker_connection = broker_connection
50         self._options = options
51         self._worker_number = worker_number
52         self._name = 'TestWorker/%d' % worker_number
53         self._stopped = False
54
55     def handle_stop(self, src):
56         self._stopped = True
57
58     def handle_test(self, src, an_int, a_str):
59         assert an_int == 1
60         assert a_str == "hello, world"
61         self._broker_connection.post_message('test', 2, 'hi, everybody')
62
63     def is_done(self):
64         return self._stopped
65
66     def name(self):
67         return self._name
68
69     def start(self):
70         pass
71
72     def run(self, port):
73         try:
74             self._broker_connection.run_message_loop()
75             self._broker_connection.yield_to_broker()
76             self._broker_connection.post_message('done')
77         except Exception, e:
78             self._broker_connection.post_message('exception', (type(e), str(e), None))
79
80
81 def get_options(worker_model):
82     option_list = manager_worker_broker.runtime_options()
83     parser = optparse.OptionParser(option_list=option_list)
84     options, args = parser.parse_args(args=['--worker-model', worker_model])
85     return options
86
87
88 def make_broker(manager, worker_model):
89     options = get_options(worker_model)
90     return manager_worker_broker.get(port.get("test"), options, manager,
91                                      TestWorker)
92
93
94 class FunctionTests(unittest.TestCase):
95     def test_get__inline(self):
96         self.assertTrue(make_broker(self, 'inline') is not None)
97
98     def test_get__threads(self):
99         self.assertTrue(make_broker(self, 'threads') is not None)
100
101     def test_get__processes(self):
102         if multiprocessing:
103             self.assertTrue(make_broker(self, 'processes') is not None)
104         else:
105             self.assertRaises(ValueError, make_broker, self, 'processes')
106
107     def test_get__unknown(self):
108         self.assertRaises(ValueError, make_broker, self, 'unknown')
109
110
111 class _TestsMixin(object):
112     """Mixin class that implements a series of tests to enforce the
113     contract all implementations must follow."""
114
115     #
116     # Methods to implement the Manager side of the ClientInterface
117     #
118     def name(self):
119         return 'Tester'
120
121     def is_done(self):
122         return self._done
123
124     #
125     # Handlers for the messages the TestWorker may send.
126     #
127     def handle_done(self, src):
128         self._done = True
129
130     def handle_test(self, src, an_int, a_str):
131         self._an_int = an_int
132         self._a_str = a_str
133
134     def handle_exception(self, src, exc_info):
135         self._exception = exc_info
136         self._done = True
137
138     #
139     # Testing helper methods
140     #
141     def setUp(self):
142         self._an_int = None
143         self._a_str = None
144         self._broker = None
145         self._done = False
146         self._exception = None
147         self._worker_model = None
148
149     def make_broker(self):
150         self._broker = make_broker(self, self._worker_model)
151
152     #
153     # Actual unit tests
154     #
155     def test_done(self):
156         if not self._worker_model:
157             return
158         self.make_broker()
159         worker = self._broker.start_worker(0)
160         self._broker.post_message('test', 1, 'hello, world')
161         self._broker.post_message('stop')
162         self._broker.run_message_loop()
163         self.assertTrue(self.is_done())
164         self.assertEqual(self._an_int, 2)
165         self.assertEqual(self._a_str, 'hi, everybody')
166
167     def test_unknown_message(self):
168         if not self._worker_model:
169             return
170         self.make_broker()
171         worker = self._broker.start_worker(0)
172         self._broker.post_message('unknown')
173         self._broker.run_message_loop()
174
175         self.assertTrue(self.is_done())
176         self.assertEquals(self._exception[0], ValueError)
177         self.assertEquals(self._exception[1],
178             "TestWorker/0: received message 'unknown' it couldn't handle")
179
180
181 class InlineBrokerTests(_TestsMixin, unittest.TestCase):
182     def setUp(self):
183         _TestsMixin.setUp(self)
184         self._worker_model = 'inline'
185
186
187 class MultiProcessBrokerTests(_TestsMixin, unittest.TestCase):
188     def setUp(self):
189         _TestsMixin.setUp(self)
190         if multiprocessing:
191             self._worker_model = 'processes'
192         else:
193             self._worker_model = None
194
195     def queue(self):
196         return multiprocessing.Queue()
197
198
199 class ThreadedBrokerTests(_TestsMixin, unittest.TestCase):
200     def setUp(self):
201         _TestsMixin.setUp(self)
202         self._worker_model = 'threads'
203
204
205 class FunctionsTest(unittest.TestCase):
206     def test_runtime_options(self):
207         option_list = manager_worker_broker.runtime_options()
208         parser = optparse.OptionParser(option_list=option_list)
209         options, args = parser.parse_args([])
210         self.assertTrue(options)
211
212
213 class InterfaceTest(unittest.TestCase):
214     # These tests mostly exist to pacify coverage.
215
216     # FIXME: There must be a better way to do this and also verify
217     # that classes do implement every abstract method in an interface.
218     def test_managerconnection_is_abstract(self):
219         # Test that all the base class methods are abstract and have the
220         # signature we expect.
221         broker = make_broker(self, 'inline')
222         obj = manager_worker_broker._ManagerConnection(broker._broker, None, self, None)
223         self.assertRaises(NotImplementedError, obj.start_worker, 0)
224
225
226 if __name__ == '__main__':
227     unittest.main()