1 # SPDX-License-Identifier: GPL-2.0-only
3 # Copyright (C) 2019 EfficiOS Inc.
10 class _MyIter(bt2
._UserMessageIterator
):
11 def __init__(self
, config
, self_output_port
):
15 def _build_meta(self
):
16 self
._tc
= self
._component
._create
_trace
_class
()
18 self
._sc
= self
._tc
.create_stream_class(supports_packets
=True)
19 self
._ec
= self
._sc
.create_event_class(name
="salut")
20 self
._my
_int
_ft
= self
._tc
.create_signed_integer_field_class(32)
21 payload_ft
= self
._tc
.create_structure_field_class()
22 payload_ft
+= [("my_int", self
._my
_int
_ft
)]
23 self
._ec
.payload_field_type
= payload_ft
24 self
._stream
= self
._t
.create_stream(self
._sc
)
25 self
._packet
= self
._stream
.create_packet()
27 def _create_event(self
, value
):
29 ev
.payload_field
["my_int"] = value
30 ev
.packet
= self
._packet
34 class GraphTestCase(unittest
.TestCase
):
36 self
._graph
= bt2
.Graph()
41 def test_create_default(self
):
44 def test_create_known_mip_version(self
):
47 def test_create_invalid_mip_version_type(self
):
48 with self
.assertRaises(TypeError):
51 def test_create_unknown_mip_version(self
):
52 with self
.assertRaisesRegex(ValueError, "unknown MIP version"):
55 def test_default_interrupter(self
):
56 interrupter
= self
._graph
.default_interrupter
57 self
.assertIs(type(interrupter
), bt2
.Interrupter
)
59 def test_add_component_user_cls(self
):
60 class MySink(bt2
._UserSinkComponent
):
61 def _user_consume(self
):
64 comp
= self
._graph
.add_component(MySink
, "salut")
65 self
.assertEqual(comp
.name
, "salut")
67 def test_add_component_gen_cls(self
):
68 class MySink(bt2
._UserSinkComponent
):
69 def _user_consume(self
):
72 comp
= self
._graph
.add_component(MySink
, "salut")
74 comp2
= self
._graph
.add_component(comp
.cls
, "salut2")
75 self
.assertEqual(comp2
.name
, "salut2")
77 def test_add_component_params(self
):
80 class MySink(bt2
._UserSinkComponent
):
81 def __init__(self
, config
, params
, obj
):
85 def _user_consume(self
):
88 params
= {"hello": 23, "path": "/path/to/stuff"}
89 self
._graph
.add_component(MySink
, "salut", params
)
90 self
.assertEqual(params
, comp_params
)
93 def test_add_component_obj_python_comp_cls(self
):
96 class MySink(bt2
._UserSinkComponent
):
97 def __init__(self
, config
, params
, obj
):
101 def _user_consume(self
):
105 self
._graph
.add_component(MySink
, "salut", obj
=obj
)
106 self
.assertIs(comp_obj
, obj
)
109 def test_add_component_obj_none_python_comp_cls(self
):
112 class MySink(bt2
._UserSinkComponent
):
113 def __init__(self
, config
, params
, obj
):
117 def _user_consume(self
):
120 self
._graph
.add_component(MySink
, "salut")
121 self
.assertIsNone(comp_obj
)
124 def test_add_component_obj_non_python_comp_cls(self
):
125 plugin
= bt2
.find_plugin("text", find_in_user_dir
=False, find_in_sys_dir
=False)
126 assert plugin
is not None
127 cc
= plugin
.source_component_classes
["dmesg"]
128 assert cc
is not None
130 with self
.assertRaises(ValueError):
131 self
._graph
.add_component(cc
, "salut", obj
=57)
133 def test_add_component_invalid_cls_type(self
):
134 with self
.assertRaises(TypeError):
135 self
._graph
.add_component(int, "salut")
137 def test_add_component_invalid_logging_level_type(self
):
138 class MySink(bt2
._UserSinkComponent
):
139 def _user_consume(self
):
142 with self
.assertRaises(TypeError):
143 self
._graph
.add_component(MySink
, "salut", logging_level
="yo")
145 def test_add_component_invalid_logging_level_value(self
):
146 class MySink(bt2
._UserSinkComponent
):
147 def _user_consume(self
):
150 with self
.assertRaises(ValueError):
151 self
._graph
.add_component(MySink
, "salut", logging_level
=12345)
153 def test_add_component_invalid_params_type(self
):
154 class MySink(bt2
._UserSinkComponent
):
155 def _user_consume(self
):
158 with self
.assertRaises(TypeError):
159 self
._graph
.add_component(MySink
, "salut", params
=12)
161 def test_add_component_params_dict(self
):
164 class MySink(bt2
._UserSinkComponent
):
165 def __init__(self
, config
, params
, obj
):
169 def _user_consume(self
):
172 params
= {"plage": 12312}
173 self
._graph
.add_component(MySink
, "salut", params
=params
)
175 # Check equality and not identity because `add_component()` method
176 # converts the Python `dict` to a `bt2.MapValue`.
177 self
.assertEqual(params
, params_obj
)
179 def test_add_component_params_mapvalue(self
):
182 class MySink(bt2
._UserSinkComponent
):
183 def __init__(self
, config
, params
, obj
):
187 def _user_consume(self
):
190 params
= bt2
.MapValue({"beachclub": "121"})
191 self
._graph
.add_component(MySink
, "salut", params
=params
)
193 self
.assertEqual(params
, params_obj
)
195 def test_add_component_logging_level(self
):
196 class MySink(bt2
._UserSinkComponent
):
197 def _user_consume(self
):
200 comp
= self
._graph
.add_component(
201 MySink
, "salut", logging_level
=bt2
.LoggingLevel
.DEBUG
203 self
.assertEqual(comp
.logging_level
, bt2
.LoggingLevel
.DEBUG
)
205 def test_connect_ports(self
):
207 bt2
._UserSourceComponent
, message_iterator_class
=bt2
._UserMessageIterator
209 def __init__(self
, config
, params
, obj
):
210 self
._add
_output
_port
("out")
212 class MySink(bt2
._UserSinkComponent
):
213 def __init__(self
, config
, params
, obj
):
214 self
._add
_input
_port
("in")
216 def _user_consume(self
):
219 src
= self
._graph
.add_component(MySource
, "src")
220 sink
= self
._graph
.add_component(MySink
, "sink")
222 conn
= self
._graph
.connect_ports(
223 src
.output_ports
["out"], sink
.input_ports
["in"]
225 self
.assertTrue(src
.output_ports
["out"].is_connected
)
226 self
.assertTrue(sink
.input_ports
["in"].is_connected
)
227 self
.assertEqual(src
.output_ports
["out"].connection
.addr
, conn
.addr
)
228 self
.assertEqual(sink
.input_ports
["in"].connection
.addr
, conn
.addr
)
230 def test_connect_ports_invalid_direction(self
):
232 bt2
._UserSourceComponent
, message_iterator_class
=bt2
._UserMessageIterator
234 def __init__(self
, config
, params
, obj
):
235 self
._add
_output
_port
("out")
237 class MySink(bt2
._UserSinkComponent
):
238 def __init__(self
, config
, params
, obj
):
239 self
._add
_input
_port
("in")
241 def _user_consume(self
):
244 src
= self
._graph
.add_component(MySource
, "src")
245 sink
= self
._graph
.add_component(MySink
, "sink")
247 with self
.assertRaises(TypeError):
248 self
._graph
.connect_ports(sink
.input_ports
["in"], src
.output_ports
["out"])
250 def test_add_interrupter(self
):
251 class MyIter(bt2
._UserMessageIterator
):
255 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
256 def __init__(self
, config
, params
, obj
):
257 self
._add
_output
_port
("out")
259 class MySink(bt2
._UserSinkComponent
):
260 def __init__(self
, config
, params
, obj
):
261 self
._add
_input
_port
("in")
263 def _user_consume(self
):
266 def _user_graph_is_configured(self
):
267 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
269 # add two interrupters, set one of them
270 interrupter1
= bt2
.Interrupter()
271 interrupter2
= bt2
.Interrupter()
272 self
._graph
.add_interrupter(interrupter1
)
273 src
= self
._graph
.add_component(MySource
, "src")
274 sink
= self
._graph
.add_component(MySink
, "sink")
275 self
._graph
.connect_ports(src
.output_ports
["out"], sink
.input_ports
["in"])
276 self
._graph
.add_interrupter(interrupter2
)
278 with self
.assertRaises(bt2
._Error
):
283 with self
.assertRaises(bt2
.TryAgain
):
288 with self
.assertRaises(bt2
._Error
):
291 # Test that Graph.run() raises bt2.Interrupted if the graph gets
292 # interrupted during execution.
293 def test_interrupt_while_running(self
):
294 class MyIter(_MyIter
):
296 return self
._create
_stream
_beginning
_message
(self
._stream
)
298 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
299 def __init__(self
, config
, params
, obj
):
300 self
._add
_output
_port
("out")
302 class MySink(bt2
._UserSinkComponent
):
303 def __init__(self
, config
, params
, obj
):
304 self
._add
_input
_port
("in")
306 def _user_consume(self
):
307 # Pretend that somebody asynchronously interrupted the graph.
309 graph
.default_interrupter
.set()
310 return next(self
._msg
_iter
)
312 def _user_graph_is_configured(self
):
313 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
316 up
= self
._graph
.add_component(MySource
, "down")
317 down
= self
._graph
.add_component(MySink
, "up")
318 self
._graph
.connect_ports(up
.output_ports
["out"], down
.input_ports
["in"])
320 with self
.assertRaises(bt2
.TryAgain
):
324 class MyIter(_MyIter
):
330 msg
= self
._create
_stream
_beginning
_message
(self
._stream
)
332 msg
= self
._create
_packet
_beginning
_message
(self
._packet
)
334 msg
= self
._create
_packet
_end
_message
(self
._packet
)
336 msg
= self
._create
_stream
_end
_message
(self
._stream
)
338 msg
= self
._create
_event
_message
(self
._ec
, self
._packet
)
343 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
344 def __init__(self
, config
, params
, obj
):
345 self
._add
_output
_port
("out")
347 class MySink(bt2
._UserSinkComponent
):
348 def __init__(self
, config
, params
, obj
):
349 self
._input
_port
= self
._add
_input
_port
("in")
352 def _user_consume(comp_self
):
353 msg
= next(comp_self
._msg
_iter
)
355 if comp_self
._at
== 0:
356 self
.assertIs(type(msg
), bt2
._StreamBeginningMessageConst
)
357 elif comp_self
._at
== 1:
358 self
.assertIs(type(msg
), bt2
._PacketBeginningMessageConst
)
359 elif comp_self
._at
>= 2 and comp_self
._at
<= 6:
360 self
.assertIs(type(msg
), bt2
._EventMessageConst
)
361 self
.assertEqual(msg
.event
.cls
.name
, "salut")
362 elif comp_self
._at
== 7:
363 self
.assertIs(type(msg
), bt2
._PacketEndMessageConst
)
364 elif comp_self
._at
== 8:
365 self
.assertIs(type(msg
), bt2
._StreamEndMessageConst
)
369 def _user_graph_is_configured(self
):
370 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_port
)
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"])
377 def test_run_once(self
):
378 class MyIter(_MyIter
):
381 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
382 def __init__(self
, config
, params
, obj
):
383 self
._add
_output
_port
("out")
385 class MySink(bt2
._UserSinkComponent
):
386 def __init__(self
, config
, params
, obj
):
387 self
._input
_port
= self
._add
_input
_port
("in")
389 def _user_consume(comp_self
):
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"])
399 with self
.assertRaises(bt2
.TryAgain
):
400 self
._graph
.run_once()
402 self
.assertEqual(run_count
, 1)
404 def test_run_once_stops(self
):
405 class MyIter(_MyIter
):
408 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
409 def __init__(self
, config
, params
, obj
):
410 self
._add
_output
_port
("out")
412 class MySink(bt2
._UserSinkComponent
):
413 def __init__(self
, config
, params
, obj
):
414 self
._input
_port
= self
._add
_input
_port
("in")
416 def _user_consume(comp_self
):
419 src
= self
._graph
.add_component(MySource
, "src")
420 sink
= self
._graph
.add_component(MySink
, "sink")
421 self
._graph
.connect_ports(src
.output_ports
["out"], sink
.input_ports
["in"])
423 with self
.assertRaises(bt2
.Stop
):
424 self
._graph
.run_once()
426 def test_run_again(self
):
427 class MyIter(_MyIter
):
433 msg
= self
._create
_stream
_beginning
_message
(self
._stream
)
435 msg
= self
._create
_packet
_beginning
_message
(self
._packet
)
437 msg
= self
._create
_event
_message
(self
._ec
, self
._packet
)
442 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
443 def __init__(self
, config
, params
, obj
):
444 self
._add
_output
_port
("out")
446 class MySink(bt2
._UserSinkComponent
):
447 def __init__(self
, config
, params
, obj
):
448 self
._input
_port
= self
._add
_input
_port
("in")
451 def _user_consume(comp_self
):
452 msg
= next(comp_self
._msg
_iter
)
453 if comp_self
._at
== 0:
454 self
.assertIs(type(msg
), bt2
._StreamBeginningMessageConst
)
455 elif comp_self
._at
== 1:
456 self
.assertIs(type(msg
), bt2
._PacketBeginningMessageConst
)
457 elif comp_self
._at
== 2:
458 self
.assertIs(type(msg
), bt2
._EventMessageConst
)
465 def _user_graph_is_configured(self
):
466 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_port
)
468 src
= self
._graph
.add_component(MySource
, "src")
469 sink
= self
._graph
.add_component(MySink
, "sink")
470 self
._graph
.connect_ports(src
.output_ports
["out"], sink
.input_ports
["in"])
472 with self
.assertRaises(bt2
.TryAgain
):
475 def test_run_error(self
):
476 raised_in_sink
= False
478 class MyIter(_MyIter
):
480 # If this gets called after the sink raised an exception, it is
482 nonlocal raised_in_sink
483 assert raised_in_sink
is False
486 msg
= self
._create
_stream
_beginning
_message
(self
._stream
)
488 msg
= self
._create
_packet
_beginning
_message
(self
._packet
)
489 elif self
._at
== 2 or self
._at
== 3:
490 msg
= self
._create
_event
_message
(self
._ec
, self
._packet
)
496 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
497 def __init__(self
, config
, params
, obj
):
498 self
._add
_output
_port
("out")
500 class MySink(bt2
._UserSinkComponent
):
501 def __init__(self
, config
, params
, obj
):
502 self
._input
_port
= self
._add
_input
_port
("in")
505 def _user_consume(comp_self
):
506 msg
= next(comp_self
._msg
_iter
)
507 if comp_self
._at
== 0:
508 self
.assertIs(type(msg
), bt2
._StreamBeginningMessageConst
)
509 elif comp_self
._at
== 1:
510 self
.assertIs(type(msg
), bt2
._PacketBeginningMessageConst
)
511 elif comp_self
._at
== 2:
512 self
.assertIs(type(msg
), bt2
._EventMessageConst
)
513 elif comp_self
._at
== 3:
514 nonlocal raised_in_sink
515 raised_in_sink
= True
516 raise RuntimeError("error!")
520 def _user_graph_is_configured(self
):
521 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_port
)
523 src
= self
._graph
.add_component(MySource
, "src")
524 sink
= self
._graph
.add_component(MySink
, "sink")
525 self
._graph
.connect_ports(src
.output_ports
["out"], sink
.input_ports
["in"])
527 with self
.assertRaises(bt2
._Error
):
530 def test_listeners(self
):
532 bt2
._UserSourceComponent
, message_iterator_class
=bt2
._UserMessageIterator
534 def __init__(self
, config
, params
, obj
):
535 self
._add
_output
_port
("out")
536 self
._add
_output
_port
("zero")
538 class MySink(bt2
._UserSinkComponent
):
539 def __init__(self
, config
, params
, obj
):
540 self
._add
_input
_port
("in")
542 def _user_consume(self
):
545 def _user_port_connected(self
, port
, other_port
):
546 self
._add
_input
_port
("taste")
548 def port_added_listener(component
, port
):
550 calls
.append((port_added_listener
, component
, port
))
553 self
._graph
.add_port_added_listener(port_added_listener
)
554 src
= self
._graph
.add_component(MySource
, "src")
555 sink
= self
._graph
.add_component(MySink
, "sink")
556 self
._graph
.connect_ports(src
.output_ports
["out"], sink
.input_ports
["in"])
558 self
.assertEqual(len(calls
), 4)
560 self
.assertIs(calls
[0][0], port_added_listener
)
561 self
.assertEqual(calls
[0][1].name
, "src")
562 self
.assertEqual(calls
[0][2].name
, "out")
564 self
.assertIs(calls
[1][0], port_added_listener
)
565 self
.assertEqual(calls
[1][1].name
, "src")
566 self
.assertEqual(calls
[1][2].name
, "zero")
568 self
.assertIs(calls
[2][0], port_added_listener
)
569 self
.assertEqual(calls
[2][1].name
, "sink")
570 self
.assertEqual(calls
[2][2].name
, "in")
572 self
.assertIs(calls
[3][0], port_added_listener
)
573 self
.assertEqual(calls
[3][1].name
, "sink")
574 self
.assertEqual(calls
[3][2].name
, "taste")
576 def test_invalid_listeners(self
):
578 bt2
._UserSourceComponent
, message_iterator_class
=bt2
._UserMessageIterator
580 def __init__(self
, config
, params
, obj
):
581 self
._add
_output
_port
("out")
582 self
._add
_output
_port
("zero")
584 class MySink(bt2
._UserSinkComponent
):
585 def __init__(self
, config
, params
, obj
):
586 self
._add
_input
_port
("in")
588 def _user_consume(self
):
591 def _user_port_connected(self
, port
, other_port
):
592 self
._add
_input
_port
("taste")
594 with self
.assertRaises(TypeError):
595 self
._graph
.add_port_added_listener(1234)
597 def test_raise_in_component_init(self
):
598 class MySink(bt2
._UserSinkComponent
):
599 def __init__(self
, config
, params
, obj
):
600 raise ValueError("oops!")
602 def _user_consume(self
):
607 with self
.assertRaises(bt2
._Error
):
608 graph
.add_component(MySink
, "comp")
610 def test_raise_in_port_added_listener(self
):
611 class MySink(bt2
._UserSinkComponent
):
612 def __init__(self
, config
, params
, obj
):
613 self
._add
_input
_port
("in")
615 def _user_consume(self
):
618 def port_added_listener(component
, port
):
619 raise ValueError("oh noes!")
622 graph
.add_port_added_listener(port_added_listener
)
624 with self
.assertRaises(bt2
._Error
):
625 graph
.add_component(MySink
, "comp")
628 if __name__
== "__main__":