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
, 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_add_component_user_cls(self
):
69 class MySink(bt2
._UserSinkComponent
):
70 def _user_consume(self
):
73 comp
= self
._graph
.add_component(MySink
, 'salut')
74 self
.assertEqual(comp
.name
, 'salut')
76 def test_add_component_gen_cls(self
):
77 class MySink(bt2
._UserSinkComponent
):
78 def _user_consume(self
):
81 comp
= self
._graph
.add_component(MySink
, 'salut')
83 comp2
= self
._graph
.add_component(comp
.cls
, 'salut2')
84 self
.assertEqual(comp2
.name
, 'salut2')
86 def test_add_component_params(self
):
89 class MySink(bt2
._UserSinkComponent
):
90 def __init__(self
, config
, params
, obj
):
94 def _user_consume(self
):
97 params
= {'hello': 23, 'path': '/path/to/stuff'}
98 self
._graph
.add_component(MySink
, 'salut', params
)
99 self
.assertEqual(params
, comp_params
)
102 def test_add_component_obj_python_comp_cls(self
):
105 class MySink(bt2
._UserSinkComponent
):
106 def __init__(self
, config
, params
, obj
):
110 def _user_consume(self
):
114 self
._graph
.add_component(MySink
, 'salut', obj
=obj
)
115 self
.assertIs(comp_obj
, obj
)
118 def test_add_component_obj_none_python_comp_cls(self
):
121 class MySink(bt2
._UserSinkComponent
):
122 def __init__(self
, config
, params
, obj
):
126 def _user_consume(self
):
129 self
._graph
.add_component(MySink
, 'salut')
130 self
.assertIsNone(comp_obj
)
133 def test_add_component_obj_non_python_comp_cls(self
):
134 plugin
= bt2
.find_plugin('text', find_in_user_dir
=False, find_in_sys_dir
=False)
135 assert plugin
is not None
136 cc
= plugin
.source_component_classes
['dmesg']
137 assert cc
is not None
139 with self
.assertRaises(ValueError):
140 self
._graph
.add_component(cc
, 'salut', obj
=57)
142 def test_add_component_invalid_cls_type(self
):
143 with self
.assertRaises(TypeError):
144 self
._graph
.add_component(int, 'salut')
146 def test_add_component_invalid_logging_level_type(self
):
147 class MySink(bt2
._UserSinkComponent
):
148 def _user_consume(self
):
151 with self
.assertRaises(TypeError):
152 self
._graph
.add_component(MySink
, 'salut', logging_level
='yo')
154 def test_add_component_invalid_logging_level_value(self
):
155 class MySink(bt2
._UserSinkComponent
):
156 def _user_consume(self
):
159 with self
.assertRaises(ValueError):
160 self
._graph
.add_component(MySink
, 'salut', logging_level
=12345)
162 def test_add_component_logging_level(self
):
163 class MySink(bt2
._UserSinkComponent
):
164 def _user_consume(self
):
167 comp
= self
._graph
.add_component(
168 MySink
, 'salut', logging_level
=bt2
.LoggingLevel
.DEBUG
170 self
.assertEqual(comp
.logging_level
, bt2
.LoggingLevel
.DEBUG
)
172 def test_connect_ports(self
):
173 class MyIter(bt2
._UserMessageIterator
):
177 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
178 def __init__(self
, config
, params
, obj
):
179 self
._add
_output
_port
('out')
181 class MySink(bt2
._UserSinkComponent
):
182 def __init__(self
, config
, params
, obj
):
183 self
._add
_input
_port
('in')
185 def _user_consume(self
):
188 src
= self
._graph
.add_component(MySource
, 'src')
189 sink
= self
._graph
.add_component(MySink
, 'sink')
191 conn
= self
._graph
.connect_ports(
192 src
.output_ports
['out'], sink
.input_ports
['in']
194 self
.assertTrue(src
.output_ports
['out'].is_connected
)
195 self
.assertTrue(sink
.input_ports
['in'].is_connected
)
196 self
.assertEqual(src
.output_ports
['out'].connection
.addr
, conn
.addr
)
197 self
.assertEqual(sink
.input_ports
['in'].connection
.addr
, conn
.addr
)
199 def test_connect_ports_invalid_direction(self
):
200 class MyIter(bt2
._UserMessageIterator
):
204 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
205 def __init__(self
, config
, params
, obj
):
206 self
._add
_output
_port
('out')
208 class MySink(bt2
._UserSinkComponent
):
209 def __init__(self
, config
, params
, obj
):
210 self
._add
_input
_port
('in')
212 def _user_consume(self
):
215 src
= self
._graph
.add_component(MySource
, 'src')
216 sink
= self
._graph
.add_component(MySink
, 'sink')
218 with self
.assertRaises(TypeError):
219 self
._graph
.connect_ports(sink
.input_ports
['in'], src
.output_ports
['out'])
221 def test_add_interrupter(self
):
222 class MyIter(bt2
._UserMessageIterator
):
226 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
227 def __init__(self
, config
, params
, obj
):
228 self
._add
_output
_port
('out')
230 class MySink(bt2
._UserSinkComponent
):
231 def __init__(self
, config
, params
, obj
):
232 self
._add
_input
_port
('in')
234 def _user_consume(self
):
237 def _user_graph_is_configured(self
):
238 self
._msg
_iter
= self
._create
_input
_port
_message
_iterator
(
239 self
._input
_ports
['in']
242 # add two interrupters, set one of them
243 interrupter1
= bt2
.Interrupter()
244 interrupter2
= bt2
.Interrupter()
245 self
._graph
.add_interrupter(interrupter1
)
246 src
= self
._graph
.add_component(MySource
, 'src')
247 sink
= self
._graph
.add_component(MySink
, 'sink')
248 self
._graph
.connect_ports(src
.output_ports
['out'], sink
.input_ports
['in'])
249 self
._graph
.add_interrupter(interrupter2
)
251 with self
.assertRaises(bt2
._Error
):
256 with self
.assertRaises(bt2
.TryAgain
):
261 with self
.assertRaises(bt2
._Error
):
264 # Test that Graph.run() raises bt2.Interrupted if the graph gets
265 # interrupted during execution.
266 def test_interrupt_while_running(self
):
267 class MyIter(_MyIter
):
269 return self
._create
_stream
_beginning
_message
(self
._stream
)
271 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
272 def __init__(self
, config
, params
, obj
):
273 self
._add
_output
_port
('out')
275 class MySink(bt2
._UserSinkComponent
):
276 def __init__(self
, config
, params
, obj
):
277 self
._add
_input
_port
('in')
279 def _user_consume(self
):
280 # Pretend that somebody asynchronously interrupted the graph.
283 return next(self
._msg
_iter
)
285 def _user_graph_is_configured(self
):
286 self
._msg
_iter
= self
._create
_input
_port
_message
_iterator
(
287 self
._input
_ports
['in']
291 up
= self
._graph
.add_component(MySource
, 'down')
292 down
= self
._graph
.add_component(MySink
, 'up')
293 self
._graph
.connect_ports(up
.output_ports
['out'], down
.input_ports
['in'])
295 with self
.assertRaises(bt2
.TryAgain
):
299 class MyIter(_MyIter
):
305 msg
= self
._create
_stream
_beginning
_message
(self
._stream
)
307 msg
= self
._create
_packet
_beginning
_message
(self
._packet
)
309 msg
= self
._create
_packet
_end
_message
(self
._packet
)
311 msg
= self
._create
_stream
_end
_message
(self
._stream
)
313 msg
= self
._create
_event
_message
(self
._ec
, self
._packet
)
318 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
319 def __init__(self
, config
, params
, obj
):
320 self
._add
_output
_port
('out')
322 class MySink(bt2
._UserSinkComponent
):
323 def __init__(self
, config
, params
, obj
):
324 self
._input
_port
= self
._add
_input
_port
('in')
327 def _user_consume(comp_self
):
328 msg
= next(comp_self
._msg
_iter
)
330 if comp_self
._at
== 0:
331 self
.assertIs(type(msg
), bt2
._StreamBeginningMessageConst
)
332 elif comp_self
._at
== 1:
333 self
.assertIs(type(msg
), bt2
._PacketBeginningMessageConst
)
334 elif comp_self
._at
>= 2 and comp_self
._at
<= 6:
335 self
.assertIs(type(msg
), bt2
._EventMessageConst
)
336 self
.assertEqual(msg
.event
.cls
.name
, 'salut')
337 elif comp_self
._at
== 7:
338 self
.assertIs(type(msg
), bt2
._PacketEndMessageConst
)
339 elif comp_self
._at
== 8:
340 self
.assertIs(type(msg
), bt2
._StreamEndMessageConst
)
344 def _user_graph_is_configured(self
):
345 self
._msg
_iter
= self
._create
_input
_port
_message
_iterator
(
349 src
= self
._graph
.add_component(MySource
, 'src')
350 sink
= self
._graph
.add_component(MySink
, 'sink')
351 self
._graph
.connect_ports(src
.output_ports
['out'], sink
.input_ports
['in'])
354 def test_run_once(self
):
355 class MyIter(_MyIter
):
358 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
359 def __init__(self
, config
, params
, obj
):
360 self
._add
_output
_port
('out')
362 class MySink(bt2
._UserSinkComponent
):
363 def __init__(self
, config
, params
, obj
):
364 self
._input
_port
= self
._add
_input
_port
('in')
366 def _user_consume(comp_self
):
372 src
= self
._graph
.add_component(MySource
, 'src')
373 sink
= self
._graph
.add_component(MySink
, 'sink')
374 self
._graph
.connect_ports(src
.output_ports
['out'], sink
.input_ports
['in'])
376 with self
.assertRaises(bt2
.TryAgain
):
377 self
._graph
.run_once()
379 self
.assertEqual(run_count
, 1)
381 def test_run_once_stops(self
):
382 class MyIter(_MyIter
):
385 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
386 def __init__(self
, config
, params
, obj
):
387 self
._add
_output
_port
('out')
389 class MySink(bt2
._UserSinkComponent
):
390 def __init__(self
, config
, params
, obj
):
391 self
._input
_port
= self
._add
_input
_port
('in')
393 def _user_consume(comp_self
):
396 src
= self
._graph
.add_component(MySource
, 'src')
397 sink
= self
._graph
.add_component(MySink
, 'sink')
398 self
._graph
.connect_ports(src
.output_ports
['out'], sink
.input_ports
['in'])
400 with self
.assertRaises(bt2
.Stop
):
401 self
._graph
.run_once()
403 def test_run_again(self
):
404 class MyIter(_MyIter
):
410 msg
= self
._create
_stream
_beginning
_message
(self
._stream
)
412 msg
= self
._create
_packet
_beginning
_message
(self
._packet
)
414 msg
= self
._create
_event
_message
(self
._ec
, self
._packet
)
419 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
420 def __init__(self
, config
, params
, obj
):
421 self
._add
_output
_port
('out')
423 class MySink(bt2
._UserSinkComponent
):
424 def __init__(self
, config
, params
, obj
):
425 self
._input
_port
= self
._add
_input
_port
('in')
428 def _user_consume(comp_self
):
429 msg
= next(comp_self
._msg
_iter
)
430 if comp_self
._at
== 0:
431 self
.assertIs(type(msg
), bt2
._StreamBeginningMessageConst
)
432 elif comp_self
._at
== 1:
433 self
.assertIs(type(msg
), bt2
._PacketBeginningMessageConst
)
434 elif comp_self
._at
== 2:
435 self
.assertIs(type(msg
), bt2
._EventMessageConst
)
442 def _user_graph_is_configured(self
):
443 self
._msg
_iter
= self
._create
_input
_port
_message
_iterator
(
447 src
= self
._graph
.add_component(MySource
, 'src')
448 sink
= self
._graph
.add_component(MySink
, 'sink')
449 self
._graph
.connect_ports(src
.output_ports
['out'], sink
.input_ports
['in'])
451 with self
.assertRaises(bt2
.TryAgain
):
454 def test_run_error(self
):
455 raised_in_sink
= False
457 class MyIter(_MyIter
):
459 # If this gets called after the sink raised an exception, it is
461 nonlocal raised_in_sink
462 assert raised_in_sink
is False
465 msg
= self
._create
_stream
_beginning
_message
(self
._stream
)
467 msg
= self
._create
_packet
_beginning
_message
(self
._packet
)
468 elif self
._at
== 2 or self
._at
== 3:
469 msg
= self
._create
_event
_message
(self
._ec
, self
._packet
)
475 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
476 def __init__(self
, config
, params
, obj
):
477 self
._add
_output
_port
('out')
479 class MySink(bt2
._UserSinkComponent
):
480 def __init__(self
, config
, params
, obj
):
481 self
._input
_port
= self
._add
_input
_port
('in')
484 def _user_consume(comp_self
):
485 msg
= next(comp_self
._msg
_iter
)
486 if comp_self
._at
== 0:
487 self
.assertIs(type(msg
), bt2
._StreamBeginningMessageConst
)
488 elif comp_self
._at
== 1:
489 self
.assertIs(type(msg
), bt2
._PacketBeginningMessageConst
)
490 elif comp_self
._at
== 2:
491 self
.assertIs(type(msg
), bt2
._EventMessageConst
)
492 elif comp_self
._at
== 3:
493 nonlocal raised_in_sink
494 raised_in_sink
= True
495 raise RuntimeError('error!')
499 def _user_graph_is_configured(self
):
500 self
._msg
_iter
= self
._create
_input
_port
_message
_iterator
(
504 src
= self
._graph
.add_component(MySource
, 'src')
505 sink
= self
._graph
.add_component(MySink
, 'sink')
506 self
._graph
.connect_ports(src
.output_ports
['out'], sink
.input_ports
['in'])
508 with self
.assertRaises(bt2
._Error
):
511 def test_listeners(self
):
512 class MyIter(bt2
._UserMessageIterator
):
516 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
517 def __init__(self
, config
, params
, obj
):
518 self
._add
_output
_port
('out')
519 self
._add
_output
_port
('zero')
521 class MySink(bt2
._UserSinkComponent
):
522 def __init__(self
, config
, params
, obj
):
523 self
._add
_input
_port
('in')
525 def _user_consume(self
):
528 def _user_port_connected(self
, port
, other_port
):
529 self
._add
_input
_port
('taste')
531 def port_added_listener(component
, port
):
533 calls
.append((port_added_listener
, component
, port
))
535 def ports_connected_listener(
536 upstream_component
, upstream_port
, downstream_component
, downstream_port
541 ports_connected_listener
,
544 downstream_component
,
550 self
._graph
.add_port_added_listener(port_added_listener
)
551 self
._graph
.add_ports_connected_listener(ports_connected_listener
)
552 src
= self
._graph
.add_component(MySource
, 'src')
553 sink
= self
._graph
.add_component(MySink
, 'sink')
554 self
._graph
.connect_ports(src
.output_ports
['out'], sink
.input_ports
['in'])
556 self
.assertEqual(len(calls
), 5)
558 self
.assertIs(calls
[0][0], port_added_listener
)
559 self
.assertEqual(calls
[0][1].name
, 'src')
560 self
.assertEqual(calls
[0][2].name
, 'out')
562 self
.assertIs(calls
[1][0], port_added_listener
)
563 self
.assertEqual(calls
[1][1].name
, 'src')
564 self
.assertEqual(calls
[1][2].name
, 'zero')
566 self
.assertIs(calls
[2][0], port_added_listener
)
567 self
.assertEqual(calls
[2][1].name
, 'sink')
568 self
.assertEqual(calls
[2][2].name
, 'in')
570 self
.assertIs(calls
[3][0], port_added_listener
)
571 self
.assertEqual(calls
[3][1].name
, 'sink')
572 self
.assertEqual(calls
[3][2].name
, 'taste')
574 self
.assertIs(calls
[4][0], ports_connected_listener
)
575 self
.assertEqual(calls
[4][1].name
, 'src')
576 self
.assertEqual(calls
[4][2].name
, 'out')
577 self
.assertEqual(calls
[4][3].name
, 'sink')
578 self
.assertEqual(calls
[4][4].name
, 'in')
580 def test_invalid_listeners(self
):
581 class MyIter(bt2
._UserMessageIterator
):
585 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
586 def __init__(self
, config
, params
, obj
):
587 self
._add
_output
_port
('out')
588 self
._add
_output
_port
('zero')
590 class MySink(bt2
._UserSinkComponent
):
591 def __init__(self
, config
, params
, obj
):
592 self
._add
_input
_port
('in')
594 def _user_consume(self
):
597 def _user_port_connected(self
, port
, other_port
):
598 self
._add
_input
_port
('taste')
600 with self
.assertRaises(TypeError):
601 self
._graph
.add_port_added_listener(1234)
602 with self
.assertRaises(TypeError):
603 self
._graph
.add_ports_connected_listener(1234)
605 def test_raise_in_component_init(self
):
606 class MySink(bt2
._UserSinkComponent
):
607 def __init__(self
, config
, params
, obj
):
608 raise ValueError('oops!')
610 def _user_consume(self
):
615 with self
.assertRaises(bt2
._Error
):
616 graph
.add_component(MySink
, 'comp')
618 def test_raise_in_port_added_listener(self
):
619 class MySink(bt2
._UserSinkComponent
):
620 def __init__(self
, config
, params
, obj
):
621 self
._add
_input
_port
('in')
623 def _user_consume(self
):
626 def port_added_listener(component
, port
):
627 raise ValueError('oh noes!')
630 graph
.add_port_added_listener(port_added_listener
)
632 with self
.assertRaises(bt2
._Error
):
633 graph
.add_component(MySink
, 'comp')
635 def test_raise_in_ports_connected_listener(self
):
636 class MyIter(bt2
._UserMessageIterator
):
640 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
641 def __init__(self
, config
, params
, obj
):
642 self
._add
_output
_port
('out')
644 class MySink(bt2
._UserSinkComponent
):
645 def __init__(self
, config
, params
, obj
):
646 self
._add
_input
_port
('in')
648 def _user_consume(self
):
651 def ports_connected_listener(
652 upstream_component
, upstream_port
, downstream_component
, downstream_port
654 raise ValueError('oh noes!')
657 graph
.add_ports_connected_listener(ports_connected_listener
)
658 up
= graph
.add_component(MySource
, 'down')
659 down
= graph
.add_component(MySink
, 'up')
661 with self
.assertRaises(bt2
._Error
):
662 graph
.connect_ports(up
.output_ports
['out'], down
.input_ports
['in'])
665 if __name__
== '__main__':