xref: /openbmc/openbmc/poky/bitbake/lib/bb/tests/event.py (revision 705982a5)
1#
2# BitBake Tests for the Event implementation (event.py)
3#
4# Copyright (C) 2017 Intel Corporation
5#
6# SPDX-License-Identifier: GPL-2.0-only
7#
8
9import collections
10import importlib
11import logging
12import pickle
13import threading
14import time
15import unittest
16import tempfile
17from unittest.mock import Mock
18from unittest.mock import call
19
20import bb
21import bb.event
22from bb.msg import BBLogFormatter
23
24
25class EventQueueStubBase(object):
26    """ Base class for EventQueueStub classes """
27    def __init__(self):
28        self.event_calls = []
29        return
30
31    def _store_event_data_string(self, event):
32        if isinstance(event, logging.LogRecord):
33            formatter = BBLogFormatter("%(levelname)s: %(message)s")
34            self.event_calls.append(formatter.format(event))
35        else:
36            self.event_calls.append(bb.event.getName(event))
37        return
38
39
40class EventQueueStub(EventQueueStubBase):
41    """ Class used as specification for UI event handler queue stub objects """
42    def __init__(self):
43        super(EventQueueStub, self).__init__()
44
45    def send(self, event):
46        super(EventQueueStub, self)._store_event_data_string(event)
47
48
49class PickleEventQueueStub(EventQueueStubBase):
50    """ Class used as specification for UI event handler queue stub objects
51        with sendpickle method """
52    def __init__(self):
53        super(PickleEventQueueStub, self).__init__()
54
55    def sendpickle(self, pickled_event):
56        event = pickle.loads(pickled_event)
57        super(PickleEventQueueStub, self)._store_event_data_string(event)
58
59
60class UIClientStub(object):
61    """ Class used as specification for UI event handler stub objects """
62    def __init__(self):
63        self.event = None
64
65
66class EventHandlingTest(unittest.TestCase):
67    """ Event handling test class """
68
69
70    def setUp(self):
71        self._test_process = Mock()
72        ui_client1 = UIClientStub()
73        ui_client2 = UIClientStub()
74        self._test_ui1 = Mock(wraps=ui_client1)
75        self._test_ui2 = Mock(wraps=ui_client2)
76        importlib.reload(bb.event)
77
78    def _create_test_handlers(self):
79        """ Method used to create a test handler ordered dictionary """
80        test_handlers = collections.OrderedDict()
81        test_handlers["handler1"] = self._test_process.handler1
82        test_handlers["handler2"] = self._test_process.handler2
83        return test_handlers
84
85    def test_class_handlers(self):
86        """ Test set_class_handlers and get_class_handlers methods """
87        test_handlers = self._create_test_handlers()
88        bb.event.set_class_handlers(test_handlers)
89        self.assertEqual(test_handlers,
90                         bb.event.get_class_handlers())
91
92    def test_handlers(self):
93        """ Test set_handlers and get_handlers """
94        test_handlers = self._create_test_handlers()
95        bb.event.set_handlers(test_handlers)
96        self.assertEqual(test_handlers,
97                         bb.event.get_handlers())
98
99    def test_clean_class_handlers(self):
100        """ Test clean_class_handlers method """
101        cleanDict = collections.OrderedDict()
102        self.assertEqual(cleanDict,
103                         bb.event.clean_class_handlers())
104
105    def test_register(self):
106        """ Test register method for class handlers """
107        result = bb.event.register("handler", self._test_process.handler)
108        self.assertEqual(result, bb.event.Registered)
109        handlers_dict = bb.event.get_class_handlers()
110        self.assertIn("handler", handlers_dict)
111
112    def test_already_registered(self):
113        """ Test detection of an already registed class handler """
114        bb.event.register("handler", self._test_process.handler)
115        handlers_dict = bb.event.get_class_handlers()
116        self.assertIn("handler", handlers_dict)
117        result = bb.event.register("handler", self._test_process.handler)
118        self.assertEqual(result, bb.event.AlreadyRegistered)
119
120    def test_register_from_string(self):
121        """ Test register method receiving code in string """
122        result = bb.event.register("string_handler", "    return True")
123        self.assertEqual(result, bb.event.Registered)
124        handlers_dict = bb.event.get_class_handlers()
125        self.assertIn("string_handler", handlers_dict)
126
127    def test_register_with_mask(self):
128        """ Test register method with event masking """
129        mask = ["bb.event.OperationStarted",
130                "bb.event.OperationCompleted"]
131        result = bb.event.register("event_handler",
132                                   self._test_process.event_handler,
133                                   mask)
134        self.assertEqual(result, bb.event.Registered)
135        handlers_dict = bb.event.get_class_handlers()
136        self.assertIn("event_handler", handlers_dict)
137
138    def test_remove(self):
139        """ Test remove method for class handlers """
140        test_handlers = self._create_test_handlers()
141        bb.event.set_class_handlers(test_handlers)
142        count = len(test_handlers)
143        bb.event.remove("handler1", None)
144        test_handlers = bb.event.get_class_handlers()
145        self.assertEqual(len(test_handlers), count - 1)
146        with self.assertRaises(KeyError):
147            bb.event.remove("handler1", None)
148
149    def test_execute_handler(self):
150        """ Test execute_handler method for class handlers """
151        mask = ["bb.event.OperationProgress"]
152        result = bb.event.register("event_handler",
153                                   self._test_process.event_handler,
154                                   mask)
155        self.assertEqual(result, bb.event.Registered)
156        event = bb.event.OperationProgress(current=10, total=100)
157        bb.event.execute_handler("event_handler",
158                                 self._test_process.event_handler,
159                                 event,
160                                 None)
161        self._test_process.event_handler.assert_called_once_with(event, None)
162
163    def test_fire_class_handlers(self):
164        """ Test fire_class_handlers method """
165        mask = ["bb.event.OperationStarted"]
166        result = bb.event.register("event_handler1",
167                                   self._test_process.event_handler1,
168                                   mask)
169        self.assertEqual(result, bb.event.Registered)
170        result = bb.event.register("event_handler2",
171                                   self._test_process.event_handler2,
172                                   "*")
173        self.assertEqual(result, bb.event.Registered)
174        event1 = bb.event.OperationStarted()
175        event2 = bb.event.OperationCompleted(total=123)
176        bb.event.fire_class_handlers(event1, None)
177        bb.event.fire_class_handlers(event2, None)
178        bb.event.fire_class_handlers(event2, None)
179        expected_event_handler1 = [call(event1, None)]
180        expected_event_handler2 = [call(event1, None),
181                                   call(event2, None),
182                                   call(event2, None)]
183        self.assertEqual(self._test_process.event_handler1.call_args_list,
184                         expected_event_handler1)
185        self.assertEqual(self._test_process.event_handler2.call_args_list,
186                         expected_event_handler2)
187
188    def test_class_handler_filters(self):
189        """ Test filters for class handlers """
190        mask = ["bb.event.OperationStarted"]
191        result = bb.event.register("event_handler1",
192                                   self._test_process.event_handler1,
193                                   mask)
194        self.assertEqual(result, bb.event.Registered)
195        result = bb.event.register("event_handler2",
196                                   self._test_process.event_handler2,
197                                   "*")
198        self.assertEqual(result, bb.event.Registered)
199        bb.event.set_eventfilter(
200            lambda name, handler, event, d :
201            name == 'event_handler2' and
202            bb.event.getName(event) == "OperationStarted")
203        event1 = bb.event.OperationStarted()
204        event2 = bb.event.OperationCompleted(total=123)
205        bb.event.fire_class_handlers(event1, None)
206        bb.event.fire_class_handlers(event2, None)
207        bb.event.fire_class_handlers(event2, None)
208        expected_event_handler1 = []
209        expected_event_handler2 = [call(event1, None)]
210        self.assertEqual(self._test_process.event_handler1.call_args_list,
211                         expected_event_handler1)
212        self.assertEqual(self._test_process.event_handler2.call_args_list,
213                         expected_event_handler2)
214
215    def test_change_handler_event_mapping(self):
216        """ Test changing the event mapping for class handlers """
217        event1 = bb.event.OperationStarted()
218        event2 = bb.event.OperationCompleted(total=123)
219
220        # register handler for all events
221        result = bb.event.register("event_handler1",
222                                   self._test_process.event_handler1,
223                                   "*")
224        self.assertEqual(result, bb.event.Registered)
225        bb.event.fire_class_handlers(event1, None)
226        bb.event.fire_class_handlers(event2, None)
227        expected = [call(event1, None), call(event2, None)]
228        self.assertEqual(self._test_process.event_handler1.call_args_list,
229                         expected)
230
231        # unregister handler and register it only for OperationStarted
232        bb.event.remove("event_handler1",
233                        self._test_process.event_handler1)
234        mask = ["bb.event.OperationStarted"]
235        result = bb.event.register("event_handler1",
236                                   self._test_process.event_handler1,
237                                   mask)
238        self.assertEqual(result, bb.event.Registered)
239        bb.event.fire_class_handlers(event1, None)
240        bb.event.fire_class_handlers(event2, None)
241        expected = [call(event1, None), call(event2, None), call(event1, None)]
242        self.assertEqual(self._test_process.event_handler1.call_args_list,
243                         expected)
244
245        # unregister handler and register it only for OperationCompleted
246        bb.event.remove("event_handler1",
247                        self._test_process.event_handler1)
248        mask = ["bb.event.OperationCompleted"]
249        result = bb.event.register("event_handler1",
250                                   self._test_process.event_handler1,
251                                   mask)
252        self.assertEqual(result, bb.event.Registered)
253        bb.event.fire_class_handlers(event1, None)
254        bb.event.fire_class_handlers(event2, None)
255        expected = [call(event1,None), call(event2, None), call(event1, None), call(event2, None)]
256        self.assertEqual(self._test_process.event_handler1.call_args_list,
257                         expected)
258
259    def test_register_UIHhandler(self):
260        """ Test register_UIHhandler method """
261        result = bb.event.register_UIHhandler(self._test_ui1, mainui=True)
262        self.assertEqual(result, 1)
263
264    def test_UIHhandler_already_registered(self):
265        """ Test registering an UIHhandler already existing """
266        result = bb.event.register_UIHhandler(self._test_ui1, mainui=True)
267        self.assertEqual(result, 1)
268        result = bb.event.register_UIHhandler(self._test_ui1, mainui=True)
269        self.assertEqual(result, 2)
270
271    def test_unregister_UIHhandler(self):
272        """ Test unregister_UIHhandler method """
273        result = bb.event.register_UIHhandler(self._test_ui1, mainui=True)
274        self.assertEqual(result, 1)
275        result = bb.event.unregister_UIHhandler(1)
276        self.assertIs(result, None)
277
278    def test_fire_ui_handlers(self):
279        """ Test fire_ui_handlers method """
280        self._test_ui1.event = Mock(spec_set=EventQueueStub)
281        result = bb.event.register_UIHhandler(self._test_ui1, mainui=True)
282        self.assertEqual(result, 1)
283        self._test_ui2.event = Mock(spec_set=PickleEventQueueStub)
284        result = bb.event.register_UIHhandler(self._test_ui2, mainui=True)
285        self.assertEqual(result, 2)
286        event1 = bb.event.OperationStarted()
287        bb.event.fire_ui_handlers(event1, None)
288        expected = [call(event1)]
289        self.assertEqual(self._test_ui1.event.send.call_args_list,
290                         expected)
291        expected = [call(pickle.dumps(event1))]
292        self.assertEqual(self._test_ui2.event.sendpickle.call_args_list,
293                         expected)
294
295    def test_ui_handler_mask_filter(self):
296        """ Test filters for UI handlers """
297        mask = ["bb.event.OperationStarted"]
298        debug_domains = {}
299        self._test_ui1.event = Mock(spec_set=EventQueueStub)
300        result = bb.event.register_UIHhandler(self._test_ui1, mainui=True)
301        bb.event.set_UIHmask(result, logging.INFO, debug_domains, mask)
302        self._test_ui2.event = Mock(spec_set=PickleEventQueueStub)
303        result = bb.event.register_UIHhandler(self._test_ui2, mainui=True)
304        bb.event.set_UIHmask(result, logging.INFO, debug_domains, mask)
305
306        event1 = bb.event.OperationStarted()
307        event2 = bb.event.OperationCompleted(total=1)
308
309        bb.event.fire_ui_handlers(event1, None)
310        bb.event.fire_ui_handlers(event2, None)
311        expected = [call(event1)]
312        self.assertEqual(self._test_ui1.event.send.call_args_list,
313                         expected)
314        expected = [call(pickle.dumps(event1))]
315        self.assertEqual(self._test_ui2.event.sendpickle.call_args_list,
316                         expected)
317
318    def test_ui_handler_log_filter(self):
319        """ Test log filters for UI handlers """
320        mask = ["*"]
321        debug_domains = {'BitBake.Foo': logging.WARNING}
322
323        self._test_ui1.event = EventQueueStub()
324        result = bb.event.register_UIHhandler(self._test_ui1, mainui=True)
325        bb.event.set_UIHmask(result, logging.ERROR, debug_domains, mask)
326        self._test_ui2.event = PickleEventQueueStub()
327        result = bb.event.register_UIHhandler(self._test_ui2, mainui=True)
328        bb.event.set_UIHmask(result, logging.ERROR, debug_domains, mask)
329
330        event1 = bb.event.OperationStarted()
331        bb.event.fire_ui_handlers(event1, None)   # All events match
332
333        event_log_handler = bb.event.LogHandler()
334        logger = logging.getLogger("BitBake")
335        logger.addHandler(event_log_handler)
336        logger1 = logging.getLogger("BitBake.Foo")
337        logger1.warning("Test warning LogRecord1") # Matches debug_domains level
338        logger1.info("Test info LogRecord")        # Filtered out
339        logger2 = logging.getLogger("BitBake.Bar")
340        logger2.error("Test error LogRecord")      # Matches filter base level
341        logger2.warning("Test warning LogRecord2") # Filtered out
342        logger.removeHandler(event_log_handler)
343
344        expected = ['OperationStarted',
345                    'WARNING: Test warning LogRecord1',
346                    'ERROR: Test error LogRecord']
347        self.assertEqual(self._test_ui1.event.event_calls, expected)
348        self.assertEqual(self._test_ui2.event.event_calls, expected)
349
350    def test_fire(self):
351        """ Test fire method used to trigger class and ui event handlers """
352        mask = ["bb.event.ConfigParsed"]
353        result = bb.event.register("event_handler1",
354                                   self._test_process.event_handler1,
355                                   mask)
356
357        self._test_ui1.event = Mock(spec_set=EventQueueStub)
358        result = bb.event.register_UIHhandler(self._test_ui1, mainui=True)
359        self.assertEqual(result, 1)
360
361        event1 = bb.event.ConfigParsed()
362        bb.event.fire(event1, None)
363        expected = [call(event1, None)]
364        self.assertEqual(self._test_process.event_handler1.call_args_list,
365                         expected)
366        expected = [call(event1)]
367        self.assertEqual(self._test_ui1.event.send.call_args_list,
368                         expected)
369
370    def test_fire_from_worker(self):
371        """ Test fire_from_worker method """
372        self._test_ui1.event = Mock(spec_set=EventQueueStub)
373        result = bb.event.register_UIHhandler(self._test_ui1, mainui=True)
374        self.assertEqual(result, 1)
375        event1 = bb.event.ConfigParsed()
376        bb.event.fire_from_worker(event1, None)
377        expected = [call(event1)]
378        self.assertEqual(self._test_ui1.event.send.call_args_list,
379                         expected)
380
381    def test_worker_fire(self):
382        """ Test the triggering of bb.event.worker_fire callback """
383        bb.event.worker_fire = Mock()
384        event = bb.event.Event()
385        bb.event.fire(event, None)
386        expected = [call(event, None)]
387        self.assertEqual(bb.event.worker_fire.call_args_list, expected)
388
389    def test_print_ui_queue(self):
390        """ Test print_ui_queue method """
391        event1 = bb.event.OperationStarted()
392        event2 = bb.event.OperationCompleted(total=123)
393        bb.event.fire(event1, None)
394        bb.event.fire(event2, None)
395        event_log_handler = bb.event.LogHandler()
396        logger = logging.getLogger("BitBake")
397        logger.addHandler(event_log_handler)
398        logger.info("Test info LogRecord")
399        logger.warning("Test warning LogRecord")
400        with self.assertLogs("BitBake", level="INFO") as cm:
401            bb.event.print_ui_queue()
402        logger.removeHandler(event_log_handler)
403        self.assertEqual(cm.output,
404                         ["INFO:BitBake:Test info LogRecord",
405                          "WARNING:BitBake:Test warning LogRecord"])
406
407    def _set_threadlock_test_mockups(self):
408        """ Create UI event handler mockups used in enable and disable
409            threadlock tests """
410        def ui1_event_send(event):
411            if type(event) is bb.event.ConfigParsed:
412                self._threadlock_test_calls.append("w1_ui1")
413            if type(event) is bb.event.OperationStarted:
414                self._threadlock_test_calls.append("w2_ui1")
415            time.sleep(2)
416
417        def ui2_event_send(event):
418            if type(event) is bb.event.ConfigParsed:
419                self._threadlock_test_calls.append("w1_ui2")
420            if type(event) is bb.event.OperationStarted:
421                self._threadlock_test_calls.append("w2_ui2")
422            time.sleep(2)
423
424        self._threadlock_test_calls = []
425        self._test_ui1.event = EventQueueStub()
426        self._test_ui1.event.send = ui1_event_send
427        result = bb.event.register_UIHhandler(self._test_ui1, mainui=True)
428        self.assertEqual(result, 1)
429        self._test_ui2.event = EventQueueStub()
430        self._test_ui2.event.send = ui2_event_send
431        result = bb.event.register_UIHhandler(self._test_ui2, mainui=True)
432        self.assertEqual(result, 2)
433
434    def _set_and_run_threadlock_test_workers(self):
435        """ Create and run the workers used to trigger events in enable and
436            disable threadlock tests """
437        worker1 = threading.Thread(target=self._thread_lock_test_worker1)
438        worker2 = threading.Thread(target=self._thread_lock_test_worker2)
439        worker1.start()
440        time.sleep(1)
441        worker2.start()
442        worker1.join()
443        worker2.join()
444
445    def _thread_lock_test_worker1(self):
446        """ First worker used to fire the ConfigParsed event for enable and
447            disable threadlocks tests """
448        bb.event.fire(bb.event.ConfigParsed(), None)
449
450    def _thread_lock_test_worker2(self):
451        """ Second worker used to fire the OperationStarted event for enable
452            and disable threadlocks tests """
453        bb.event.fire(bb.event.OperationStarted(), None)
454
455    def test_event_threadlock(self):
456        """ Test enable_threadlock method """
457        self._set_threadlock_test_mockups()
458        self._set_and_run_threadlock_test_workers()
459        # Calls to UI handlers should be in order as all the registered
460        # handlers for the event coming from the first worker should be
461        # called before processing the event from the second worker.
462        self.assertEqual(self._threadlock_test_calls,
463                         ["w1_ui1", "w1_ui2", "w2_ui1", "w2_ui2"])
464
465class EventClassesTest(unittest.TestCase):
466    """ Event classes test class """
467
468    _worker_pid = 54321
469
470    def setUp(self):
471        bb.event.worker_pid = EventClassesTest._worker_pid
472        self.d = bb.data.init()
473        bb.parse.siggen = bb.siggen.init(self.d)
474
475    def test_Event(self):
476        """ Test the Event base class """
477        event = bb.event.Event()
478        self.assertEqual(event.pid, EventClassesTest._worker_pid)
479
480    def test_HeartbeatEvent(self):
481        """ Test the HeartbeatEvent class """
482        time = 10
483        event = bb.event.HeartbeatEvent(time)
484        self.assertEqual(event.time, time)
485        self.assertEqual(event.pid, EventClassesTest._worker_pid)
486
487    def test_OperationStarted(self):
488        """ Test OperationStarted event class """
489        msg = "Foo Bar"
490        event = bb.event.OperationStarted(msg)
491        self.assertEqual(event.msg, msg)
492        self.assertEqual(event.pid, EventClassesTest._worker_pid)
493
494    def test_OperationCompleted(self):
495        """ Test OperationCompleted event class """
496        msg = "Foo Bar"
497        total = 123
498        event = bb.event.OperationCompleted(total, msg)
499        self.assertEqual(event.msg, msg)
500        self.assertEqual(event.total, total)
501        self.assertEqual(event.pid, EventClassesTest._worker_pid)
502
503    def test_OperationProgress(self):
504        """ Test OperationProgress event class """
505        msg = "Foo Bar"
506        total = 123
507        current = 111
508        event = bb.event.OperationProgress(current, total, msg)
509        self.assertEqual(event.msg, msg + ": %s/%s" % (current, total))
510        self.assertEqual(event.pid, EventClassesTest._worker_pid)
511
512    def test_ConfigParsed(self):
513        """ Test the ConfigParsed class """
514        event = bb.event.ConfigParsed()
515        self.assertEqual(event.pid, EventClassesTest._worker_pid)
516
517    def test_MultiConfigParsed(self):
518        """ Test MultiConfigParsed event class """
519        mcdata = {"foobar": "Foo Bar"}
520        event = bb.event.MultiConfigParsed(mcdata)
521        self.assertEqual(event.mcdata, mcdata)
522        self.assertEqual(event.pid, EventClassesTest._worker_pid)
523
524    def test_RecipeEvent(self):
525        """ Test RecipeEvent event base class """
526        callback = lambda a: 2 * a
527        event = bb.event.RecipeEvent(callback)
528        self.assertEqual(event.fn(1), callback(1))
529        self.assertEqual(event.pid, EventClassesTest._worker_pid)
530
531    def test_RecipePreFinalise(self):
532        """ Test RecipePreFinalise event class """
533        callback = lambda a: 2 * a
534        event = bb.event.RecipePreFinalise(callback)
535        self.assertEqual(event.fn(1), callback(1))
536        self.assertEqual(event.pid, EventClassesTest._worker_pid)
537
538    def test_RecipeTaskPreProcess(self):
539        """ Test RecipeTaskPreProcess event class """
540        callback = lambda a: 2 * a
541        tasklist = [("foobar", callback)]
542        event = bb.event.RecipeTaskPreProcess(callback, tasklist)
543        self.assertEqual(event.fn(1), callback(1))
544        self.assertEqual(event.tasklist, tasklist)
545        self.assertEqual(event.pid, EventClassesTest._worker_pid)
546
547    def test_RecipeParsed(self):
548        """ Test RecipeParsed event base class """
549        callback = lambda a: 2 * a
550        event = bb.event.RecipeParsed(callback)
551        self.assertEqual(event.fn(1), callback(1))
552        self.assertEqual(event.pid, EventClassesTest._worker_pid)
553
554    def test_BuildBase(self):
555        """ Test base class for bitbake build events """
556        name = "foo"
557        pkgs = ["bar"]
558        failures = 123
559        event = bb.event.BuildBase(name, pkgs, failures)
560        self.assertEqual(event.name, name)
561        self.assertEqual(event.pkgs, pkgs)
562        self.assertEqual(event.getFailures(), failures)
563        name = event.name = "bar"
564        pkgs = event.pkgs = ["foo"]
565        self.assertEqual(event.name, name)
566        self.assertEqual(event.pkgs, pkgs)
567        self.assertEqual(event.getFailures(), failures)
568        self.assertEqual(event.pid, EventClassesTest._worker_pid)
569
570    def test_BuildInit(self):
571        """ Test class for bitbake build invocation events """
572        event = bb.event.BuildInit()
573        self.assertEqual(event.name, None)
574        self.assertEqual(event.pkgs, [])
575        self.assertEqual(event.getFailures(), 0)
576        name = event.name = "bar"
577        pkgs = event.pkgs = ["foo"]
578        self.assertEqual(event.name, name)
579        self.assertEqual(event.pkgs, pkgs)
580        self.assertEqual(event.getFailures(), 0)
581        self.assertEqual(event.pid, EventClassesTest._worker_pid)
582
583    def test_BuildStarted(self):
584        """ Test class for build started events """
585        name = "foo"
586        pkgs = ["bar"]
587        failures = 123
588        event = bb.event.BuildStarted(name, pkgs, failures)
589        self.assertEqual(event.name, name)
590        self.assertEqual(event.pkgs, pkgs)
591        self.assertEqual(event.getFailures(), failures)
592        self.assertEqual(event.msg, "Building Started")
593        name = event.name = "bar"
594        pkgs = event.pkgs = ["foo"]
595        msg = event.msg = "foobar"
596        self.assertEqual(event.name, name)
597        self.assertEqual(event.pkgs, pkgs)
598        self.assertEqual(event.getFailures(), failures)
599        self.assertEqual(event.msg, msg)
600        self.assertEqual(event.pid, EventClassesTest._worker_pid)
601
602    def test_BuildCompleted(self):
603        """ Test class for build completed events """
604        total = 1000
605        name = "foo"
606        pkgs = ["bar"]
607        failures = 123
608        interrupted = 1
609        event = bb.event.BuildCompleted(total, name, pkgs, failures,
610                                        interrupted)
611        self.assertEqual(event.name, name)
612        self.assertEqual(event.pkgs, pkgs)
613        self.assertEqual(event.getFailures(), failures)
614        self.assertEqual(event.msg, "Building Failed")
615        event2 = bb.event.BuildCompleted(total, name, pkgs)
616        self.assertEqual(event2.name, name)
617        self.assertEqual(event2.pkgs, pkgs)
618        self.assertEqual(event2.getFailures(), 0)
619        self.assertEqual(event2.msg, "Building Succeeded")
620        self.assertEqual(event2.pid, EventClassesTest._worker_pid)
621
622    def test_DiskFull(self):
623        """ Test DiskFull event class """
624        dev = "/dev/foo"
625        type = "ext4"
626        freespace = "104M"
627        mountpoint = "/"
628        event = bb.event.DiskFull(dev, type, freespace, mountpoint)
629        self.assertEqual(event.pid, EventClassesTest._worker_pid)
630
631    def test_MonitorDiskEvent(self):
632        """ Test MonitorDiskEvent class """
633        available_bytes = 10000000
634        free_bytes = 90000000
635        total_bytes = 1000000000
636        du = bb.event.DiskUsageSample(available_bytes, free_bytes,
637                                      total_bytes)
638        event = bb.event.MonitorDiskEvent(du)
639        self.assertEqual(event.disk_usage.available_bytes, available_bytes)
640        self.assertEqual(event.disk_usage.free_bytes, free_bytes)
641        self.assertEqual(event.disk_usage.total_bytes, total_bytes)
642        self.assertEqual(event.pid, EventClassesTest._worker_pid)
643
644    def test_NoProvider(self):
645        """ Test NoProvider event class """
646        item = "foobar"
647        event1 = bb.event.NoProvider(item)
648        self.assertEqual(event1.getItem(), item)
649        self.assertEqual(event1.isRuntime(), False)
650        self.assertEqual(str(event1), "Nothing PROVIDES 'foobar'")
651        runtime = True
652        dependees = ["foo", "bar"]
653        reasons = None
654        close_matches = ["foibar", "footbar"]
655        event2 = bb.event.NoProvider(item, runtime, dependees, reasons,
656                                     close_matches)
657        self.assertEqual(event2.isRuntime(), True)
658        expected = ("Nothing RPROVIDES 'foobar' (but foo, bar RDEPENDS"
659                    " on or otherwise requires it). Close matches:\n"
660                    "  foibar\n"
661                    "  footbar")
662        self.assertEqual(str(event2), expected)
663        reasons = ["Item does not exist on database"]
664        close_matches = ["foibar", "footbar"]
665        event3 = bb.event.NoProvider(item, runtime, dependees, reasons,
666                                     close_matches)
667        expected = ("Nothing RPROVIDES 'foobar' (but foo, bar RDEPENDS"
668                    " on or otherwise requires it)\n"
669                    "Item does not exist on database")
670        self.assertEqual(str(event3), expected)
671        self.assertEqual(event3.pid, EventClassesTest._worker_pid)
672
673    def test_MultipleProviders(self):
674        """ Test MultipleProviders event class """
675        item = "foobar"
676        candidates = ["foobarv1", "foobars"]
677        event1 = bb.event.MultipleProviders(item, candidates)
678        self.assertEqual(event1.isRuntime(), False)
679        self.assertEqual(event1.getItem(), item)
680        self.assertEqual(event1.getCandidates(), candidates)
681        expected = ("Multiple providers are available for foobar (foobarv1,"
682                    " foobars)\n"
683                    "Consider defining a PREFERRED_PROVIDER entry to match "
684                    "foobar")
685        self.assertEqual(str(event1), expected)
686        runtime = True
687        event2 = bb.event.MultipleProviders(item, candidates, runtime)
688        self.assertEqual(event2.isRuntime(), runtime)
689        expected = ("Multiple providers are available for runtime foobar "
690                    "(foobarv1, foobars)\n"
691                    "Consider defining a PREFERRED_RPROVIDER entry to match "
692                    "foobar")
693        self.assertEqual(str(event2), expected)
694        self.assertEqual(event2.pid, EventClassesTest._worker_pid)
695
696    def test_ParseStarted(self):
697        """ Test ParseStarted event class """
698        total = 123
699        event = bb.event.ParseStarted(total)
700        self.assertEqual(event.msg, "Recipe parsing Started")
701        self.assertEqual(event.total, total)
702        self.assertEqual(event.pid, EventClassesTest._worker_pid)
703
704    def test_ParseCompleted(self):
705        """ Test ParseCompleted event class """
706        cached = 10
707        parsed = 13
708        skipped = 7
709        virtuals = 2
710        masked = 1
711        errors = 0
712        total = 23
713        event = bb.event.ParseCompleted(cached, parsed, skipped, masked,
714                                        virtuals, errors, total)
715        self.assertEqual(event.msg, "Recipe parsing Completed")
716        expected = [cached, parsed, skipped, virtuals, masked, errors,
717                    cached + parsed, total]
718        actual = [event.cached, event.parsed, event.skipped, event.virtuals,
719                  event.masked, event.errors, event.sofar, event.total]
720        self.assertEqual(str(actual), str(expected))
721        self.assertEqual(event.pid, EventClassesTest._worker_pid)
722
723    def test_ParseProgress(self):
724        """ Test ParseProgress event class """
725        current = 10
726        total = 100
727        event = bb.event.ParseProgress(current, total)
728        self.assertEqual(event.msg,
729                         "Recipe parsing" + ": %s/%s" % (current, total))
730        self.assertEqual(event.pid, EventClassesTest._worker_pid)
731
732    def test_CacheLoadStarted(self):
733        """ Test CacheLoadStarted event class """
734        total = 123
735        event = bb.event.CacheLoadStarted(total)
736        self.assertEqual(event.msg, "Loading cache Started")
737        self.assertEqual(event.total, total)
738        self.assertEqual(event.pid, EventClassesTest._worker_pid)
739
740    def test_CacheLoadProgress(self):
741        """ Test CacheLoadProgress event class """
742        current = 10
743        total = 100
744        event = bb.event.CacheLoadProgress(current, total)
745        self.assertEqual(event.msg,
746                         "Loading cache" + ": %s/%s" % (current, total))
747        self.assertEqual(event.pid, EventClassesTest._worker_pid)
748
749    def test_CacheLoadCompleted(self):
750        """ Test CacheLoadCompleted event class """
751        total = 23
752        num_entries = 12
753        event = bb.event.CacheLoadCompleted(total, num_entries)
754        self.assertEqual(event.msg, "Loading cache Completed")
755        expected = [total, num_entries]
756        actual = [event.total, event.num_entries]
757        self.assertEqual(str(actual), str(expected))
758        self.assertEqual(event.pid, EventClassesTest._worker_pid)
759
760    def test_TreeDataPreparationStarted(self):
761        """ Test TreeDataPreparationStarted event class """
762        event = bb.event.TreeDataPreparationStarted()
763        self.assertEqual(event.msg, "Preparing tree data Started")
764        self.assertEqual(event.pid, EventClassesTest._worker_pid)
765
766    def test_TreeDataPreparationProgress(self):
767        """ Test TreeDataPreparationProgress event class """
768        current = 10
769        total = 100
770        event = bb.event.TreeDataPreparationProgress(current, total)
771        self.assertEqual(event.msg,
772                         "Preparing tree data" + ": %s/%s" % (current, total))
773        self.assertEqual(event.pid, EventClassesTest._worker_pid)
774
775    def test_TreeDataPreparationCompleted(self):
776        """ Test TreeDataPreparationCompleted event class """
777        total = 23
778        event = bb.event.TreeDataPreparationCompleted(total)
779        self.assertEqual(event.msg, "Preparing tree data Completed")
780        self.assertEqual(event.total, total)
781        self.assertEqual(event.pid, EventClassesTest._worker_pid)
782
783    def test_DepTreeGenerated(self):
784        """ Test DepTreeGenerated event class """
785        depgraph = Mock()
786        event = bb.event.DepTreeGenerated(depgraph)
787        self.assertEqual(event.pid, EventClassesTest._worker_pid)
788
789    def test_TargetsTreeGenerated(self):
790        """ Test TargetsTreeGenerated event class """
791        model = Mock()
792        event = bb.event.TargetsTreeGenerated(model)
793        self.assertEqual(event.pid, EventClassesTest._worker_pid)
794
795    def test_ReachableStamps(self):
796        """ Test ReachableStamps event class """
797        stamps = [Mock(), Mock()]
798        event = bb.event.ReachableStamps(stamps)
799        self.assertEqual(event.stamps, stamps)
800        self.assertEqual(event.pid, EventClassesTest._worker_pid)
801
802    def test_FilesMatchingFound(self):
803        """ Test FilesMatchingFound event class """
804        pattern = "foo.*bar"
805        matches = ["foobar"]
806        event = bb.event.FilesMatchingFound(pattern, matches)
807        self.assertEqual(event.pid, EventClassesTest._worker_pid)
808
809    def test_ConfigFilesFound(self):
810        """ Test ConfigFilesFound event class """
811        variable = "FOO_BAR"
812        values = ["foo", "bar"]
813        event = bb.event.ConfigFilesFound(variable, values)
814        self.assertEqual(event.pid, EventClassesTest._worker_pid)
815
816    def test_ConfigFilePathFound(self):
817        """ Test ConfigFilePathFound event class """
818        path = "/foo/bar"
819        event = bb.event.ConfigFilePathFound(path)
820        self.assertEqual(event.pid, EventClassesTest._worker_pid)
821
822    def test_message_classes(self):
823        """ Test message event classes """
824        msg = "foobar foo bar"
825        event = bb.event.MsgBase(msg)
826        self.assertEqual(event.pid, EventClassesTest._worker_pid)
827        event = bb.event.MsgDebug(msg)
828        self.assertEqual(event.pid, EventClassesTest._worker_pid)
829        event = bb.event.MsgNote(msg)
830        self.assertEqual(event.pid, EventClassesTest._worker_pid)
831        event = bb.event.MsgWarn(msg)
832        self.assertEqual(event.pid, EventClassesTest._worker_pid)
833        event = bb.event.MsgError(msg)
834        self.assertEqual(event.pid, EventClassesTest._worker_pid)
835        event = bb.event.MsgFatal(msg)
836        self.assertEqual(event.pid, EventClassesTest._worker_pid)
837        event = bb.event.MsgPlain(msg)
838        self.assertEqual(event.pid, EventClassesTest._worker_pid)
839
840    def test_LogExecTTY(self):
841        """ Test LogExecTTY event class """
842        msg = "foo bar"
843        prog = "foo.sh"
844        sleep_delay = 10
845        retries = 3
846        event = bb.event.LogExecTTY(msg, prog, sleep_delay, retries)
847        self.assertEqual(event.msg, msg)
848        self.assertEqual(event.prog, prog)
849        self.assertEqual(event.sleep_delay, sleep_delay)
850        self.assertEqual(event.retries, retries)
851        self.assertEqual(event.pid, EventClassesTest._worker_pid)
852
853    def _throw_zero_division_exception(self):
854        a = 1 / 0
855        return
856
857    def _worker_handler(self, event, d):
858        self._returned_event = event
859        return
860
861    def test_LogHandler(self):
862        """ Test LogHandler class """
863        logger = logging.getLogger("TestEventClasses")
864        logger.propagate = False
865        handler = bb.event.LogHandler(logging.INFO)
866        logger.addHandler(handler)
867        bb.event.worker_fire = self._worker_handler
868        try:
869            self._throw_zero_division_exception()
870        except ZeroDivisionError as ex:
871            logger.exception(ex)
872        event = self._returned_event
873        try:
874            pe = pickle.dumps(event)
875            newevent = pickle.loads(pe)
876        except:
877            self.fail('Logged event is not serializable')
878        self.assertEqual(event.taskpid, EventClassesTest._worker_pid)
879
880    def test_MetadataEvent(self):
881        """ Test MetadataEvent class """
882        eventtype = "footype"
883        eventdata = {"foo": "bar"}
884        event = bb.event.MetadataEvent(eventtype, eventdata)
885        self.assertEqual(event.type, eventtype)
886        self.assertEqual(event.pid, EventClassesTest._worker_pid)
887
888    def test_ProcessStarted(self):
889        """ Test ProcessStarted class """
890        processname = "foo"
891        total = 9783128974
892        event = bb.event.ProcessStarted(processname, total)
893        self.assertEqual(event.processname, processname)
894        self.assertEqual(event.total, total)
895        self.assertEqual(event.pid, EventClassesTest._worker_pid)
896
897    def test_ProcessProgress(self):
898        """ Test ProcessProgress class """
899        processname = "foo"
900        progress = 243224
901        event = bb.event.ProcessProgress(processname, progress)
902        self.assertEqual(event.processname, processname)
903        self.assertEqual(event.progress, progress)
904        self.assertEqual(event.pid, EventClassesTest._worker_pid)
905
906    def test_ProcessFinished(self):
907        """ Test ProcessFinished class """
908        processname = "foo"
909        total = 1242342344
910        event = bb.event.ProcessFinished(processname)
911        self.assertEqual(event.processname, processname)
912        self.assertEqual(event.pid, EventClassesTest._worker_pid)
913
914    def test_SanityCheck(self):
915        """ Test SanityCheck class """
916        event1 = bb.event.SanityCheck()
917        self.assertEqual(event1.generateevents, True)
918        self.assertEqual(event1.pid, EventClassesTest._worker_pid)
919        generateevents = False
920        event2 = bb.event.SanityCheck(generateevents)
921        self.assertEqual(event2.generateevents, generateevents)
922        self.assertEqual(event2.pid, EventClassesTest._worker_pid)
923
924    def test_SanityCheckPassed(self):
925        """ Test SanityCheckPassed class """
926        event = bb.event.SanityCheckPassed()
927        self.assertEqual(event.pid, EventClassesTest._worker_pid)
928
929    def test_SanityCheckFailed(self):
930        """ Test SanityCheckFailed class """
931        msg = "The sanity test failed."
932        event1 = bb.event.SanityCheckFailed(msg)
933        self.assertEqual(event1.pid, EventClassesTest._worker_pid)
934        network_error = True
935        event2 = bb.event.SanityCheckFailed(msg, network_error)
936        self.assertEqual(event2.pid, EventClassesTest._worker_pid)
937
938    def test_network_event_classes(self):
939        """ Test network event classes """
940        event1 = bb.event.NetworkTest()
941        generateevents = False
942        self.assertEqual(event1.pid, EventClassesTest._worker_pid)
943        event2 = bb.event.NetworkTest(generateevents)
944        self.assertEqual(event2.pid, EventClassesTest._worker_pid)
945        event3 = bb.event.NetworkTestPassed()
946        self.assertEqual(event3.pid, EventClassesTest._worker_pid)
947        event4 = bb.event.NetworkTestFailed()
948        self.assertEqual(event4.pid, EventClassesTest._worker_pid)
949
950    def test_FindSigInfoResult(self):
951        """ Test FindSigInfoResult event class """
952        result = [Mock()]
953        event = bb.event.FindSigInfoResult(result)
954        self.assertEqual(event.result, result)
955        self.assertEqual(event.pid, EventClassesTest._worker_pid)
956
957    def test_lineno_in_eventhandler(self):
958        # The error lineno is 5, not 4 since the first line is '\n'
959        error_line = """
960# Comment line1
961# Comment line2
962python test_lineno_in_eventhandler() {
963    This is an error line
964}
965addhandler test_lineno_in_eventhandler
966test_lineno_in_eventhandler[eventmask] = "bb.event.ConfigParsed"
967"""
968
969        with self.assertLogs() as logs:
970            f = tempfile.NamedTemporaryFile(suffix = '.bb')
971            f.write(bytes(error_line, "utf-8"))
972            f.flush()
973            d = bb.parse.handle(f.name, self.d)['']
974
975        output = "".join(logs.output)
976        self.assertTrue(" line 5\n" in output)
977