Commit | Line | Data |
---|---|---|
0235b0db | 1 | # SPDX-License-Identifier: GPL-2.0-only |
d2d857a8 MJ |
2 | # |
3 | # Copyright (C) 2019 EfficiOS Inc. | |
4 | # | |
d2d857a8 | 5 | |
811644b8 | 6 | import unittest |
5995b304 | 7 | |
811644b8 PP |
8 | import bt2 |
9 | ||
10 | ||
5f25509b | 11 | class _MyIter(bt2._UserMessageIterator): |
8d8b141d | 12 | def __init__(self, config, self_output_port): |
5f25509b SM |
13 | self._build_meta() |
14 | self._at = 0 | |
15 | ||
16 | def _build_meta(self): | |
17 | self._tc = self._component._create_trace_class() | |
18 | self._t = self._tc() | |
26fc5aed | 19 | self._sc = self._tc.create_stream_class(supports_packets=True) |
f5567ea8 | 20 | self._ec = self._sc.create_event_class(name="salut") |
5f25509b SM |
21 | self._my_int_ft = self._tc.create_signed_integer_field_class(32) |
22 | payload_ft = self._tc.create_structure_field_class() | |
f5567ea8 | 23 | payload_ft += [("my_int", self._my_int_ft)] |
5f25509b SM |
24 | self._ec.payload_field_type = payload_ft |
25 | self._stream = self._t.create_stream(self._sc) | |
26 | self._packet = self._stream.create_packet() | |
27 | ||
28 | def _create_event(self, value): | |
29 | ev = self._ec() | |
f5567ea8 | 30 | ev.payload_field["my_int"] = value |
5f25509b SM |
31 | ev.packet = self._packet |
32 | return ev | |
33 | ||
34 | ||
811644b8 PP |
35 | class GraphTestCase(unittest.TestCase): |
36 | def setUp(self): | |
37 | self._graph = bt2.Graph() | |
38 | ||
39 | def tearDown(self): | |
40 | del self._graph | |
41 | ||
056deb59 PP |
42 | def test_create_default(self): |
43 | bt2.Graph() | |
44 | ||
45 | def test_create_known_mip_version(self): | |
46 | bt2.Graph(0) | |
47 | ||
48 | def test_create_invalid_mip_version_type(self): | |
49 | with self.assertRaises(TypeError): | |
f5567ea8 | 50 | bt2.Graph("") |
056deb59 PP |
51 | |
52 | def test_create_unknown_mip_version(self): | |
f5567ea8 | 53 | with self.assertRaisesRegex(ValueError, "unknown MIP version"): |
056deb59 | 54 | bt2.Graph(1) |
811644b8 | 55 | |
c513d240 SM |
56 | def test_default_interrupter(self): |
57 | interrupter = self._graph.default_interrupter | |
58 | self.assertIs(type(interrupter), bt2.Interrupter) | |
59 | ||
811644b8 PP |
60 | def test_add_component_user_cls(self): |
61 | class MySink(bt2._UserSinkComponent): | |
6a91742b | 62 | def _user_consume(self): |
a01b452b | 63 | pass |
811644b8 | 64 | |
f5567ea8 FD |
65 | comp = self._graph.add_component(MySink, "salut") |
66 | self.assertEqual(comp.name, "salut") | |
811644b8 PP |
67 | |
68 | def test_add_component_gen_cls(self): | |
69 | class MySink(bt2._UserSinkComponent): | |
6a91742b | 70 | def _user_consume(self): |
a01b452b | 71 | pass |
811644b8 | 72 | |
f5567ea8 | 73 | comp = self._graph.add_component(MySink, "salut") |
5f25509b | 74 | assert comp |
f5567ea8 FD |
75 | comp2 = self._graph.add_component(comp.cls, "salut2") |
76 | self.assertEqual(comp2.name, "salut2") | |
811644b8 PP |
77 | |
78 | def test_add_component_params(self): | |
79 | comp_params = None | |
80 | ||
81 | class MySink(bt2._UserSinkComponent): | |
59225a3e | 82 | def __init__(self, config, params, obj): |
811644b8 PP |
83 | nonlocal comp_params |
84 | comp_params = params | |
85 | ||
6a91742b | 86 | def _user_consume(self): |
a01b452b | 87 | pass |
811644b8 | 88 | |
f5567ea8 FD |
89 | params = {"hello": 23, "path": "/path/to/stuff"} |
90 | self._graph.add_component(MySink, "salut", params) | |
811644b8 PP |
91 | self.assertEqual(params, comp_params) |
92 | del comp_params | |
93 | ||
66964f3f PP |
94 | def test_add_component_obj_python_comp_cls(self): |
95 | comp_obj = None | |
96 | ||
97 | class MySink(bt2._UserSinkComponent): | |
59225a3e | 98 | def __init__(self, config, params, obj): |
66964f3f PP |
99 | nonlocal comp_obj |
100 | comp_obj = obj | |
101 | ||
102 | def _user_consume(self): | |
103 | pass | |
104 | ||
105 | obj = object() | |
f5567ea8 | 106 | self._graph.add_component(MySink, "salut", obj=obj) |
66964f3f PP |
107 | self.assertIs(comp_obj, obj) |
108 | del comp_obj | |
109 | ||
110 | def test_add_component_obj_none_python_comp_cls(self): | |
111 | comp_obj = None | |
112 | ||
113 | class MySink(bt2._UserSinkComponent): | |
59225a3e | 114 | def __init__(self, config, params, obj): |
66964f3f PP |
115 | nonlocal comp_obj |
116 | comp_obj = obj | |
117 | ||
118 | def _user_consume(self): | |
119 | pass | |
120 | ||
f5567ea8 | 121 | self._graph.add_component(MySink, "salut") |
66964f3f PP |
122 | self.assertIsNone(comp_obj) |
123 | del comp_obj | |
124 | ||
125 | def test_add_component_obj_non_python_comp_cls(self): | |
f5567ea8 | 126 | plugin = bt2.find_plugin("text", find_in_user_dir=False, find_in_sys_dir=False) |
66964f3f | 127 | assert plugin is not None |
f5567ea8 | 128 | cc = plugin.source_component_classes["dmesg"] |
66964f3f PP |
129 | assert cc is not None |
130 | ||
131 | with self.assertRaises(ValueError): | |
f5567ea8 | 132 | self._graph.add_component(cc, "salut", obj=57) |
66964f3f | 133 | |
811644b8 PP |
134 | def test_add_component_invalid_cls_type(self): |
135 | with self.assertRaises(TypeError): | |
f5567ea8 | 136 | self._graph.add_component(int, "salut") |
811644b8 | 137 | |
8ef46e79 PP |
138 | def test_add_component_invalid_logging_level_type(self): |
139 | class MySink(bt2._UserSinkComponent): | |
6a91742b | 140 | def _user_consume(self): |
a01b452b | 141 | pass |
8ef46e79 PP |
142 | |
143 | with self.assertRaises(TypeError): | |
f5567ea8 | 144 | self._graph.add_component(MySink, "salut", logging_level="yo") |
8ef46e79 PP |
145 | |
146 | def test_add_component_invalid_logging_level_value(self): | |
147 | class MySink(bt2._UserSinkComponent): | |
6a91742b | 148 | def _user_consume(self): |
a01b452b | 149 | pass |
8ef46e79 PP |
150 | |
151 | with self.assertRaises(ValueError): | |
f5567ea8 | 152 | self._graph.add_component(MySink, "salut", logging_level=12345) |
8ef46e79 | 153 | |
401b7022 FD |
154 | def test_add_component_invalid_params_type(self): |
155 | class MySink(bt2._UserSinkComponent): | |
156 | def _user_consume(self): | |
157 | pass | |
158 | ||
159 | with self.assertRaises(TypeError): | |
f5567ea8 | 160 | self._graph.add_component(MySink, "salut", params=12) |
401b7022 FD |
161 | |
162 | def test_add_component_params_dict(self): | |
163 | params_obj = None | |
164 | ||
165 | class MySink(bt2._UserSinkComponent): | |
166 | def __init__(self, config, params, obj): | |
167 | nonlocal params_obj | |
168 | params_obj = params | |
169 | ||
170 | def _user_consume(self): | |
171 | pass | |
172 | ||
f5567ea8 FD |
173 | params = {"plage": 12312} |
174 | self._graph.add_component(MySink, "salut", params=params) | |
401b7022 FD |
175 | |
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) | |
179 | ||
180 | def test_add_component_params_mapvalue(self): | |
181 | params_obj = None | |
182 | ||
183 | class MySink(bt2._UserSinkComponent): | |
184 | def __init__(self, config, params, obj): | |
185 | nonlocal params_obj | |
186 | params_obj = params | |
187 | ||
188 | def _user_consume(self): | |
189 | pass | |
190 | ||
f5567ea8 FD |
191 | params = bt2.MapValue({"beachclub": "121"}) |
192 | self._graph.add_component(MySink, "salut", params=params) | |
401b7022 FD |
193 | |
194 | self.assertEqual(params, params_obj) | |
195 | ||
8ef46e79 PP |
196 | def test_add_component_logging_level(self): |
197 | class MySink(bt2._UserSinkComponent): | |
6a91742b | 198 | def _user_consume(self): |
a01b452b | 199 | pass |
8ef46e79 | 200 | |
cfbd7cf3 | 201 | comp = self._graph.add_component( |
f5567ea8 | 202 | MySink, "salut", logging_level=bt2.LoggingLevel.DEBUG |
cfbd7cf3 | 203 | ) |
8ef46e79 PP |
204 | self.assertEqual(comp.logging_level, bt2.LoggingLevel.DEBUG) |
205 | ||
811644b8 | 206 | def test_connect_ports(self): |
5c61fb9d SM |
207 | class MySource( |
208 | bt2._UserSourceComponent, message_iterator_class=bt2._UserMessageIterator | |
209 | ): | |
59225a3e | 210 | def __init__(self, config, params, obj): |
f5567ea8 | 211 | self._add_output_port("out") |
811644b8 PP |
212 | |
213 | class MySink(bt2._UserSinkComponent): | |
59225a3e | 214 | def __init__(self, config, params, obj): |
f5567ea8 | 215 | self._add_input_port("in") |
811644b8 | 216 | |
6a91742b | 217 | def _user_consume(self): |
811644b8 PP |
218 | raise bt2.Stop |
219 | ||
f5567ea8 FD |
220 | src = self._graph.add_component(MySource, "src") |
221 | sink = self._graph.add_component(MySink, "sink") | |
5f25509b | 222 | |
cfbd7cf3 | 223 | conn = self._graph.connect_ports( |
f5567ea8 | 224 | src.output_ports["out"], sink.input_ports["in"] |
cfbd7cf3 | 225 | ) |
f5567ea8 FD |
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) | |
811644b8 PP |
230 | |
231 | def test_connect_ports_invalid_direction(self): | |
5c61fb9d SM |
232 | class MySource( |
233 | bt2._UserSourceComponent, message_iterator_class=bt2._UserMessageIterator | |
234 | ): | |
59225a3e | 235 | def __init__(self, config, params, obj): |
f5567ea8 | 236 | self._add_output_port("out") |
811644b8 PP |
237 | |
238 | class MySink(bt2._UserSinkComponent): | |
59225a3e | 239 | def __init__(self, config, params, obj): |
f5567ea8 | 240 | self._add_input_port("in") |
811644b8 | 241 | |
6a91742b | 242 | def _user_consume(self): |
811644b8 PP |
243 | raise bt2.Stop |
244 | ||
f5567ea8 FD |
245 | src = self._graph.add_component(MySource, "src") |
246 | sink = self._graph.add_component(MySink, "sink") | |
811644b8 PP |
247 | |
248 | with self.assertRaises(TypeError): | |
f5567ea8 | 249 | self._graph.connect_ports(sink.input_ports["in"], src.output_ports["out"]) |
811644b8 | 250 | |
9b4f9b42 PP |
251 | def test_add_interrupter(self): |
252 | class MyIter(bt2._UserMessageIterator): | |
253 | def __next__(self): | |
254 | raise TypeError | |
255 | ||
256 | class MySource(bt2._UserSourceComponent, message_iterator_class=MyIter): | |
59225a3e | 257 | def __init__(self, config, params, obj): |
f5567ea8 | 258 | self._add_output_port("out") |
9b4f9b42 PP |
259 | |
260 | class MySink(bt2._UserSinkComponent): | |
59225a3e | 261 | def __init__(self, config, params, obj): |
f5567ea8 | 262 | self._add_input_port("in") |
9b4f9b42 | 263 | |
6a91742b | 264 | def _user_consume(self): |
9b4f9b42 PP |
265 | next(self._msg_iter) |
266 | ||
6a91742b | 267 | def _user_graph_is_configured(self): |
f5567ea8 | 268 | self._msg_iter = self._create_message_iterator(self._input_ports["in"]) |
9b4f9b42 PP |
269 | |
270 | # add two interrupters, set one of them | |
271 | interrupter1 = bt2.Interrupter() | |
272 | interrupter2 = bt2.Interrupter() | |
273 | self._graph.add_interrupter(interrupter1) | |
f5567ea8 FD |
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"]) | |
9b4f9b42 PP |
277 | self._graph.add_interrupter(interrupter2) |
278 | ||
279 | with self.assertRaises(bt2._Error): | |
280 | self._graph.run() | |
281 | ||
282 | interrupter2.set() | |
283 | ||
284 | with self.assertRaises(bt2.TryAgain): | |
285 | self._graph.run() | |
286 | ||
287 | interrupter2.reset() | |
288 | ||
289 | with self.assertRaises(bt2._Error): | |
290 | self._graph.run() | |
291 | ||
292 | # Test that Graph.run() raises bt2.Interrupted if the graph gets | |
293 | # interrupted during execution. | |
294 | def test_interrupt_while_running(self): | |
5f25509b | 295 | class MyIter(_MyIter): |
1d915789 | 296 | def __next__(self): |
5f25509b | 297 | return self._create_stream_beginning_message(self._stream) |
1d915789 | 298 | |
cfbd7cf3 | 299 | class MySource(bt2._UserSourceComponent, message_iterator_class=MyIter): |
59225a3e | 300 | def __init__(self, config, params, obj): |
f5567ea8 | 301 | self._add_output_port("out") |
1d915789 PP |
302 | |
303 | class MySink(bt2._UserSinkComponent): | |
59225a3e | 304 | def __init__(self, config, params, obj): |
f5567ea8 | 305 | self._add_input_port("in") |
1d915789 | 306 | |
6a91742b | 307 | def _user_consume(self): |
9b4f9b42 | 308 | # Pretend that somebody asynchronously interrupted the graph. |
5f25509b | 309 | nonlocal graph |
c513d240 | 310 | graph.default_interrupter.set() |
5f25509b | 311 | return next(self._msg_iter) |
1d915789 | 312 | |
6a91742b | 313 | def _user_graph_is_configured(self): |
f5567ea8 | 314 | self._msg_iter = self._create_message_iterator(self._input_ports["in"]) |
1d915789 | 315 | |
9b4f9b42 | 316 | graph = self._graph |
f5567ea8 FD |
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"]) | |
9b4f9b42 PP |
320 | |
321 | with self.assertRaises(bt2.TryAgain): | |
322 | self._graph.run() | |
811644b8 PP |
323 | |
324 | def test_run(self): | |
5f25509b | 325 | class MyIter(_MyIter): |
811644b8 | 326 | def __next__(self): |
5f25509b SM |
327 | if self._at == 9: |
328 | raise StopIteration | |
329 | ||
330 | if self._at == 0: | |
331 | msg = self._create_stream_beginning_message(self._stream) | |
332 | elif self._at == 1: | |
333 | msg = self._create_packet_beginning_message(self._packet) | |
334 | elif self._at == 7: | |
335 | msg = self._create_packet_end_message(self._packet) | |
336 | elif self._at == 8: | |
337 | msg = self._create_stream_end_message(self._stream) | |
338 | else: | |
339 | msg = self._create_event_message(self._ec, self._packet) | |
811644b8 | 340 | |
811644b8 | 341 | self._at += 1 |
5602ef81 | 342 | return msg |
811644b8 | 343 | |
cfbd7cf3 | 344 | class MySource(bt2._UserSourceComponent, message_iterator_class=MyIter): |
59225a3e | 345 | def __init__(self, config, params, obj): |
f5567ea8 | 346 | self._add_output_port("out") |
811644b8 PP |
347 | |
348 | class MySink(bt2._UserSinkComponent): | |
59225a3e | 349 | def __init__(self, config, params, obj): |
f5567ea8 | 350 | self._input_port = self._add_input_port("in") |
811644b8 PP |
351 | self._at = 0 |
352 | ||
6a91742b | 353 | def _user_consume(comp_self): |
5602ef81 | 354 | msg = next(comp_self._msg_iter) |
811644b8 PP |
355 | |
356 | if comp_self._at == 0: | |
f0a42b33 | 357 | self.assertIs(type(msg), bt2._StreamBeginningMessageConst) |
811644b8 | 358 | elif comp_self._at == 1: |
f0a42b33 | 359 | self.assertIs(type(msg), bt2._PacketBeginningMessageConst) |
811644b8 | 360 | elif comp_self._at >= 2 and comp_self._at <= 6: |
f0a42b33 | 361 | self.assertIs(type(msg), bt2._EventMessageConst) |
f5567ea8 | 362 | self.assertEqual(msg.event.cls.name, "salut") |
811644b8 | 363 | elif comp_self._at == 7: |
f0a42b33 | 364 | self.assertIs(type(msg), bt2._PacketEndMessageConst) |
811644b8 | 365 | elif comp_self._at == 8: |
f0a42b33 | 366 | self.assertIs(type(msg), bt2._StreamEndMessageConst) |
811644b8 PP |
367 | |
368 | comp_self._at += 1 | |
369 | ||
6a91742b | 370 | def _user_graph_is_configured(self): |
9a2c8b8e | 371 | self._msg_iter = self._create_message_iterator(self._input_port) |
811644b8 | 372 | |
f5567ea8 FD |
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"]) | |
811644b8 PP |
376 | self._graph.run() |
377 | ||
8cc0e6ea PP |
378 | def test_run_once(self): |
379 | class MyIter(_MyIter): | |
380 | pass | |
381 | ||
382 | class MySource(bt2._UserSourceComponent, message_iterator_class=MyIter): | |
59225a3e | 383 | def __init__(self, config, params, obj): |
f5567ea8 | 384 | self._add_output_port("out") |
8cc0e6ea PP |
385 | |
386 | class MySink(bt2._UserSinkComponent): | |
59225a3e | 387 | def __init__(self, config, params, obj): |
f5567ea8 | 388 | self._input_port = self._add_input_port("in") |
8cc0e6ea PP |
389 | |
390 | def _user_consume(comp_self): | |
391 | nonlocal run_count | |
392 | run_count += 1 | |
393 | raise bt2.TryAgain | |
394 | ||
395 | run_count = 0 | |
f5567ea8 FD |
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"]) | |
8cc0e6ea PP |
399 | |
400 | with self.assertRaises(bt2.TryAgain): | |
401 | self._graph.run_once() | |
402 | ||
403 | self.assertEqual(run_count, 1) | |
404 | ||
405 | def test_run_once_stops(self): | |
406 | class MyIter(_MyIter): | |
407 | pass | |
408 | ||
409 | class MySource(bt2._UserSourceComponent, message_iterator_class=MyIter): | |
59225a3e | 410 | def __init__(self, config, params, obj): |
f5567ea8 | 411 | self._add_output_port("out") |
8cc0e6ea PP |
412 | |
413 | class MySink(bt2._UserSinkComponent): | |
59225a3e | 414 | def __init__(self, config, params, obj): |
f5567ea8 | 415 | self._input_port = self._add_input_port("in") |
8cc0e6ea PP |
416 | |
417 | def _user_consume(comp_self): | |
418 | raise bt2.Stop | |
419 | ||
f5567ea8 FD |
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"]) | |
8cc0e6ea PP |
423 | |
424 | with self.assertRaises(bt2.Stop): | |
425 | self._graph.run_once() | |
426 | ||
811644b8 | 427 | def test_run_again(self): |
5f25509b | 428 | class MyIter(_MyIter): |
811644b8 | 429 | def __next__(self): |
5f25509b | 430 | if self._at == 3: |
811644b8 PP |
431 | raise bt2.TryAgain |
432 | ||
5f25509b SM |
433 | if self._at == 0: |
434 | msg = self._create_stream_beginning_message(self._stream) | |
435 | elif self._at == 1: | |
436 | msg = self._create_packet_beginning_message(self._packet) | |
437 | elif self._at == 2: | |
438 | msg = self._create_event_message(self._ec, self._packet) | |
439 | ||
811644b8 | 440 | self._at += 1 |
5602ef81 | 441 | return msg |
811644b8 | 442 | |
cfbd7cf3 | 443 | class MySource(bt2._UserSourceComponent, message_iterator_class=MyIter): |
59225a3e | 444 | def __init__(self, config, params, obj): |
f5567ea8 | 445 | self._add_output_port("out") |
811644b8 PP |
446 | |
447 | class MySink(bt2._UserSinkComponent): | |
59225a3e | 448 | def __init__(self, config, params, obj): |
f5567ea8 | 449 | self._input_port = self._add_input_port("in") |
811644b8 PP |
450 | self._at = 0 |
451 | ||
6a91742b | 452 | def _user_consume(comp_self): |
5f25509b | 453 | msg = next(comp_self._msg_iter) |
811644b8 | 454 | if comp_self._at == 0: |
f0a42b33 | 455 | self.assertIs(type(msg), bt2._StreamBeginningMessageConst) |
811644b8 | 456 | elif comp_self._at == 1: |
f0a42b33 | 457 | self.assertIs(type(msg), bt2._PacketBeginningMessageConst) |
5f25509b | 458 | elif comp_self._at == 2: |
f0a42b33 | 459 | self.assertIs(type(msg), bt2._EventMessageConst) |
811644b8 | 460 | raise bt2.TryAgain |
5f25509b SM |
461 | else: |
462 | pass | |
811644b8 PP |
463 | |
464 | comp_self._at += 1 | |
465 | ||
6a91742b | 466 | def _user_graph_is_configured(self): |
9a2c8b8e | 467 | self._msg_iter = self._create_message_iterator(self._input_port) |
811644b8 | 468 | |
f5567ea8 FD |
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"]) | |
811644b8 PP |
472 | |
473 | with self.assertRaises(bt2.TryAgain): | |
474 | self._graph.run() | |
475 | ||
811644b8 | 476 | def test_run_error(self): |
5f25509b | 477 | raised_in_sink = False |
811644b8 | 478 | |
5f25509b | 479 | class MyIter(_MyIter): |
811644b8 | 480 | def __next__(self): |
5f25509b SM |
481 | # If this gets called after the sink raised an exception, it is |
482 | # an error. | |
483 | nonlocal raised_in_sink | |
484 | assert raised_in_sink is False | |
485 | ||
486 | if self._at == 0: | |
487 | msg = self._create_stream_beginning_message(self._stream) | |
488 | elif self._at == 1: | |
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) | |
492 | else: | |
811644b8 | 493 | raise bt2.TryAgain |
811644b8 | 494 | self._at += 1 |
5602ef81 | 495 | return msg |
811644b8 | 496 | |
cfbd7cf3 | 497 | class MySource(bt2._UserSourceComponent, message_iterator_class=MyIter): |
59225a3e | 498 | def __init__(self, config, params, obj): |
f5567ea8 | 499 | self._add_output_port("out") |
811644b8 PP |
500 | |
501 | class MySink(bt2._UserSinkComponent): | |
59225a3e | 502 | def __init__(self, config, params, obj): |
f5567ea8 | 503 | self._input_port = self._add_input_port("in") |
811644b8 PP |
504 | self._at = 0 |
505 | ||
6a91742b | 506 | def _user_consume(comp_self): |
5f25509b | 507 | msg = next(comp_self._msg_iter) |
811644b8 | 508 | if comp_self._at == 0: |
f0a42b33 | 509 | self.assertIs(type(msg), bt2._StreamBeginningMessageConst) |
811644b8 | 510 | elif comp_self._at == 1: |
f0a42b33 | 511 | self.assertIs(type(msg), bt2._PacketBeginningMessageConst) |
5f25509b | 512 | elif comp_self._at == 2: |
f0a42b33 | 513 | self.assertIs(type(msg), bt2._EventMessageConst) |
5f25509b SM |
514 | elif comp_self._at == 3: |
515 | nonlocal raised_in_sink | |
516 | raised_in_sink = True | |
f5567ea8 | 517 | raise RuntimeError("error!") |
811644b8 PP |
518 | |
519 | comp_self._at += 1 | |
520 | ||
6a91742b | 521 | def _user_graph_is_configured(self): |
9a2c8b8e | 522 | self._msg_iter = self._create_message_iterator(self._input_port) |
811644b8 | 523 | |
f5567ea8 FD |
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"]) | |
811644b8 | 527 | |
694c792b | 528 | with self.assertRaises(bt2._Error): |
811644b8 PP |
529 | self._graph.run() |
530 | ||
5f25509b | 531 | def test_listeners(self): |
5c61fb9d SM |
532 | class MySource( |
533 | bt2._UserSourceComponent, message_iterator_class=bt2._UserMessageIterator | |
534 | ): | |
59225a3e | 535 | def __init__(self, config, params, obj): |
f5567ea8 FD |
536 | self._add_output_port("out") |
537 | self._add_output_port("zero") | |
1d915789 PP |
538 | |
539 | class MySink(bt2._UserSinkComponent): | |
59225a3e | 540 | def __init__(self, config, params, obj): |
f5567ea8 | 541 | self._add_input_port("in") |
1d915789 | 542 | |
6a91742b | 543 | def _user_consume(self): |
5f25509b | 544 | raise bt2.Stop |
1d915789 | 545 | |
6a91742b | 546 | def _user_port_connected(self, port, other_port): |
f5567ea8 | 547 | self._add_input_port("taste") |
1d915789 | 548 | |
5f25509b SM |
549 | def port_added_listener(component, port): |
550 | nonlocal calls | |
551 | calls.append((port_added_listener, component, port)) | |
1d915789 | 552 | |
5f25509b SM |
553 | calls = [] |
554 | self._graph.add_port_added_listener(port_added_listener) | |
f5567ea8 FD |
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"]) | |
1d915789 | 558 | |
2945edfe | 559 | self.assertEqual(len(calls), 4) |
5f25509b SM |
560 | |
561 | self.assertIs(calls[0][0], port_added_listener) | |
f5567ea8 FD |
562 | self.assertEqual(calls[0][1].name, "src") |
563 | self.assertEqual(calls[0][2].name, "out") | |
5f25509b SM |
564 | |
565 | self.assertIs(calls[1][0], port_added_listener) | |
f5567ea8 FD |
566 | self.assertEqual(calls[1][1].name, "src") |
567 | self.assertEqual(calls[1][2].name, "zero") | |
5f25509b SM |
568 | |
569 | self.assertIs(calls[2][0], port_added_listener) | |
f5567ea8 FD |
570 | self.assertEqual(calls[2][1].name, "sink") |
571 | self.assertEqual(calls[2][2].name, "in") | |
5f25509b SM |
572 | |
573 | self.assertIs(calls[3][0], port_added_listener) | |
f5567ea8 FD |
574 | self.assertEqual(calls[3][1].name, "sink") |
575 | self.assertEqual(calls[3][2].name, "taste") | |
5f25509b | 576 | |
5f25509b | 577 | def test_invalid_listeners(self): |
5c61fb9d SM |
578 | class MySource( |
579 | bt2._UserSourceComponent, message_iterator_class=bt2._UserMessageIterator | |
580 | ): | |
59225a3e | 581 | def __init__(self, config, params, obj): |
f5567ea8 FD |
582 | self._add_output_port("out") |
583 | self._add_output_port("zero") | |
811644b8 | 584 | |
811644b8 | 585 | class MySink(bt2._UserSinkComponent): |
59225a3e | 586 | def __init__(self, config, params, obj): |
f5567ea8 | 587 | self._add_input_port("in") |
811644b8 | 588 | |
6a91742b | 589 | def _user_consume(self): |
811644b8 PP |
590 | raise bt2.Stop |
591 | ||
6a91742b | 592 | def _user_port_connected(self, port, other_port): |
f5567ea8 | 593 | self._add_input_port("taste") |
811644b8 | 594 | |
5f25509b SM |
595 | with self.assertRaises(TypeError): |
596 | self._graph.add_port_added_listener(1234) | |
811644b8 | 597 | |
5f25509b SM |
598 | def test_raise_in_component_init(self): |
599 | class MySink(bt2._UserSinkComponent): | |
59225a3e | 600 | def __init__(self, config, params, obj): |
f5567ea8 | 601 | raise ValueError("oops!") |
811644b8 | 602 | |
6a91742b | 603 | def _user_consume(self): |
5f25509b SM |
604 | raise bt2.Stop |
605 | ||
606 | graph = bt2.Graph() | |
607 | ||
694c792b | 608 | with self.assertRaises(bt2._Error): |
f5567ea8 | 609 | graph.add_component(MySink, "comp") |
5f25509b SM |
610 | |
611 | def test_raise_in_port_added_listener(self): | |
612 | class MySink(bt2._UserSinkComponent): | |
59225a3e | 613 | def __init__(self, config, params, obj): |
f5567ea8 | 614 | self._add_input_port("in") |
5f25509b | 615 | |
6a91742b | 616 | def _user_consume(self): |
5f25509b SM |
617 | raise bt2.Stop |
618 | ||
619 | def port_added_listener(component, port): | |
f5567ea8 | 620 | raise ValueError("oh noes!") |
5f25509b SM |
621 | |
622 | graph = bt2.Graph() | |
623 | graph.add_port_added_listener(port_added_listener) | |
624 | ||
694c792b | 625 | with self.assertRaises(bt2._Error): |
f5567ea8 | 626 | graph.add_component(MySink, "comp") |
5f25509b | 627 | |
d14ddbba | 628 | |
f5567ea8 | 629 | if __name__ == "__main__": |
d14ddbba | 630 | unittest.main() |