summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJair Gonzalez <jair.de.jesus.gonzalez.plascencia@linux.intel.com>2017-01-20 15:59:09 -0600
committerRichard Purdie <richard.purdie@linuxfoundation.org>2017-06-23 14:14:17 +0100
commitdf051ba9a2a187e25b821ca2cda6459ad0d251ce (patch)
tree7400c9f9c1b414fc236fc85e49140971c2667802
parentd591b00af06abd197904902baed3a6d2fcb5dbc6 (diff)
downloadpoky-df051ba9a2a187e25b821ca2cda6459ad0d251ce.tar.gz
bitbake: tests: create unit tests for event module
This change adds a new unit test module (bb.tests.event) for bitbake event. It includes the following items: - Client and server stubs setup - Testing the module's main functions including: - get_class_handlers - set_class_handlers - clean_class_handlers - enable_threadlock - disable_threadlock - get_handlers - set_handlers - execute_handler - fire_class_handlers - print_ui_queue - fire_ui_handlers - fire - fire_from_worker - register - remove - register_UIHhandler - unregister_UIHhandler - Testing event handling using: - class Event(object) - class OperationStarted(Event) - class OperationCompleted(Event) - class OperationProgress(Event) - class ConfigParsed(Event) [YOCTO #10368] (Bitbake rev: 0be3ad391adc73cc0dff81bd0ed7874f2c6a00be) Signed-off-by: Jair Gonzalez <jair.de.jesus.gonzalez.plascencia@linux.intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r--bitbake/lib/bb/tests/event.py377
1 files changed, 377 insertions, 0 deletions
diff --git a/bitbake/lib/bb/tests/event.py b/bitbake/lib/bb/tests/event.py
new file mode 100644
index 0000000000..c7eb1fe44c
--- /dev/null
+++ b/bitbake/lib/bb/tests/event.py
@@ -0,0 +1,377 @@
1# ex:ts=4:sw=4:sts=4:et
2# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
3#
4# BitBake Tests for the Event implementation (event.py)
5#
6# Copyright (C) 2017 Intel Corporation
7#
8# This program is free software; you can redistribute it and/or modify
9# it under the terms of the GNU General Public License version 2 as
10# published by the Free Software Foundation.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License along
18# with this program; if not, write to the Free Software Foundation, Inc.,
19# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20#
21
22import unittest
23import bb
24import logging
25import bb.compat
26import bb.event
27import importlib
28import threading
29import time
30import pickle
31from unittest.mock import Mock
32from unittest.mock import call
33
34
35class EventQueueStub():
36 """ Class used as specification for UI event handler queue stub objects """
37 def __init__(self):
38 return
39
40 def send(self, event):
41 return
42
43
44class PickleEventQueueStub():
45 """ Class used as specification for UI event handler queue stub objects
46 with sendpickle method """
47 def __init__(self):
48 return
49
50 def sendpickle(self, pickled_event):
51 return
52
53
54class UIClientStub():
55 """ Class used as specification for UI event handler stub objects """
56 def __init__(self):
57 self.event = None
58
59
60class EventHandlingTest(unittest.TestCase):
61 """ Event handling test class """
62 _threadlock_test_calls = []
63
64 def setUp(self):
65 self._test_process = Mock()
66 ui_client1 = UIClientStub()
67 ui_client2 = UIClientStub()
68 self._test_ui1 = Mock(wraps=ui_client1)
69 self._test_ui2 = Mock(wraps=ui_client2)
70 importlib.reload(bb.event)
71
72 def _create_test_handlers(self):
73 """ Method used to create a test handler ordered dictionary """
74 test_handlers = bb.compat.OrderedDict()
75 test_handlers["handler1"] = self._test_process.handler1
76 test_handlers["handler2"] = self._test_process.handler2
77 return test_handlers
78
79 def test_class_handlers(self):
80 """ Test set_class_handlers and get_class_handlers methods """
81 test_handlers = self._create_test_handlers()
82 bb.event.set_class_handlers(test_handlers)
83 self.assertEqual(test_handlers,
84 bb.event.get_class_handlers())
85
86 def test_handlers(self):
87 """ Test set_handlers and get_handlers """
88 test_handlers = self._create_test_handlers()
89 bb.event.set_handlers(test_handlers)
90 self.assertEqual(test_handlers,
91 bb.event.get_handlers())
92
93 def test_clean_class_handlers(self):
94 """ Test clean_class_handlers method """
95 cleanDict = bb.compat.OrderedDict()
96 self.assertEqual(cleanDict,
97 bb.event.clean_class_handlers())
98
99 def test_register(self):
100 """ Test register method for class handlers """
101 result = bb.event.register("handler", self._test_process.handler)
102 self.assertEqual(result, bb.event.Registered)
103 handlers_dict = bb.event.get_class_handlers()
104 self.assertIn("handler", handlers_dict)
105
106 def test_already_registered(self):
107 """ Test detection of an already registed class handler """
108 bb.event.register("handler", self._test_process.handler)
109 handlers_dict = bb.event.get_class_handlers()
110 self.assertIn("handler", handlers_dict)
111 result = bb.event.register("handler", self._test_process.handler)
112 self.assertEqual(result, bb.event.AlreadyRegistered)
113
114 def test_register_from_string(self):
115 """ Test register method receiving code in string """
116 result = bb.event.register("string_handler", " return True")
117 self.assertEqual(result, bb.event.Registered)
118 handlers_dict = bb.event.get_class_handlers()
119 self.assertIn("string_handler", handlers_dict)
120
121 def test_register_with_mask(self):
122 """ Test register method with event masking """
123 mask = ["bb.event.OperationStarted",
124 "bb.event.OperationCompleted"]
125 result = bb.event.register("event_handler",
126 self._test_process.event_handler,
127 mask)
128 self.assertEqual(result, bb.event.Registered)
129 handlers_dict = bb.event.get_class_handlers()
130 self.assertIn("event_handler", handlers_dict)
131
132 def test_remove(self):
133 """ Test remove method for class handlers """
134 test_handlers = self._create_test_handlers()
135 bb.event.set_class_handlers(test_handlers)
136 count = len(test_handlers)
137 bb.event.remove("handler1", None)
138 test_handlers = bb.event.get_class_handlers()
139 self.assertEqual(len(test_handlers), count - 1)
140 with self.assertRaises(KeyError):
141 bb.event.remove("handler1", None)
142
143 def test_execute_handler(self):
144 """ Test execute_handler method for class handlers """
145 mask = ["bb.event.OperationProgress"]
146 result = bb.event.register("event_handler",
147 self._test_process.event_handler,
148 mask)
149 self.assertEqual(result, bb.event.Registered)
150 event = bb.event.OperationProgress(current=10, total=100)
151 bb.event.execute_handler("event_handler",
152 self._test_process.event_handler,
153 event,
154 None)
155 self._test_process.event_handler.assert_called_once_with(event)
156
157 def test_fire_class_handlers(self):
158 """ Test fire_class_handlers method """
159 mask = ["bb.event.OperationStarted"]
160 result = bb.event.register("event_handler1",
161 self._test_process.event_handler1,
162 mask)
163 self.assertEqual(result, bb.event.Registered)
164 result = bb.event.register("event_handler2",
165 self._test_process.event_handler2,
166 "*")
167 self.assertEqual(result, bb.event.Registered)
168 event1 = bb.event.OperationStarted()
169 event2 = bb.event.OperationCompleted(total=123)
170 bb.event.fire_class_handlers(event1, None)
171 bb.event.fire_class_handlers(event2, None)
172 bb.event.fire_class_handlers(event2, None)
173 expected_event_handler1 = [call(event1)]
174 expected_event_handler2 = [call(event1),
175 call(event2),
176 call(event2)]
177 self.assertEqual(self._test_process.event_handler1.call_args_list,
178 expected_event_handler1)
179 self.assertEqual(self._test_process.event_handler2.call_args_list,
180 expected_event_handler2)
181
182 def test_change_handler_event_mapping(self):
183 """ Test changing the event mapping for class handlers """
184 event1 = bb.event.OperationStarted()
185 event2 = bb.event.OperationCompleted(total=123)
186
187 # register handler for all events
188 result = bb.event.register("event_handler1",
189 self._test_process.event_handler1,
190 "*")
191 self.assertEqual(result, bb.event.Registered)
192 bb.event.fire_class_handlers(event1, None)
193 bb.event.fire_class_handlers(event2, None)
194 expected = [call(event1), call(event2)]
195 self.assertEqual(self._test_process.event_handler1.call_args_list,
196 expected)
197
198 # unregister handler and register it only for OperationStarted
199 result = bb.event.remove("event_handler1",
200 self._test_process.event_handler1)
201 mask = ["bb.event.OperationStarted"]
202 result = bb.event.register("event_handler1",
203 self._test_process.event_handler1,
204 mask)
205 self.assertEqual(result, bb.event.Registered)
206 bb.event.fire_class_handlers(event1, None)
207 bb.event.fire_class_handlers(event2, None)
208 expected = [call(event1), call(event2), call(event1)]
209 self.assertEqual(self._test_process.event_handler1.call_args_list,
210 expected)
211
212 # unregister handler and register it only for OperationCompleted
213 result = bb.event.remove("event_handler1",
214 self._test_process.event_handler1)
215 mask = ["bb.event.OperationCompleted"]
216 result = bb.event.register("event_handler1",
217 self._test_process.event_handler1,
218 mask)
219 self.assertEqual(result, bb.event.Registered)
220 bb.event.fire_class_handlers(event1, None)
221 bb.event.fire_class_handlers(event2, None)
222 expected = [call(event1), call(event2), call(event1), call(event2)]
223 self.assertEqual(self._test_process.event_handler1.call_args_list,
224 expected)
225
226 def test_register_UIHhandler(self):
227 """ Test register_UIHhandler method """
228 result = bb.event.register_UIHhandler(self._test_ui1, mainui=True)
229 self.assertEqual(result, 1)
230
231 def test_UIHhandler_already_registered(self):
232 """ Test registering an UIHhandler already existing """
233 result = bb.event.register_UIHhandler(self._test_ui1, mainui=True)
234 self.assertEqual(result, 1)
235 result = bb.event.register_UIHhandler(self._test_ui1, mainui=True)
236 self.assertEqual(result, 2)
237
238 def test_unregister_UIHhandler(self):
239 """ Test unregister_UIHhandler method """
240 result = bb.event.register_UIHhandler(self._test_ui1, mainui=True)
241 self.assertEqual(result, 1)
242 result = bb.event.unregister_UIHhandler(1)
243 self.assertIs(result, None)
244
245 def test_fire_ui_handlers(self):
246 """ Test fire_ui_handlers method """
247 self._test_ui1.event = Mock(spec_set=EventQueueStub)
248 result = bb.event.register_UIHhandler(self._test_ui1, mainui=True)
249 self.assertEqual(result, 1)
250 self._test_ui2.event = Mock(spec_set=PickleEventQueueStub)
251 result = bb.event.register_UIHhandler(self._test_ui2, mainui=True)
252 self.assertEqual(result, 2)
253 event1 = bb.event.OperationStarted()
254 bb.event.fire_ui_handlers(event1, None)
255 expected = [call(event1)]
256 self.assertEqual(self._test_ui1.event.send.call_args_list,
257 expected)
258 expected = [call(pickle.dumps(event1))]
259 self.assertEqual(self._test_ui2.event.sendpickle.call_args_list,
260 expected)
261
262 def test_fire(self):
263 """ Test fire method used to trigger class and ui event handlers """
264 mask = ["bb.event.ConfigParsed"]
265 result = bb.event.register("event_handler1",
266 self._test_process.event_handler1,
267 mask)
268
269 self._test_ui1.event = Mock(spec_set=EventQueueStub)
270 result = bb.event.register_UIHhandler(self._test_ui1, mainui=True)
271 self.assertEqual(result, 1)
272
273 event1 = bb.event.ConfigParsed()
274 bb.event.fire(event1, None)
275 expected = [call(event1)]
276 self.assertEqual(self._test_process.event_handler1.call_args_list,
277 expected)
278 self.assertEqual(self._test_ui1.event.send.call_args_list,
279 expected)
280
281 def test_fire_from_worker(self):
282 """ Test fire_from_worker method """
283 self._test_ui1.event = Mock(spec_set=EventQueueStub)
284 result = bb.event.register_UIHhandler(self._test_ui1, mainui=True)
285 self.assertEqual(result, 1)
286 event1 = bb.event.ConfigParsed()
287 bb.event.fire_from_worker(event1, None)
288 expected = [call(event1)]
289 self.assertEqual(self._test_ui1.event.send.call_args_list,
290 expected)
291
292 def test_print_ui_queue(self):
293 """ Test print_ui_queue method """
294 event1 = bb.event.OperationStarted()
295 event2 = bb.event.OperationCompleted(total=123)
296 bb.event.fire(event1, None)
297 bb.event.fire(event2, None)
298 logger = logging.getLogger("BitBake")
299 logger.addHandler(bb.event.LogHandler())
300 logger.info("Test info LogRecord")
301 logger.warning("Test warning LogRecord")
302 with self.assertLogs("BitBake", level="INFO") as cm:
303 bb.event.print_ui_queue()
304 self.assertEqual(cm.output,
305 ["INFO:BitBake:Test info LogRecord",
306 "WARNING:BitBake:Test warning LogRecord"])
307
308 def _set_threadlock_test_mockups(self):
309 """ Create UI event handler mockups used in enable and disable
310 threadlock tests """
311 def ui1_event_send(event):
312 if type(event) is bb.event.ConfigParsed:
313 self._threadlock_test_calls.append("w1_ui1")
314 if type(event) is bb.event.OperationStarted:
315 self._threadlock_test_calls.append("w2_ui1")
316 time.sleep(2)
317
318 def ui2_event_send(event):
319 if type(event) is bb.event.ConfigParsed:
320 self._threadlock_test_calls.append("w1_ui2")
321 if type(event) is bb.event.OperationStarted:
322 self._threadlock_test_calls.append("w2_ui2")
323 time.sleep(2)
324
325 self._threadlock_test_calls = []
326 self._test_ui1.event = EventQueueStub()
327 self._test_ui1.event.send = ui1_event_send
328 result = bb.event.register_UIHhandler(self._test_ui1, mainui=True)
329 self.assertEqual(result, 1)
330 self._test_ui2.event = EventQueueStub()
331 self._test_ui2.event.send = ui2_event_send
332 result = bb.event.register_UIHhandler(self._test_ui2, mainui=True)
333 self.assertEqual(result, 2)
334
335 def _set_and_run_threadlock_test_workers(self):
336 """ Create and run the workers used to trigger events in enable and
337 disable threadlock tests """
338 worker1 = threading.Thread(target=self._thread_lock_test_worker1)
339 worker2 = threading.Thread(target=self._thread_lock_test_worker2)
340 worker1.start()
341 time.sleep(1)
342 worker2.start()
343 worker1.join()
344 worker2.join()
345
346 def _thread_lock_test_worker1(self):
347 """ First worker used to fire the ConfigParsed event for enable and
348 disable threadlocks tests """
349 bb.event.fire(bb.event.ConfigParsed(), None)
350
351 def _thread_lock_test_worker2(self):
352 """ Second worker used to fire the OperationStarted event for enable
353 and disable threadlocks tests """
354 bb.event.fire(bb.event.OperationStarted(), None)
355
356 def test_enable_threadlock(self):
357 """ Test enable_threadlock method """
358 self._set_threadlock_test_mockups()
359 bb.event.enable_threadlock()
360 self._set_and_run_threadlock_test_workers()
361 # Calls to UI handlers should be in order as all the registered
362 # handlers for the event coming from the first worker should be
363 # called before processing the event from the second worker.
364 self.assertEqual(self._threadlock_test_calls,
365 ["w1_ui1", "w1_ui2", "w2_ui1", "w2_ui2"])
366
367 def test_disable_threadlock(self):
368 """ Test disable_threadlock method """
369 self._set_threadlock_test_mockups()
370 bb.event.disable_threadlock()
371 self._set_and_run_threadlock_test_workers()
372 # Calls to UI handlers should be intertwined together. Thanks to the
373 # delay in the registered handlers for the event coming from the first
374 # worker, the event coming from the second worker starts being
375 # processed before finishing handling the first worker event.
376 self.assertEqual(self._threadlock_test_calls,
377 ["w1_ui1", "w2_ui1", "w1_ui2", "w2_ui2"])