1 # SPDX-License-Identifier: GPL-2.0-only
3 # Copyright (C) 2019 EfficiOS Inc.
11 class _MyIter(bt2
._UserMessageIterator
):
12 def __init__(self
, config
, self_output_port
):
16 def _build_meta(self
):
17 self
._tc
= self
._component
._create
_trace
_class
()
19 self
._sc
= self
._tc
.create_stream_class(supports_packets
=True)
20 self
._ec
= self
._sc
.create_event_class(name
="salut")
21 self
._my
_int
_ft
= self
._tc
.create_signed_integer_field_class(32)
22 payload_ft
= self
._tc
.create_structure_field_class()
23 payload_ft
+= [("my_int", self
._my
_int
_ft
)]
24 self
._ec
.payload_field_type
= payload_ft
25 self
._stream
= self
._t
.create_stream(self
._sc
)
26 self
._packet
= self
._stream
.create_packet()
28 def _create_event(self
, value
):
30 ev
.payload_field
["my_int"] = value
31 ev
.packet
= self
._packet
35 class GraphTestCase(unittest
.TestCase
):
37 self
._graph
= bt2
.Graph()
42 def test_create_default(self
):
45 def test_create_known_mip_version(self
):
48 def test_create_invalid_mip_version_type(self
):
49 with self
.assertRaises(TypeError):
52 def test_create_unknown_mip_version(self
):
53 with self
.assertRaisesRegex(ValueError, "unknown MIP version"):
56 def test_default_interrupter(self
):
57 interrupter
= self
._graph
.default_interrupter
58 self
.assertIs(type(interrupter
), bt2
.Interrupter
)
60 def test_add_component_user_cls(self
):
61 class MySink(bt2
._UserSinkComponent
):
62 def _user_consume(self
):
65 comp
= self
._graph
.add_component(MySink
, "salut")
66 self
.assertEqual(comp
.name
, "salut")
68 def test_add_component_gen_cls(self
):
69 class MySink(bt2
._UserSinkComponent
):
70 def _user_consume(self
):
73 comp
= self
._graph
.add_component(MySink
, "salut")
75 comp2
= self
._graph
.add_component(comp
.cls
, "salut2")
76 self
.assertEqual(comp2
.name
, "salut2")
78 def test_add_component_params(self
):
81 class MySink(bt2
._UserSinkComponent
):
82 def __init__(self
, config
, params
, obj
):
86 def _user_consume(self
):
89 params
= {"hello": 23, "path": "/path/to/stuff"}
90 self
._graph
.add_component(MySink
, "salut", params
)
91 self
.assertEqual(params
, comp_params
)
94 def test_add_component_obj_python_comp_cls(self
):
97 class MySink(bt2
._UserSinkComponent
):
98 def __init__(self
, config
, params
, obj
):
102 def _user_consume(self
):
106 self
._graph
.add_component(MySink
, "salut", obj
=obj
)
107 self
.assertIs(comp_obj
, obj
)
110 def test_add_component_obj_none_python_comp_cls(self
):
113 class MySink(bt2
._UserSinkComponent
):
114 def __init__(self
, config
, params
, obj
):
118 def _user_consume(self
):
121 self
._graph
.add_component(MySink
, "salut")
122 self
.assertIsNone(comp_obj
)
125 def test_add_component_obj_non_python_comp_cls(self
):
126 plugin
= bt2
.find_plugin("text", find_in_user_dir
=False, find_in_sys_dir
=False)
127 assert plugin
is not None
128 cc
= plugin
.source_component_classes
["dmesg"]
129 assert cc
is not None
131 with self
.assertRaises(ValueError):
132 self
._graph
.add_component(cc
, "salut", obj
=57)
134 def test_add_component_invalid_cls_type(self
):
135 with self
.assertRaises(TypeError):
136 self
._graph
.add_component(int, "salut")
138 def test_add_component_invalid_logging_level_type(self
):
139 class MySink(bt2
._UserSinkComponent
):
140 def _user_consume(self
):
143 with self
.assertRaises(TypeError):
144 self
._graph
.add_component(MySink
, "salut", logging_level
="yo")
146 def test_add_component_invalid_logging_level_value(self
):
147 class MySink(bt2
._UserSinkComponent
):
148 def _user_consume(self
):
151 with self
.assertRaises(ValueError):
152 self
._graph
.add_component(MySink
, "salut", logging_level
=12345)
154 def test_add_component_invalid_params_type(self
):
155 class MySink(bt2
._UserSinkComponent
):
156 def _user_consume(self
):
159 with self
.assertRaises(TypeError):
160 self
._graph
.add_component(MySink
, "salut", params
=12)
162 def test_add_component_params_dict(self
):
165 class MySink(bt2
._UserSinkComponent
):
166 def __init__(self
, config
, params
, obj
):
170 def _user_consume(self
):
173 params
= {"plage": 12312}
174 self
._graph
.add_component(MySink
, "salut", params
=params
)
176 # Check equality and not identity because `add_component()` method
177 # converts the Python `dict` to a `bt2.MapValue`.
178 self
.assertEqual(params
, params_obj
)
180 def test_add_component_params_mapvalue(self
):
183 class MySink(bt2
._UserSinkComponent
):
184 def __init__(self
, config
, params
, obj
):
188 def _user_consume(self
):
191 params
= bt2
.MapValue({"beachclub": "121"})
192 self
._graph
.add_component(MySink
, "salut", params
=params
)
194 self
.assertEqual(params
, params_obj
)
196 def test_add_component_logging_level(self
):
197 class MySink(bt2
._UserSinkComponent
):
198 def _user_consume(self
):
201 comp
= self
._graph
.add_component(
202 MySink
, "salut", logging_level
=bt2
.LoggingLevel
.DEBUG
204 self
.assertEqual(comp
.logging_level
, bt2
.LoggingLevel
.DEBUG
)
206 def test_connect_ports(self
):
208 bt2
._UserSourceComponent
, message_iterator_class
=bt2
._UserMessageIterator
210 def __init__(self
, config
, params
, obj
):
211 self
._add
_output
_port
("out")
213 class MySink(bt2
._UserSinkComponent
):
214 def __init__(self
, config
, params
, obj
):
215 self
._add
_input
_port
("in")
217 def _user_consume(self
):
220 src
= self
._graph
.add_component(MySource
, "src")
221 sink
= self
._graph
.add_component(MySink
, "sink")
223 conn
= self
._graph
.connect_ports(
224 src
.output_ports
["out"], sink
.input_ports
["in"]
226 self
.assertTrue(src
.output_ports
["out"].is_connected
)
227 self
.assertTrue(sink
.input_ports
["in"].is_connected
)
228 self
.assertEqual(src
.output_ports
["out"].connection
.addr
, conn
.addr
)
229 self
.assertEqual(sink
.input_ports
["in"].connection
.addr
, conn
.addr
)
231 def test_connect_ports_invalid_direction(self
):
233 bt2
._UserSourceComponent
, message_iterator_class
=bt2
._UserMessageIterator
235 def __init__(self
, config
, params
, obj
):
236 self
._add
_output
_port
("out")
238 class MySink(bt2
._UserSinkComponent
):
239 def __init__(self
, config
, params
, obj
):
240 self
._add
_input
_port
("in")
242 def _user_consume(self
):
245 src
= self
._graph
.add_component(MySource
, "src")
246 sink
= self
._graph
.add_component(MySink
, "sink")
248 with self
.assertRaises(TypeError):
249 self
._graph
.connect_ports(sink
.input_ports
["in"], src
.output_ports
["out"])
251 def test_add_interrupter(self
):
252 class MyIter(bt2
._UserMessageIterator
):
256 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
257 def __init__(self
, config
, params
, obj
):
258 self
._add
_output
_port
("out")
260 class MySink(bt2
._UserSinkComponent
):
261 def __init__(self
, config
, params
, obj
):
262 self
._add
_input
_port
("in")
264 def _user_consume(self
):
267 def _user_graph_is_configured(self
):
268 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
270 # add two interrupters, set one of them
271 interrupter1
= bt2
.Interrupter()
272 interrupter2
= bt2
.Interrupter()
273 self
._graph
.add_interrupter(interrupter1
)
274 src
= self
._graph
.add_component(MySource
, "src")
275 sink
= self
._graph
.add_component(MySink
, "sink")
276 self
._graph
.connect_ports(src
.output_ports
["out"], sink
.input_ports
["in"])
277 self
._graph
.add_interrupter(interrupter2
)
279 with self
.assertRaises(bt2
._Error
):
284 with self
.assertRaises(bt2
.TryAgain
):
289 with self
.assertRaises(bt2
._Error
):
292 # Test that Graph.run() raises bt2.Interrupted if the graph gets
293 # interrupted during execution.
294 def test_interrupt_while_running(self
):
295 class MyIter(_MyIter
):
297 return self
._create
_stream
_beginning
_message
(self
._stream
)
299 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
300 def __init__(self
, config
, params
, obj
):
301 self
._add
_output
_port
("out")
303 class MySink(bt2
._UserSinkComponent
):
304 def __init__(self
, config
, params
, obj
):
305 self
._add
_input
_port
("in")
307 def _user_consume(self
):
308 # Pretend that somebody asynchronously interrupted the graph.
310 graph
.default_interrupter
.set()
311 return next(self
._msg
_iter
)
313 def _user_graph_is_configured(self
):
314 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
317 up
= self
._graph
.add_component(MySource
, "down")
318 down
= self
._graph
.add_component(MySink
, "up")
319 self
._graph
.connect_ports(up
.output_ports
["out"], down
.input_ports
["in"])
321 with self
.assertRaises(bt2
.TryAgain
):
325 class MyIter(_MyIter
):
331 msg
= self
._create
_stream
_beginning
_message
(self
._stream
)
333 msg
= self
._create
_packet
_beginning
_message
(self
._packet
)
335 msg
= self
._create
_packet
_end
_message
(self
._packet
)
337 msg
= self
._create
_stream
_end
_message
(self
._stream
)
339 msg
= self
._create
_event
_message
(self
._ec
, self
._packet
)
344 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
345 def __init__(self
, config
, params
, obj
):
346 self
._add
_output
_port
("out")
348 class MySink(bt2
._UserSinkComponent
):
349 def __init__(self
, config
, params
, obj
):
350 self
._input
_port
= self
._add
_input
_port
("in")
353 def _user_consume(comp_self
):
354 msg
= next(comp_self
._msg
_iter
)
356 if comp_self
._at
== 0:
357 self
.assertIs(type(msg
), bt2
._StreamBeginningMessageConst
)
358 elif comp_self
._at
== 1:
359 self
.assertIs(type(msg
), bt2
._PacketBeginningMessageConst
)
360 elif comp_self
._at
>= 2 and comp_self
._at
<= 6:
361 self
.assertIs(type(msg
), bt2
._EventMessageConst
)
362 self
.assertEqual(msg
.event
.cls
.name
, "salut")
363 elif comp_self
._at
== 7:
364 self
.assertIs(type(msg
), bt2
._PacketEndMessageConst
)
365 elif comp_self
._at
== 8:
366 self
.assertIs(type(msg
), bt2
._StreamEndMessageConst
)
370 def _user_graph_is_configured(self
):
371 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_port
)
373 src
= self
._graph
.add_component(MySource
, "src")
374 sink
= self
._graph
.add_component(MySink
, "sink")
375 self
._graph
.connect_ports(src
.output_ports
["out"], sink
.input_ports
["in"])
378 def test_run_once(self
):
379 class MyIter(_MyIter
):
382 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
383 def __init__(self
, config
, params
, obj
):
384 self
._add
_output
_port
("out")
386 class MySink(bt2
._UserSinkComponent
):
387 def __init__(self
, config
, params
, obj
):
388 self
._input
_port
= self
._add
_input
_port
("in")
390 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
.TryAgain
):
401 self
._graph
.run_once()
403 self
.assertEqual(run_count
, 1)
405 def test_run_once_stops(self
):
406 class MyIter(_MyIter
):
409 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
410 def __init__(self
, config
, params
, obj
):
411 self
._add
_output
_port
("out")
413 class MySink(bt2
._UserSinkComponent
):
414 def __init__(self
, config
, params
, obj
):
415 self
._input
_port
= self
._add
_input
_port
("in")
417 def _user_consume(comp_self
):
420 src
= self
._graph
.add_component(MySource
, "src")
421 sink
= self
._graph
.add_component(MySink
, "sink")
422 self
._graph
.connect_ports(src
.output_ports
["out"], sink
.input_ports
["in"])
424 with self
.assertRaises(bt2
.Stop
):
425 self
._graph
.run_once()
427 def test_run_again(self
):
428 class MyIter(_MyIter
):
434 msg
= self
._create
_stream
_beginning
_message
(self
._stream
)
436 msg
= self
._create
_packet
_beginning
_message
(self
._packet
)
438 msg
= self
._create
_event
_message
(self
._ec
, self
._packet
)
443 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
444 def __init__(self
, config
, params
, obj
):
445 self
._add
_output
_port
("out")
447 class MySink(bt2
._UserSinkComponent
):
448 def __init__(self
, config
, params
, obj
):
449 self
._input
_port
= self
._add
_input
_port
("in")
452 def _user_consume(comp_self
):
453 msg
= next(comp_self
._msg
_iter
)
454 if comp_self
._at
== 0:
455 self
.assertIs(type(msg
), bt2
._StreamBeginningMessageConst
)
456 elif comp_self
._at
== 1:
457 self
.assertIs(type(msg
), bt2
._PacketBeginningMessageConst
)
458 elif comp_self
._at
== 2:
459 self
.assertIs(type(msg
), bt2
._EventMessageConst
)
466 def _user_graph_is_configured(self
):
467 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_port
)
469 src
= self
._graph
.add_component(MySource
, "src")
470 sink
= self
._graph
.add_component(MySink
, "sink")
471 self
._graph
.connect_ports(src
.output_ports
["out"], sink
.input_ports
["in"])
473 with self
.assertRaises(bt2
.TryAgain
):
476 def test_run_error(self
):
477 raised_in_sink
= False
479 class MyIter(_MyIter
):
481 # If this gets called after the sink raised an exception, it is
483 nonlocal raised_in_sink
484 assert raised_in_sink
is False
487 msg
= self
._create
_stream
_beginning
_message
(self
._stream
)
489 msg
= self
._create
_packet
_beginning
_message
(self
._packet
)
490 elif self
._at
== 2 or self
._at
== 3:
491 msg
= self
._create
_event
_message
(self
._ec
, self
._packet
)
497 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
498 def __init__(self
, config
, params
, obj
):
499 self
._add
_output
_port
("out")
501 class MySink(bt2
._UserSinkComponent
):
502 def __init__(self
, config
, params
, obj
):
503 self
._input
_port
= self
._add
_input
_port
("in")
506 def _user_consume(comp_self
):
507 msg
= next(comp_self
._msg
_iter
)
508 if comp_self
._at
== 0:
509 self
.assertIs(type(msg
), bt2
._StreamBeginningMessageConst
)
510 elif comp_self
._at
== 1:
511 self
.assertIs(type(msg
), bt2
._PacketBeginningMessageConst
)
512 elif comp_self
._at
== 2:
513 self
.assertIs(type(msg
), bt2
._EventMessageConst
)
514 elif comp_self
._at
== 3:
515 nonlocal raised_in_sink
516 raised_in_sink
= True
517 raise RuntimeError("error!")
521 def _user_graph_is_configured(self
):
522 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_port
)
524 src
= self
._graph
.add_component(MySource
, "src")
525 sink
= self
._graph
.add_component(MySink
, "sink")
526 self
._graph
.connect_ports(src
.output_ports
["out"], sink
.input_ports
["in"])
528 with self
.assertRaises(bt2
._Error
):
531 def test_listeners(self
):
533 bt2
._UserSourceComponent
, message_iterator_class
=bt2
._UserMessageIterator
535 def __init__(self
, config
, params
, obj
):
536 self
._add
_output
_port
("out")
537 self
._add
_output
_port
("zero")
539 class MySink(bt2
._UserSinkComponent
):
540 def __init__(self
, config
, params
, obj
):
541 self
._add
_input
_port
("in")
543 def _user_consume(self
):
546 def _user_port_connected(self
, port
, other_port
):
547 self
._add
_input
_port
("taste")
549 def port_added_listener(component
, port
):
551 calls
.append((port_added_listener
, component
, port
))
554 self
._graph
.add_port_added_listener(port_added_listener
)
555 src
= self
._graph
.add_component(MySource
, "src")
556 sink
= self
._graph
.add_component(MySink
, "sink")
557 self
._graph
.connect_ports(src
.output_ports
["out"], sink
.input_ports
["in"])
559 self
.assertEqual(len(calls
), 4)
561 self
.assertIs(calls
[0][0], port_added_listener
)
562 self
.assertEqual(calls
[0][1].name
, "src")
563 self
.assertEqual(calls
[0][2].name
, "out")
565 self
.assertIs(calls
[1][0], port_added_listener
)
566 self
.assertEqual(calls
[1][1].name
, "src")
567 self
.assertEqual(calls
[1][2].name
, "zero")
569 self
.assertIs(calls
[2][0], port_added_listener
)
570 self
.assertEqual(calls
[2][1].name
, "sink")
571 self
.assertEqual(calls
[2][2].name
, "in")
573 self
.assertIs(calls
[3][0], port_added_listener
)
574 self
.assertEqual(calls
[3][1].name
, "sink")
575 self
.assertEqual(calls
[3][2].name
, "taste")
577 def test_invalid_listeners(self
):
579 bt2
._UserSourceComponent
, message_iterator_class
=bt2
._UserMessageIterator
581 def __init__(self
, config
, params
, obj
):
582 self
._add
_output
_port
("out")
583 self
._add
_output
_port
("zero")
585 class MySink(bt2
._UserSinkComponent
):
586 def __init__(self
, config
, params
, obj
):
587 self
._add
_input
_port
("in")
589 def _user_consume(self
):
592 def _user_port_connected(self
, port
, other_port
):
593 self
._add
_input
_port
("taste")
595 with self
.assertRaises(TypeError):
596 self
._graph
.add_port_added_listener(1234)
598 def test_raise_in_component_init(self
):
599 class MySink(bt2
._UserSinkComponent
):
600 def __init__(self
, config
, params
, obj
):
601 raise ValueError("oops!")
603 def _user_consume(self
):
608 with self
.assertRaises(bt2
._Error
):
609 graph
.add_component(MySink
, "comp")
611 def test_raise_in_port_added_listener(self
):
612 class MySink(bt2
._UserSinkComponent
):
613 def __init__(self
, config
, params
, obj
):
614 self
._add
_input
_port
("in")
616 def _user_consume(self
):
619 def port_added_listener(component
, port
):
620 raise ValueError("oh noes!")
623 graph
.add_port_added_listener(port_added_listener
)
625 with self
.assertRaises(bt2
._Error
):
626 graph
.add_component(MySink
, "comp")
629 if __name__
== "__main__":