2 # Copyright (C) 2019 EfficiOS Inc.
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; only version 2
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 class _MyIter(bt2
._UserMessageIterator
):
24 def __init__(self
, config
, self_output_port
):
28 def _build_meta(self
):
29 self
._tc
= self
._component
._create
_trace
_class
()
31 self
._sc
= self
._tc
.create_stream_class(supports_packets
=True)
32 self
._ec
= self
._sc
.create_event_class(name
='salut')
33 self
._my
_int
_ft
= self
._tc
.create_signed_integer_field_class(32)
34 payload_ft
= self
._tc
.create_structure_field_class()
35 payload_ft
+= [('my_int', self
._my
_int
_ft
)]
36 self
._ec
.payload_field_type
= payload_ft
37 self
._stream
= self
._t
.create_stream(self
._sc
)
38 self
._packet
= self
._stream
.create_packet()
40 def _create_event(self
, value
):
42 ev
.payload_field
['my_int'] = value
43 ev
.packet
= self
._packet
47 class GraphTestCase(unittest
.TestCase
):
49 self
._graph
= bt2
.Graph()
54 def test_create_default(self
):
57 def test_create_known_mip_version(self
):
60 def test_create_invalid_mip_version_type(self
):
61 with self
.assertRaises(TypeError):
64 def test_create_unknown_mip_version(self
):
65 with self
.assertRaisesRegex(ValueError, 'unknown MIP version'):
68 def test_default_interrupter(self
):
69 interrupter
= self
._graph
.default_interrupter
70 self
.assertIs(type(interrupter
), bt2
.Interrupter
)
72 def test_add_component_user_cls(self
):
73 class MySink(bt2
._UserSinkComponent
):
74 def _user_consume(self
):
77 comp
= self
._graph
.add_component(MySink
, 'salut')
78 self
.assertEqual(comp
.name
, 'salut')
80 def test_add_component_gen_cls(self
):
81 class MySink(bt2
._UserSinkComponent
):
82 def _user_consume(self
):
85 comp
= self
._graph
.add_component(MySink
, 'salut')
87 comp2
= self
._graph
.add_component(comp
.cls
, 'salut2')
88 self
.assertEqual(comp2
.name
, 'salut2')
90 def test_add_component_params(self
):
93 class MySink(bt2
._UserSinkComponent
):
94 def __init__(self
, config
, params
, obj
):
98 def _user_consume(self
):
101 params
= {'hello': 23, 'path': '/path/to/stuff'}
102 self
._graph
.add_component(MySink
, 'salut', params
)
103 self
.assertEqual(params
, comp_params
)
106 def test_add_component_obj_python_comp_cls(self
):
109 class MySink(bt2
._UserSinkComponent
):
110 def __init__(self
, config
, params
, obj
):
114 def _user_consume(self
):
118 self
._graph
.add_component(MySink
, 'salut', obj
=obj
)
119 self
.assertIs(comp_obj
, obj
)
122 def test_add_component_obj_none_python_comp_cls(self
):
125 class MySink(bt2
._UserSinkComponent
):
126 def __init__(self
, config
, params
, obj
):
130 def _user_consume(self
):
133 self
._graph
.add_component(MySink
, 'salut')
134 self
.assertIsNone(comp_obj
)
137 def test_add_component_obj_non_python_comp_cls(self
):
138 plugin
= bt2
.find_plugin('text', find_in_user_dir
=False, find_in_sys_dir
=False)
139 assert plugin
is not None
140 cc
= plugin
.source_component_classes
['dmesg']
141 assert cc
is not None
143 with self
.assertRaises(ValueError):
144 self
._graph
.add_component(cc
, 'salut', obj
=57)
146 def test_add_component_invalid_cls_type(self
):
147 with self
.assertRaises(TypeError):
148 self
._graph
.add_component(int, 'salut')
150 def test_add_component_invalid_logging_level_type(self
):
151 class MySink(bt2
._UserSinkComponent
):
152 def _user_consume(self
):
155 with self
.assertRaises(TypeError):
156 self
._graph
.add_component(MySink
, 'salut', logging_level
='yo')
158 def test_add_component_invalid_logging_level_value(self
):
159 class MySink(bt2
._UserSinkComponent
):
160 def _user_consume(self
):
163 with self
.assertRaises(ValueError):
164 self
._graph
.add_component(MySink
, 'salut', logging_level
=12345)
166 def test_add_component_invalid_params_type(self
):
167 class MySink(bt2
._UserSinkComponent
):
168 def _user_consume(self
):
171 with self
.assertRaises(TypeError):
172 self
._graph
.add_component(MySink
, 'salut', params
=12)
174 def test_add_component_params_dict(self
):
177 class MySink(bt2
._UserSinkComponent
):
178 def __init__(self
, config
, params
, obj
):
182 def _user_consume(self
):
185 params
= {'plage': 12312}
186 self
._graph
.add_component(MySink
, 'salut', params
=params
)
188 # Check equality and not identity because `add_component()` method
189 # converts the Python `dict` to a `bt2.MapValue`.
190 self
.assertEqual(params
, params_obj
)
192 def test_add_component_params_mapvalue(self
):
195 class MySink(bt2
._UserSinkComponent
):
196 def __init__(self
, config
, params
, obj
):
200 def _user_consume(self
):
203 params
= bt2
.MapValue({'beachclub': '121'})
204 self
._graph
.add_component(MySink
, 'salut', params
=params
)
206 self
.assertEqual(params
, params_obj
)
208 def test_add_component_logging_level(self
):
209 class MySink(bt2
._UserSinkComponent
):
210 def _user_consume(self
):
213 comp
= self
._graph
.add_component(
214 MySink
, 'salut', logging_level
=bt2
.LoggingLevel
.DEBUG
216 self
.assertEqual(comp
.logging_level
, bt2
.LoggingLevel
.DEBUG
)
218 def test_connect_ports(self
):
219 class MyIter(bt2
._UserMessageIterator
):
223 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
224 def __init__(self
, config
, params
, obj
):
225 self
._add
_output
_port
('out')
227 class MySink(bt2
._UserSinkComponent
):
228 def __init__(self
, config
, params
, obj
):
229 self
._add
_input
_port
('in')
231 def _user_consume(self
):
234 src
= self
._graph
.add_component(MySource
, 'src')
235 sink
= self
._graph
.add_component(MySink
, 'sink')
237 conn
= self
._graph
.connect_ports(
238 src
.output_ports
['out'], sink
.input_ports
['in']
240 self
.assertTrue(src
.output_ports
['out'].is_connected
)
241 self
.assertTrue(sink
.input_ports
['in'].is_connected
)
242 self
.assertEqual(src
.output_ports
['out'].connection
.addr
, conn
.addr
)
243 self
.assertEqual(sink
.input_ports
['in'].connection
.addr
, conn
.addr
)
245 def test_connect_ports_invalid_direction(self
):
246 class MyIter(bt2
._UserMessageIterator
):
250 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
251 def __init__(self
, config
, params
, obj
):
252 self
._add
_output
_port
('out')
254 class MySink(bt2
._UserSinkComponent
):
255 def __init__(self
, config
, params
, obj
):
256 self
._add
_input
_port
('in')
258 def _user_consume(self
):
261 src
= self
._graph
.add_component(MySource
, 'src')
262 sink
= self
._graph
.add_component(MySink
, 'sink')
264 with self
.assertRaises(TypeError):
265 self
._graph
.connect_ports(sink
.input_ports
['in'], src
.output_ports
['out'])
267 def test_add_interrupter(self
):
268 class MyIter(bt2
._UserMessageIterator
):
272 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
273 def __init__(self
, config
, params
, obj
):
274 self
._add
_output
_port
('out')
276 class MySink(bt2
._UserSinkComponent
):
277 def __init__(self
, config
, params
, obj
):
278 self
._add
_input
_port
('in')
280 def _user_consume(self
):
283 def _user_graph_is_configured(self
):
284 self
._msg
_iter
= self
._create
_input
_port
_message
_iterator
(
285 self
._input
_ports
['in']
288 # add two interrupters, set one of them
289 interrupter1
= bt2
.Interrupter()
290 interrupter2
= bt2
.Interrupter()
291 self
._graph
.add_interrupter(interrupter1
)
292 src
= self
._graph
.add_component(MySource
, 'src')
293 sink
= self
._graph
.add_component(MySink
, 'sink')
294 self
._graph
.connect_ports(src
.output_ports
['out'], sink
.input_ports
['in'])
295 self
._graph
.add_interrupter(interrupter2
)
297 with self
.assertRaises(bt2
._Error
):
302 with self
.assertRaises(bt2
.TryAgain
):
307 with self
.assertRaises(bt2
._Error
):
310 # Test that Graph.run() raises bt2.Interrupted if the graph gets
311 # interrupted during execution.
312 def test_interrupt_while_running(self
):
313 class MyIter(_MyIter
):
315 return self
._create
_stream
_beginning
_message
(self
._stream
)
317 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
318 def __init__(self
, config
, params
, obj
):
319 self
._add
_output
_port
('out')
321 class MySink(bt2
._UserSinkComponent
):
322 def __init__(self
, config
, params
, obj
):
323 self
._add
_input
_port
('in')
325 def _user_consume(self
):
326 # Pretend that somebody asynchronously interrupted the graph.
328 graph
.default_interrupter
.set()
329 return next(self
._msg
_iter
)
331 def _user_graph_is_configured(self
):
332 self
._msg
_iter
= self
._create
_input
_port
_message
_iterator
(
333 self
._input
_ports
['in']
337 up
= self
._graph
.add_component(MySource
, 'down')
338 down
= self
._graph
.add_component(MySink
, 'up')
339 self
._graph
.connect_ports(up
.output_ports
['out'], down
.input_ports
['in'])
341 with self
.assertRaises(bt2
.TryAgain
):
345 class MyIter(_MyIter
):
351 msg
= self
._create
_stream
_beginning
_message
(self
._stream
)
353 msg
= self
._create
_packet
_beginning
_message
(self
._packet
)
355 msg
= self
._create
_packet
_end
_message
(self
._packet
)
357 msg
= self
._create
_stream
_end
_message
(self
._stream
)
359 msg
= self
._create
_event
_message
(self
._ec
, self
._packet
)
364 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
365 def __init__(self
, config
, params
, obj
):
366 self
._add
_output
_port
('out')
368 class MySink(bt2
._UserSinkComponent
):
369 def __init__(self
, config
, params
, obj
):
370 self
._input
_port
= self
._add
_input
_port
('in')
373 def _user_consume(comp_self
):
374 msg
= next(comp_self
._msg
_iter
)
376 if comp_self
._at
== 0:
377 self
.assertIs(type(msg
), bt2
._StreamBeginningMessageConst
)
378 elif comp_self
._at
== 1:
379 self
.assertIs(type(msg
), bt2
._PacketBeginningMessageConst
)
380 elif comp_self
._at
>= 2 and comp_self
._at
<= 6:
381 self
.assertIs(type(msg
), bt2
._EventMessageConst
)
382 self
.assertEqual(msg
.event
.cls
.name
, 'salut')
383 elif comp_self
._at
== 7:
384 self
.assertIs(type(msg
), bt2
._PacketEndMessageConst
)
385 elif comp_self
._at
== 8:
386 self
.assertIs(type(msg
), bt2
._StreamEndMessageConst
)
390 def _user_graph_is_configured(self
):
391 self
._msg
_iter
= self
._create
_input
_port
_message
_iterator
(
395 src
= self
._graph
.add_component(MySource
, 'src')
396 sink
= self
._graph
.add_component(MySink
, 'sink')
397 self
._graph
.connect_ports(src
.output_ports
['out'], sink
.input_ports
['in'])
400 def test_run_once(self
):
401 class MyIter(_MyIter
):
404 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
405 def __init__(self
, config
, params
, obj
):
406 self
._add
_output
_port
('out')
408 class MySink(bt2
._UserSinkComponent
):
409 def __init__(self
, config
, params
, obj
):
410 self
._input
_port
= self
._add
_input
_port
('in')
412 def _user_consume(comp_self
):
418 src
= self
._graph
.add_component(MySource
, 'src')
419 sink
= self
._graph
.add_component(MySink
, 'sink')
420 self
._graph
.connect_ports(src
.output_ports
['out'], sink
.input_ports
['in'])
422 with self
.assertRaises(bt2
.TryAgain
):
423 self
._graph
.run_once()
425 self
.assertEqual(run_count
, 1)
427 def test_run_once_stops(self
):
428 class MyIter(_MyIter
):
431 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
432 def __init__(self
, config
, params
, obj
):
433 self
._add
_output
_port
('out')
435 class MySink(bt2
._UserSinkComponent
):
436 def __init__(self
, config
, params
, obj
):
437 self
._input
_port
= self
._add
_input
_port
('in')
439 def _user_consume(comp_self
):
442 src
= self
._graph
.add_component(MySource
, 'src')
443 sink
= self
._graph
.add_component(MySink
, 'sink')
444 self
._graph
.connect_ports(src
.output_ports
['out'], sink
.input_ports
['in'])
446 with self
.assertRaises(bt2
.Stop
):
447 self
._graph
.run_once()
449 def test_run_again(self
):
450 class MyIter(_MyIter
):
456 msg
= self
._create
_stream
_beginning
_message
(self
._stream
)
458 msg
= self
._create
_packet
_beginning
_message
(self
._packet
)
460 msg
= self
._create
_event
_message
(self
._ec
, self
._packet
)
465 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
466 def __init__(self
, config
, params
, obj
):
467 self
._add
_output
_port
('out')
469 class MySink(bt2
._UserSinkComponent
):
470 def __init__(self
, config
, params
, obj
):
471 self
._input
_port
= self
._add
_input
_port
('in')
474 def _user_consume(comp_self
):
475 msg
= next(comp_self
._msg
_iter
)
476 if comp_self
._at
== 0:
477 self
.assertIs(type(msg
), bt2
._StreamBeginningMessageConst
)
478 elif comp_self
._at
== 1:
479 self
.assertIs(type(msg
), bt2
._PacketBeginningMessageConst
)
480 elif comp_self
._at
== 2:
481 self
.assertIs(type(msg
), bt2
._EventMessageConst
)
488 def _user_graph_is_configured(self
):
489 self
._msg
_iter
= self
._create
_input
_port
_message
_iterator
(
493 src
= self
._graph
.add_component(MySource
, 'src')
494 sink
= self
._graph
.add_component(MySink
, 'sink')
495 self
._graph
.connect_ports(src
.output_ports
['out'], sink
.input_ports
['in'])
497 with self
.assertRaises(bt2
.TryAgain
):
500 def test_run_error(self
):
501 raised_in_sink
= False
503 class MyIter(_MyIter
):
505 # If this gets called after the sink raised an exception, it is
507 nonlocal raised_in_sink
508 assert raised_in_sink
is False
511 msg
= self
._create
_stream
_beginning
_message
(self
._stream
)
513 msg
= self
._create
_packet
_beginning
_message
(self
._packet
)
514 elif self
._at
== 2 or self
._at
== 3:
515 msg
= self
._create
_event
_message
(self
._ec
, self
._packet
)
521 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
522 def __init__(self
, config
, params
, obj
):
523 self
._add
_output
_port
('out')
525 class MySink(bt2
._UserSinkComponent
):
526 def __init__(self
, config
, params
, obj
):
527 self
._input
_port
= self
._add
_input
_port
('in')
530 def _user_consume(comp_self
):
531 msg
= next(comp_self
._msg
_iter
)
532 if comp_self
._at
== 0:
533 self
.assertIs(type(msg
), bt2
._StreamBeginningMessageConst
)
534 elif comp_self
._at
== 1:
535 self
.assertIs(type(msg
), bt2
._PacketBeginningMessageConst
)
536 elif comp_self
._at
== 2:
537 self
.assertIs(type(msg
), bt2
._EventMessageConst
)
538 elif comp_self
._at
== 3:
539 nonlocal raised_in_sink
540 raised_in_sink
= True
541 raise RuntimeError('error!')
545 def _user_graph_is_configured(self
):
546 self
._msg
_iter
= self
._create
_input
_port
_message
_iterator
(
550 src
= self
._graph
.add_component(MySource
, 'src')
551 sink
= self
._graph
.add_component(MySink
, 'sink')
552 self
._graph
.connect_ports(src
.output_ports
['out'], sink
.input_ports
['in'])
554 with self
.assertRaises(bt2
._Error
):
557 def test_listeners(self
):
558 class MyIter(bt2
._UserMessageIterator
):
562 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
563 def __init__(self
, config
, params
, obj
):
564 self
._add
_output
_port
('out')
565 self
._add
_output
_port
('zero')
567 class MySink(bt2
._UserSinkComponent
):
568 def __init__(self
, config
, params
, obj
):
569 self
._add
_input
_port
('in')
571 def _user_consume(self
):
574 def _user_port_connected(self
, port
, other_port
):
575 self
._add
_input
_port
('taste')
577 def port_added_listener(component
, port
):
579 calls
.append((port_added_listener
, component
, port
))
582 self
._graph
.add_port_added_listener(port_added_listener
)
583 src
= self
._graph
.add_component(MySource
, 'src')
584 sink
= self
._graph
.add_component(MySink
, 'sink')
585 self
._graph
.connect_ports(src
.output_ports
['out'], sink
.input_ports
['in'])
587 self
.assertEqual(len(calls
), 4)
589 self
.assertIs(calls
[0][0], port_added_listener
)
590 self
.assertEqual(calls
[0][1].name
, 'src')
591 self
.assertEqual(calls
[0][2].name
, 'out')
593 self
.assertIs(calls
[1][0], port_added_listener
)
594 self
.assertEqual(calls
[1][1].name
, 'src')
595 self
.assertEqual(calls
[1][2].name
, 'zero')
597 self
.assertIs(calls
[2][0], port_added_listener
)
598 self
.assertEqual(calls
[2][1].name
, 'sink')
599 self
.assertEqual(calls
[2][2].name
, 'in')
601 self
.assertIs(calls
[3][0], port_added_listener
)
602 self
.assertEqual(calls
[3][1].name
, 'sink')
603 self
.assertEqual(calls
[3][2].name
, 'taste')
605 def test_invalid_listeners(self
):
606 class MyIter(bt2
._UserMessageIterator
):
610 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
611 def __init__(self
, config
, params
, obj
):
612 self
._add
_output
_port
('out')
613 self
._add
_output
_port
('zero')
615 class MySink(bt2
._UserSinkComponent
):
616 def __init__(self
, config
, params
, obj
):
617 self
._add
_input
_port
('in')
619 def _user_consume(self
):
622 def _user_port_connected(self
, port
, other_port
):
623 self
._add
_input
_port
('taste')
625 with self
.assertRaises(TypeError):
626 self
._graph
.add_port_added_listener(1234)
628 def test_raise_in_component_init(self
):
629 class MySink(bt2
._UserSinkComponent
):
630 def __init__(self
, config
, params
, obj
):
631 raise ValueError('oops!')
633 def _user_consume(self
):
638 with self
.assertRaises(bt2
._Error
):
639 graph
.add_component(MySink
, 'comp')
641 def test_raise_in_port_added_listener(self
):
642 class MySink(bt2
._UserSinkComponent
):
643 def __init__(self
, config
, params
, obj
):
644 self
._add
_input
_port
('in')
646 def _user_consume(self
):
649 def port_added_listener(component
, port
):
650 raise ValueError('oh noes!')
653 graph
.add_port_added_listener(port_added_listener
)
655 with self
.assertRaises(bt2
._Error
):
656 graph
.add_component(MySink
, 'comp')
659 if __name__
== '__main__':