bt2c::Logger: remove unused cLevel() method
[babeltrace.git] / tests / bindings / python / bt2 / test_message_iterator.py
CommitLineData
0235b0db 1# SPDX-License-Identifier: GPL-2.0-only
d2d857a8
MJ
2#
3# Copyright (C) 2019 EfficiOS Inc.
4#
d2d857a8 5
5995b304 6import sys
811644b8 7import unittest
5995b304 8
811644b8 9import bt2
14503fb1 10from bt2 import port as bt2_port
8d8b141d 11from bt2 import message_iterator as bt2_message_iterator
5995b304 12from utils import TestOutputPortMessageIterator
811644b8
PP
13
14
0a6d7302
SM
15class SimpleSink(bt2._UserSinkComponent):
16 # Straightforward sink that creates one input port (`in`) and consumes from
17 # it.
811644b8 18
59225a3e 19 def __init__(self, config, params, obj):
f5567ea8 20 self._add_input_port("in")
811644b8 21
0a6d7302
SM
22 def _user_consume(self):
23 next(self._msg_iter)
811644b8 24
0a6d7302 25 def _user_graph_is_configured(self):
f5567ea8 26 self._msg_iter = self._create_message_iterator(self._input_ports["in"])
ca02df0a 27
ca02df0a 28
0a6d7302
SM
29def _create_graph(src_comp_cls, sink_comp_cls, flt_comp_cls=None):
30 graph = bt2.Graph()
ca02df0a 31
f5567ea8
FD
32 src_comp = graph.add_component(src_comp_cls, "src")
33 sink_comp = graph.add_component(sink_comp_cls, "sink")
ca02df0a 34
0a6d7302 35 if flt_comp_cls is not None:
f5567ea8
FD
36 flt_comp = graph.add_component(flt_comp_cls, "flt")
37 graph.connect_ports(src_comp.output_ports["out"], flt_comp.input_ports["in"])
38 graph.connect_ports(flt_comp.output_ports["out"], sink_comp.input_ports["in"])
0a6d7302 39 else:
f5567ea8 40 graph.connect_ports(src_comp.output_ports["out"], sink_comp.input_ports["in"])
811644b8 41
0a6d7302
SM
42 return graph
43
44
45class UserMessageIteratorTestCase(unittest.TestCase):
811644b8 46 def test_init(self):
c5f330cd
SM
47 the_output_port_from_source = None
48 the_output_port_from_iter = None
49
5602ef81 50 class MyIter(bt2._UserMessageIterator):
8d8b141d 51 def __init__(self, config, self_port_output):
811644b8 52 nonlocal initialized
c5f330cd 53 nonlocal the_output_port_from_iter
811644b8 54 initialized = True
c5f330cd 55 the_output_port_from_iter = self_port_output
811644b8 56
cfbd7cf3 57 class MySource(bt2._UserSourceComponent, message_iterator_class=MyIter):
59225a3e 58 def __init__(self, config, params, obj):
c5f330cd 59 nonlocal the_output_port_from_source
f5567ea8 60 the_output_port_from_source = self._add_output_port("out", "user data")
811644b8
PP
61
62 initialized = False
0a6d7302 63 graph = _create_graph(MySource, SimpleSink)
c5f330cd 64 graph.run()
811644b8 65 self.assertTrue(initialized)
cfbd7cf3
FD
66 self.assertEqual(
67 the_output_port_from_source.addr, the_output_port_from_iter.addr
68 )
f5567ea8 69 self.assertEqual(the_output_port_from_iter.user_data, "user data")
811644b8 70
ca02df0a
PP
71 def test_create_from_message_iterator(self):
72 class MySourceIter(bt2._UserMessageIterator):
8d8b141d 73 def __init__(self, config, self_port_output):
ca02df0a
PP
74 nonlocal src_iter_initialized
75 src_iter_initialized = True
76
77 class MySource(bt2._UserSourceComponent, message_iterator_class=MySourceIter):
59225a3e 78 def __init__(self, config, params, obj):
f5567ea8 79 self._add_output_port("out")
ca02df0a
PP
80
81 class MyFilterIter(bt2._UserMessageIterator):
8d8b141d 82 def __init__(self, config, self_port_output):
ca02df0a
PP
83 nonlocal flt_iter_initialized
84 flt_iter_initialized = True
9a2c8b8e 85 self._up_iter = self._create_message_iterator(
f5567ea8 86 self._component._input_ports["in"]
ca02df0a
PP
87 )
88
89 def __next__(self):
90 return next(self._up_iter)
91
92 class MyFilter(bt2._UserFilterComponent, message_iterator_class=MyFilterIter):
59225a3e 93 def __init__(self, config, params, obj):
f5567ea8
FD
94 self._add_input_port("in")
95 self._add_output_port("out")
ca02df0a
PP
96
97 src_iter_initialized = False
98 flt_iter_initialized = False
0a6d7302 99 graph = _create_graph(MySource, SimpleSink, MyFilter)
ca02df0a
PP
100 graph.run()
101 self.assertTrue(src_iter_initialized)
102 self.assertTrue(flt_iter_initialized)
103
415d43a1 104 # Test that creating a message iterator from a sink component on a
e7401568 105 # non-connected input port raises.
415d43a1
SM
106 def test_create_from_sink_component_unconnected_port_raises(self):
107 class MySink(bt2._UserSinkComponent):
108 def __init__(comp_self, config, params, obj):
f5567ea8 109 comp_self._input_port = comp_self._add_input_port("in")
415d43a1
SM
110
111 def _user_graph_is_configured(comp_self):
f5567ea8 112 with self.assertRaisesRegex(ValueError, "input port is not connected"):
415d43a1
SM
113 comp_self._create_message_iterator(comp_self._input_port)
114
115 nonlocal seen
116 seen = True
117
118 def _user_consume(self):
119 raise bt2.Stop
120
121 seen = False
122 graph = bt2.Graph()
f5567ea8 123 graph.add_component(MySink, "snk")
415d43a1
SM
124 graph.run()
125 self.assertTrue(seen)
126
e7401568
SM
127 # Test that creating a message iterator from a message iterator on a
128 # non-connected input port raises.
415d43a1
SM
129 def test_create_from_message_iterator_unconnected_port_raises(self):
130 class MyFilterIter(bt2._UserMessageIterator):
131 def __init__(iter_self, config, port):
f5567ea8 132 input_port = iter_self._component._input_ports["in"]
415d43a1 133
f5567ea8 134 with self.assertRaisesRegex(ValueError, "input port is not connected"):
415d43a1
SM
135 iter_self._create_message_iterator(input_port)
136
137 nonlocal seen
138 seen = True
139
140 class MyFilter(bt2._UserFilterComponent, message_iterator_class=MyFilterIter):
141 def __init__(comp_self, config, params, obj):
f5567ea8
FD
142 comp_self._add_input_port("in")
143 comp_self._add_output_port("out")
415d43a1
SM
144
145 class MySink(bt2._UserSinkComponent):
146 def __init__(comp_self, config, params, obj):
f5567ea8 147 comp_self._input_port = comp_self._add_input_port("in")
415d43a1
SM
148
149 def _user_graph_is_configured(comp_self):
150 comp_self._input_iter = comp_self._create_message_iterator(
151 comp_self._input_port
152 )
153
154 def _user_consume(self):
155 raise bt2.Stop
156
157 seen = False
158 graph = bt2.Graph()
f5567ea8
FD
159 flt = graph.add_component(MyFilter, "flt")
160 snk = graph.add_component(MySink, "snk")
161 graph.connect_ports(flt.output_ports["out"], snk.input_ports["in"])
415d43a1
SM
162 graph.run()
163 self.assertTrue(seen)
164
e803df70
SM
165 def test_create_user_error(self):
166 # This tests both error handling by
9a2c8b8e
PP
167 # _UserSinkComponent._create_message_iterator
168 # and _UserMessageIterator._create_message_iterator, as they
e803df70
SM
169 # are both used in the graph.
170 class MySourceIter(bt2._UserMessageIterator):
8d8b141d 171 def __init__(self, config, self_port_output):
f5567ea8 172 raise ValueError("Very bad error")
e803df70
SM
173
174 class MySource(bt2._UserSourceComponent, message_iterator_class=MySourceIter):
59225a3e 175 def __init__(self, config, params, obj):
f5567ea8 176 self._add_output_port("out")
e803df70
SM
177
178 class MyFilterIter(bt2._UserMessageIterator):
8d8b141d 179 def __init__(self, config, self_port_output):
e803df70
SM
180 # This is expected to raise because of the error in
181 # MySourceIter.__init__.
f5567ea8 182 self._create_message_iterator(self._component._input_ports["in"])
e803df70
SM
183
184 class MyFilter(bt2._UserFilterComponent, message_iterator_class=MyFilterIter):
59225a3e 185 def __init__(self, config, params, obj):
f5567ea8
FD
186 self._add_input_port("in")
187 self._add_output_port("out")
e803df70 188
0a6d7302 189 graph = _create_graph(MySource, SimpleSink, MyFilter)
e803df70
SM
190
191 with self.assertRaises(bt2._Error) as ctx:
192 graph.run()
193
194 exc = ctx.exception
195 cause = exc[0]
196
197 self.assertIsInstance(cause, bt2._MessageIteratorErrorCause)
f5567ea8
FD
198 self.assertEqual(cause.component_name, "src")
199 self.assertEqual(cause.component_output_port_name, "out")
200 self.assertIn("ValueError: Very bad error", cause.message)
e803df70 201
811644b8 202 def test_finalize(self):
5602ef81 203 class MyIter(bt2._UserMessageIterator):
6a91742b 204 def _user_finalize(self):
811644b8
PP
205 nonlocal finalized
206 finalized = True
207
cfbd7cf3 208 class MySource(bt2._UserSourceComponent, message_iterator_class=MyIter):
59225a3e 209 def __init__(self, config, params, obj):
f5567ea8 210 self._add_output_port("out")
811644b8
PP
211
212 finalized = False
0a6d7302 213 graph = _create_graph(MySource, SimpleSink)
c5f330cd 214 graph.run()
811644b8
PP
215 del graph
216 self.assertTrue(finalized)
217
8d8b141d
SM
218 def test_config_parameter(self):
219 class MyIter(bt2._UserMessageIterator):
220 def __init__(self, config, port):
221 nonlocal config_type
222 config_type = type(config)
223
224 class MySource(bt2._UserSourceComponent, message_iterator_class=MyIter):
225 def __init__(self, config, params, obj):
f5567ea8 226 self._add_output_port("out")
8d8b141d
SM
227
228 config_type = None
229 graph = _create_graph(MySource, SimpleSink)
230 graph.run()
231 self.assertIs(config_type, bt2_message_iterator._MessageIteratorConfiguration)
232
233 def _test_config_can_seek_forward(self, set_can_seek_forward):
234 class MyIter(bt2._UserMessageIterator):
235 def __init__(self, config, port):
236 if set_can_seek_forward:
237 config.can_seek_forward = True
238
239 class MySource(bt2._UserSourceComponent, message_iterator_class=MyIter):
240 def __init__(self, config, params, obj):
f5567ea8 241 self._add_output_port("out")
8d8b141d
SM
242
243 class MySink(bt2._UserSinkComponent):
244 def __init__(self, config, params, obj):
f5567ea8 245 self._add_input_port("in")
8d8b141d
SM
246
247 def _user_graph_is_configured(self):
f5567ea8 248 self._msg_iter = self._create_message_iterator(self._input_ports["in"])
8d8b141d
SM
249
250 def _user_consume(self):
251 nonlocal can_seek_forward
252 can_seek_forward = self._msg_iter.can_seek_forward
253
254 can_seek_forward = None
255 graph = _create_graph(MySource, MySink)
256 graph.run_once()
257 self.assertIs(can_seek_forward, set_can_seek_forward)
258
259 def test_config_can_seek_forward_default(self):
260 self._test_config_can_seek_forward(False)
261
262 def test_config_can_seek_forward(self):
263 self._test_config_can_seek_forward(True)
264
265 def test_config_can_seek_forward_wrong_type(self):
266 class MyIter(bt2._UserMessageIterator):
267 def __init__(self, config, port):
268 config.can_seek_forward = 1
269
270 class MySource(bt2._UserSourceComponent, message_iterator_class=MyIter):
271 def __init__(self, config, params, obj):
f5567ea8 272 self._add_output_port("out")
8d8b141d
SM
273
274 graph = _create_graph(MySource, SimpleSink)
275 with self.assertRaises(bt2._Error) as ctx:
276 graph.run()
277
278 root_cause = ctx.exception[0]
279 self.assertIn("TypeError: 'int' is not a 'bool' object", root_cause.message)
280
811644b8 281 def test_component(self):
5602ef81 282 class MyIter(bt2._UserMessageIterator):
8d8b141d 283 def __init__(self, config, self_port_output):
811644b8
PP
284 nonlocal salut
285 salut = self._component._salut
286
cfbd7cf3 287 class MySource(bt2._UserSourceComponent, message_iterator_class=MyIter):
59225a3e 288 def __init__(self, config, params, obj):
f5567ea8 289 self._add_output_port("out")
811644b8
PP
290 self._salut = 23
291
292 salut = None
0a6d7302 293 graph = _create_graph(MySource, SimpleSink)
c5f330cd 294 graph.run()
811644b8
PP
295 self.assertEqual(salut, 23)
296
14503fb1
SM
297 def test_port(self):
298 class MyIter(bt2._UserMessageIterator):
8d8b141d 299 def __init__(self_iter, config, self_port_output):
14503fb1
SM
300 nonlocal called
301 called = True
302 port = self_iter._port
303 self.assertIs(type(self_port_output), bt2_port._UserComponentOutputPort)
304 self.assertIs(type(port), bt2_port._UserComponentOutputPort)
305 self.assertEqual(self_port_output.addr, port.addr)
306
307 class MySource(bt2._UserSourceComponent, message_iterator_class=MyIter):
59225a3e 308 def __init__(self, config, params, obj):
f5567ea8 309 self._add_output_port("out")
14503fb1
SM
310
311 called = False
0a6d7302 312 graph = _create_graph(MySource, SimpleSink)
14503fb1
SM
313 graph.run()
314 self.assertTrue(called)
315
811644b8 316 def test_addr(self):
5602ef81 317 class MyIter(bt2._UserMessageIterator):
8d8b141d 318 def __init__(self, config, self_port_output):
811644b8
PP
319 nonlocal addr
320 addr = self.addr
321
cfbd7cf3 322 class MySource(bt2._UserSourceComponent, message_iterator_class=MyIter):
59225a3e 323 def __init__(self, config, params, obj):
f5567ea8 324 self._add_output_port("out")
811644b8
PP
325
326 addr = None
0a6d7302 327 graph = _create_graph(MySource, SimpleSink)
c5f330cd 328 graph.run()
811644b8
PP
329 self.assertIsNotNone(addr)
330 self.assertNotEqual(addr, 0)
331
d79a8353
SM
332 # Test that messages returned by _UserMessageIterator.__next__ remain valid
333 # and can be re-used.
334 def test_reuse_message(self):
335 class MyIter(bt2._UserMessageIterator):
8d8b141d 336 def __init__(self, config, port):
d79a8353
SM
337 tc, sc, ec = port.user_data
338 trace = tc()
339 stream = trace.create_stream(sc)
340 packet = stream.create_packet()
341
342 # This message will be returned twice by __next__.
343 event_message = self._create_event_message(ec, packet)
344
345 self._msgs = [
346 self._create_stream_beginning_message(stream),
d79a8353
SM
347 self._create_packet_beginning_message(packet),
348 event_message,
349 event_message,
350 ]
351
352 def __next__(self):
353 return self._msgs.pop(0)
354
355 class MySource(bt2._UserSourceComponent, message_iterator_class=MyIter):
59225a3e 356 def __init__(self, config, params, obj):
d79a8353 357 tc = self._create_trace_class()
26fc5aed 358 sc = tc.create_stream_class(supports_packets=True)
d79a8353 359 ec = sc.create_event_class()
f5567ea8 360 self._add_output_port("out", (tc, sc, ec))
d79a8353
SM
361
362 graph = bt2.Graph()
f5567ea8
FD
363 src = graph.add_component(MySource, "src")
364 it = TestOutputPortMessageIterator(graph, src.output_ports["out"])
d79a8353
SM
365
366 # Skip beginning messages.
188edac1 367 msg = next(it)
f0a42b33 368 self.assertIs(type(msg), bt2._StreamBeginningMessageConst)
188edac1 369 msg = next(it)
f0a42b33 370 self.assertIs(type(msg), bt2._PacketBeginningMessageConst)
d79a8353
SM
371
372 msg_ev1 = next(it)
373 msg_ev2 = next(it)
374
f0a42b33
FD
375 self.assertIs(type(msg_ev1), bt2._EventMessageConst)
376 self.assertIs(type(msg_ev2), bt2._EventMessageConst)
d79a8353
SM
377 self.assertEqual(msg_ev1.addr, msg_ev2.addr)
378
0a6d7302
SM
379 # Try consuming many times from an iterator that always returns TryAgain.
380 # This verifies that we are not missing an incref of Py_None, making the
381 # refcount of Py_None reach 0.
382 def test_try_again_many_times(self):
a3788aca
SM
383 # Starting with Python 3.12, `None` is immortal: its reference
384 # count operations are no-op. Skip this test in that case.
385 before = sys.getrefcount(None)
386 dummy = None # noqa: F841
387
388 if before == sys.getrefcount(None):
389 raise unittest.SkipTest("`None` is immortal")
390
0a6d7302 391 class MyIter(bt2._UserMessageIterator):
f00b8d40 392 def __next__(self):
0a6d7302 393 raise bt2.TryAgain
f00b8d40 394
0a6d7302 395 class MySource(bt2._UserSourceComponent, message_iterator_class=MyIter):
59225a3e 396 def __init__(self, config, params, obj):
f5567ea8 397 self._add_output_port("out")
f00b8d40 398
f00b8d40 399 graph = bt2.Graph()
f5567ea8
FD
400 src = graph.add_component(MySource, "src")
401 it = TestOutputPortMessageIterator(graph, src.output_ports["out"])
0a6d7302
SM
402
403 # Three times the initial ref count of `None` iterations should
404 # be enough to catch the bug even if there are small differences
405 # between configurations.
406 none_ref_count = sys.getrefcount(None) * 3
407
408 for i in range(none_ref_count):
409 with self.assertRaises(bt2.TryAgain):
410 next(it)
411
fca28f75
SM
412 def test_error_in_iterator_with_cycle_after_having_created_upstream_iterator(self):
413 # Test a failure that triggered an abort in libbabeltrace2, in this situation:
414 #
415 # - The filter iterator creates an upstream iterator.
416 # - The filter iterator creates a reference cycle, including itself.
417 # - An exception is raised, causing the filter iterator's
418 # initialization method to fail.
419 class MySourceIter(bt2._UserMessageIterator):
420 pass
421
422 class MySource(bt2._UserSourceComponent, message_iterator_class=MySourceIter):
423 def __init__(self, config, params, obj):
f5567ea8 424 self._add_output_port("out")
fca28f75
SM
425
426 class MyFilterIter(bt2._UserMessageIterator):
427 def __init__(self, config, port):
428 # First, create an upstream iterator.
9a2c8b8e 429 self._upstream_iter = self._create_message_iterator(
f5567ea8 430 self._component._input_ports["in"]
fca28f75
SM
431 )
432
433 # Then, voluntarily make a reference cycle that will keep this
434 # Python object alive, which will keep the upstream iterator
435 # Babeltrace object alive.
436 self._self = self
437
438 # Finally, raise an exception to make __init__ fail.
f5567ea8 439 raise ValueError("woops")
fca28f75
SM
440
441 class MyFilter(bt2._UserFilterComponent, message_iterator_class=MyFilterIter):
442 def __init__(self, config, params, obj):
f5567ea8
FD
443 self._in = self._add_input_port("in")
444 self._out = self._add_output_port("out")
fca28f75
SM
445
446 class MySink(bt2._UserSinkComponent):
447 def __init__(self, config, params, obj):
f5567ea8 448 self._input_port = self._add_input_port("in")
fca28f75
SM
449
450 def _user_graph_is_configured(self):
9a2c8b8e 451 self._upstream_iter = self._create_message_iterator(self._input_port)
fca28f75
SM
452
453 def _user_consume(self):
454 # We should not reach this.
455 assert False
456
457 g = bt2.Graph()
f5567ea8
FD
458 src = g.add_component(MySource, "src")
459 flt = g.add_component(MyFilter, "flt")
460 snk = g.add_component(MySink, "snk")
461 g.connect_ports(src.output_ports["out"], flt.input_ports["in"])
462 g.connect_ports(flt.output_ports["out"], snk.input_ports["in"])
fca28f75 463
f5567ea8 464 with self.assertRaisesRegex(bt2._Error, "ValueError: woops"):
fca28f75
SM
465 g.run()
466
0a6d7302 467
c182d7dd
SM
468def _setup_seek_test(
469 sink_cls,
470 user_seek_beginning=None,
471 user_can_seek_beginning=None,
472 user_seek_ns_from_origin=None,
473 user_can_seek_ns_from_origin=None,
c0e46a7c 474 can_seek_forward=False,
c182d7dd 475):
0a6d7302 476 class MySourceIter(bt2._UserMessageIterator):
8d8b141d 477 def __init__(self, config, port):
0a6d7302
SM
478 tc, sc, ec = port.user_data
479 trace = tc()
480 stream = trace.create_stream(sc)
481 packet = stream.create_packet()
482
483 self._msgs = [
484 self._create_stream_beginning_message(stream),
485 self._create_packet_beginning_message(packet),
486 self._create_event_message(ec, packet),
487 self._create_event_message(ec, packet),
488 self._create_packet_end_message(packet),
489 self._create_stream_end_message(stream),
490 ]
491 self._at = 0
c0e46a7c 492 config.can_seek_forward = can_seek_forward
0a6d7302
SM
493
494 def __next__(self):
495 if self._at < len(self._msgs):
496 msg = self._msgs[self._at]
497 self._at += 1
498 return msg
499 else:
500 raise StopIteration
501
502 if user_seek_beginning is not None:
503 MySourceIter._user_seek_beginning = user_seek_beginning
504
505 if user_can_seek_beginning is not None:
14cfc8ce 506 MySourceIter._user_can_seek_beginning = user_can_seek_beginning
0a6d7302 507
c182d7dd
SM
508 if user_seek_ns_from_origin is not None:
509 MySourceIter._user_seek_ns_from_origin = user_seek_ns_from_origin
510
511 if user_can_seek_ns_from_origin is not None:
512 MySourceIter._user_can_seek_ns_from_origin = user_can_seek_ns_from_origin
513
0a6d7302 514 class MySource(bt2._UserSourceComponent, message_iterator_class=MySourceIter):
59225a3e 515 def __init__(self, config, params, obj):
0a6d7302
SM
516 tc = self._create_trace_class()
517 sc = tc.create_stream_class(supports_packets=True)
518 ec = sc.create_event_class()
519
f5567ea8 520 self._add_output_port("out", (tc, sc, ec))
0a6d7302
SM
521
522 class MyFilterIter(bt2._UserMessageIterator):
8d8b141d 523 def __init__(self, config, port):
9a2c8b8e 524 self._upstream_iter = self._create_message_iterator(
f5567ea8 525 self._component._input_ports["in"]
0a6d7302 526 )
c0e46a7c 527 config.can_seek_forward = self._upstream_iter.can_seek_forward
0a6d7302
SM
528
529 def __next__(self):
530 return next(self._upstream_iter)
531
0a6d7302 532 def _user_can_seek_beginning(self):
14cfc8ce 533 return self._upstream_iter.can_seek_beginning()
0a6d7302
SM
534
535 def _user_seek_beginning(self):
536 self._upstream_iter.seek_beginning()
537
c182d7dd
SM
538 def _user_can_seek_ns_from_origin(self, ns_from_origin):
539 return self._upstream_iter.can_seek_ns_from_origin(ns_from_origin)
540
541 def _user_seek_ns_from_origin(self, ns_from_origin):
542 self._upstream_iter.seek_ns_from_origin(ns_from_origin)
543
0a6d7302 544 class MyFilter(bt2._UserFilterComponent, message_iterator_class=MyFilterIter):
59225a3e 545 def __init__(self, config, params, obj):
f5567ea8
FD
546 self._add_input_port("in")
547 self._add_output_port("out")
0a6d7302
SM
548
549 return _create_graph(MySource, sink_cls, flt_comp_cls=MyFilter)
f00b8d40 550
0a6d7302
SM
551
552class UserMessageIteratorSeekBeginningTestCase(unittest.TestCase):
2e1b5615
SM
553 def test_can_seek_beginning_without_seek_beginning(self):
554 with self.assertRaisesRegex(
555 bt2._IncompleteUserClass,
556 "cannot create component class 'MySource': message iterator class implements _user_can_seek_beginning but not _user_seek_beginning",
557 ):
558 _setup_seek_test(SimpleSink, user_can_seek_beginning=lambda: None)
559
f00b8d40 560 def test_can_seek_beginning(self):
6c373cc9 561 class MySink(bt2._UserSinkComponent):
59225a3e 562 def __init__(self, config, params, obj):
f5567ea8 563 self._add_input_port("in")
6c373cc9
PP
564
565 def _user_graph_is_configured(self):
f5567ea8 566 self._msg_iter = self._create_message_iterator(self._input_ports["in"])
6c373cc9
PP
567
568 def _user_consume(self):
569 nonlocal can_seek_beginning
14cfc8ce 570 can_seek_beginning = self._msg_iter.can_seek_beginning()
6c373cc9 571
6a91742b 572 def _user_can_seek_beginning(self):
6c373cc9
PP
573 nonlocal input_port_iter_can_seek_beginning
574 return input_port_iter_can_seek_beginning
f00b8d40 575
0a6d7302 576 graph = _setup_seek_test(
2e1b5615
SM
577 MySink,
578 user_can_seek_beginning=_user_can_seek_beginning,
579 user_seek_beginning=lambda: None,
0a6d7302 580 )
f00b8d40 581
6c373cc9
PP
582 input_port_iter_can_seek_beginning = True
583 can_seek_beginning = None
584 graph.run_once()
7f0c21bb 585 self.assertIs(can_seek_beginning, True)
f00b8d40 586
6c373cc9
PP
587 input_port_iter_can_seek_beginning = False
588 can_seek_beginning = None
589 graph.run_once()
7f0c21bb 590 self.assertIs(can_seek_beginning, False)
f00b8d40 591
0a6d7302
SM
592 def test_no_can_seek_beginning_with_seek_beginning(self):
593 # Test an iterator without a _user_can_seek_beginning method, but with
594 # a _user_seek_beginning method.
595 class MySink(bt2._UserSinkComponent):
59225a3e 596 def __init__(self, config, params, obj):
f5567ea8 597 self._add_input_port("in")
0a6d7302
SM
598
599 def _user_graph_is_configured(self):
f5567ea8 600 self._msg_iter = self._create_message_iterator(self._input_ports["in"])
0a6d7302
SM
601
602 def _user_consume(self):
603 nonlocal can_seek_beginning
14cfc8ce 604 can_seek_beginning = self._msg_iter.can_seek_beginning()
0a6d7302
SM
605
606 def _user_seek_beginning(self):
607 pass
f00b8d40 608
0a6d7302 609 graph = _setup_seek_test(MySink, user_seek_beginning=_user_seek_beginning)
6c373cc9
PP
610 can_seek_beginning = None
611 graph.run_once()
7f0c21bb 612 self.assertIs(can_seek_beginning, True)
f00b8d40 613
0a6d7302
SM
614 def test_no_can_seek_beginning(self):
615 # Test an iterator without a _user_can_seek_beginning method, without
616 # a _user_seek_beginning method.
617 class MySink(bt2._UserSinkComponent):
59225a3e 618 def __init__(self, config, params, obj):
f5567ea8 619 self._add_input_port("in")
0a6d7302
SM
620
621 def _user_graph_is_configured(self):
f5567ea8 622 self._msg_iter = self._create_message_iterator(self._input_ports["in"])
0a6d7302
SM
623
624 def _user_consume(self):
625 nonlocal can_seek_beginning
14cfc8ce 626 can_seek_beginning = self._msg_iter.can_seek_beginning()
0a6d7302
SM
627
628 graph = _setup_seek_test(MySink)
6c373cc9
PP
629 can_seek_beginning = None
630 graph.run_once()
7f0c21bb 631 self.assertIs(can_seek_beginning, False)
f00b8d40 632
f2fb1b32
SM
633 def test_can_seek_beginning_user_error(self):
634 class MySink(bt2._UserSinkComponent):
59225a3e 635 def __init__(self, config, params, obj):
f5567ea8 636 self._add_input_port("in")
f2fb1b32
SM
637
638 def _user_graph_is_configured(self):
f5567ea8 639 self._msg_iter = self._create_message_iterator(self._input_ports["in"])
f2fb1b32
SM
640
641 def _user_consume(self):
642 # This is expected to raise.
14cfc8ce 643 self._msg_iter.can_seek_beginning()
f2fb1b32
SM
644
645 def _user_can_seek_beginning(self):
f5567ea8 646 raise ValueError("moustiquaire")
f2fb1b32
SM
647
648 graph = _setup_seek_test(
2e1b5615
SM
649 MySink,
650 user_can_seek_beginning=_user_can_seek_beginning,
651 user_seek_beginning=lambda: None,
f2fb1b32
SM
652 )
653
654 with self.assertRaises(bt2._Error) as ctx:
655 graph.run_once()
656
657 cause = ctx.exception[0]
f5567ea8 658 self.assertIn("ValueError: moustiquaire", cause.message)
f2fb1b32
SM
659
660 def test_can_seek_beginning_wrong_return_value(self):
661 class MySink(bt2._UserSinkComponent):
59225a3e 662 def __init__(self, config, params, obj):
f5567ea8 663 self._add_input_port("in")
f2fb1b32
SM
664
665 def _user_graph_is_configured(self):
f5567ea8 666 self._msg_iter = self._create_message_iterator(self._input_ports["in"])
f2fb1b32
SM
667
668 def _user_consume(self):
669 # This is expected to raise.
14cfc8ce 670 self._msg_iter.can_seek_beginning()
f2fb1b32
SM
671
672 def _user_can_seek_beginning(self):
f5567ea8 673 return "Amqui"
f2fb1b32
SM
674
675 graph = _setup_seek_test(
2e1b5615
SM
676 MySink,
677 user_can_seek_beginning=_user_can_seek_beginning,
678 user_seek_beginning=lambda: None,
f2fb1b32
SM
679 )
680
681 with self.assertRaises(bt2._Error) as ctx:
682 graph.run_once()
683
684 cause = ctx.exception[0]
685 self.assertIn("TypeError: 'str' is not a 'bool' object", cause.message)
686
f00b8d40 687 def test_seek_beginning(self):
6c373cc9 688 class MySink(bt2._UserSinkComponent):
59225a3e 689 def __init__(self, config, params, obj):
f5567ea8 690 self._add_input_port("in")
f00b8d40 691
6c373cc9 692 def _user_graph_is_configured(self):
f5567ea8 693 self._msg_iter = self._create_message_iterator(self._input_ports["in"])
6c373cc9
PP
694
695 def _user_consume(self):
696 nonlocal do_seek_beginning
697 nonlocal msg
698
699 if do_seek_beginning:
700 self._msg_iter.seek_beginning()
701 return
702
703 msg = next(self._msg_iter)
704
0a6d7302
SM
705 def _user_seek_beginning(self):
706 self._at = 0
707
6c373cc9 708 msg = None
0a6d7302
SM
709 graph = _setup_seek_test(MySink, user_seek_beginning=_user_seek_beginning)
710
711 # Consume message.
712 do_seek_beginning = False
6c373cc9 713 graph.run_once()
f0a42b33 714 self.assertIs(type(msg), bt2._StreamBeginningMessageConst)
0a6d7302
SM
715
716 # Consume message.
6c373cc9 717 graph.run_once()
f0a42b33 718 self.assertIs(type(msg), bt2._PacketBeginningMessageConst)
0a6d7302
SM
719
720 # Seek beginning.
6c373cc9
PP
721 do_seek_beginning = True
722 graph.run_once()
0a6d7302
SM
723
724 # Consume message.
6c373cc9
PP
725 do_seek_beginning = False
726 graph.run_once()
f0a42b33 727 self.assertIs(type(msg), bt2._StreamBeginningMessageConst)
f00b8d40 728
6c373cc9
PP
729 def test_seek_beginning_user_error(self):
730 class MySink(bt2._UserSinkComponent):
59225a3e 731 def __init__(self, config, params, obj):
f5567ea8 732 self._add_input_port("in")
f00b8d40 733
6c373cc9 734 def _user_graph_is_configured(self):
f5567ea8 735 self._msg_iter = self._create_message_iterator(self._input_ports["in"])
f00b8d40 736
6c373cc9
PP
737 def _user_consume(self):
738 self._msg_iter.seek_beginning()
f00b8d40 739
0a6d7302 740 def _user_seek_beginning(self):
f5567ea8 741 raise ValueError("ouch")
f00b8d40 742
0a6d7302 743 graph = _setup_seek_test(MySink, user_seek_beginning=_user_seek_beginning)
f00b8d40 744
694c792b 745 with self.assertRaises(bt2._Error):
6c373cc9 746 graph.run_once()
f00b8d40
SM
747
748
c182d7dd 749class UserMessageIteratorSeekNsFromOriginTestCase(unittest.TestCase):
2e1b5615
SM
750 def test_can_seek_ns_from_origin_without_seek_ns_from_origin(self):
751 # Test the case where:
752 #
753 # - can_seek_ns_from_origin: Returns True (don't really care, as long
754 # as it's provided)
755 # - seek_ns_from_origin provided: No
756 # - can the iterator seek beginning: Don't care
757 # - can the iterator seek forward: Don't care
758 for can_seek_ns_from_origin in (False, True):
759 for iter_can_seek_beginning in (False, True):
760 for iter_can_seek_forward in (False, True):
761 with self.assertRaisesRegex(
762 bt2._IncompleteUserClass,
763 "cannot create component class 'MySource': message iterator class implements _user_can_seek_ns_from_origin but not _user_seek_ns_from_origin",
764 ):
765 self._can_seek_ns_from_origin_test(
766 None,
767 user_can_seek_ns_from_origin_ret_val=True,
768 user_seek_ns_from_origin_provided=False,
769 iter_can_seek_beginning=iter_can_seek_beginning,
770 iter_can_seek_forward=iter_can_seek_forward,
771 )
772
c0e46a7c
SM
773 def test_can_seek_ns_from_origin_returns_true(self):
774 # Test the case where:
775 #
776 # - can_seek_ns_from_origin: returns True
2e1b5615 777 # - seek_ns_from_origin provided: Yes
c0e46a7c
SM
778 # - can the iterator seek beginning: Don't care
779 # - can the iterator seek forward: Don't care
780 #
781 # We expect iter.can_seek_ns_from_origin to return True.
2e1b5615
SM
782 for iter_can_seek_beginning in (False, True):
783 for iter_can_seek_forward in (False, True):
784 self._can_seek_ns_from_origin_test(
785 expected_outcome=True,
786 user_can_seek_ns_from_origin_ret_val=True,
787 user_seek_ns_from_origin_provided=True,
788 iter_can_seek_beginning=iter_can_seek_beginning,
789 iter_can_seek_forward=iter_can_seek_forward,
790 )
c0e46a7c
SM
791
792 def test_can_seek_ns_from_origin_returns_false_can_seek_beginning_forward_seekable(
75882e97 793 self,
c0e46a7c
SM
794 ):
795 # Test the case where:
796 #
797 # - can_seek_ns_from_origin: returns False
2e1b5615 798 # - seek_ns_from_origin provided: Yes
c0e46a7c
SM
799 # - can the iterator seek beginning: Yes
800 # - can the iterator seek forward: Yes
801 #
802 # We expect iter.can_seek_ns_from_origin to return True.
2e1b5615
SM
803 self._can_seek_ns_from_origin_test(
804 expected_outcome=True,
805 user_can_seek_ns_from_origin_ret_val=False,
806 user_seek_ns_from_origin_provided=True,
807 iter_can_seek_beginning=True,
808 iter_can_seek_forward=True,
809 )
c182d7dd 810
c0e46a7c 811 def test_can_seek_ns_from_origin_returns_false_can_seek_beginning_not_forward_seekable(
75882e97 812 self,
c0e46a7c
SM
813 ):
814 # Test the case where:
815 #
816 # - can_seek_ns_from_origin: returns False
2e1b5615 817 # - seek_ns_from_origin provided: Yes
c0e46a7c
SM
818 # - can the iterator seek beginning: Yes
819 # - can the iterator seek forward: No
820 #
821 # We expect iter.can_seek_ns_from_origin to return False.
2e1b5615
SM
822 self._can_seek_ns_from_origin_test(
823 expected_outcome=False,
824 user_can_seek_ns_from_origin_ret_val=False,
825 user_seek_ns_from_origin_provided=True,
826 iter_can_seek_beginning=True,
827 iter_can_seek_forward=False,
828 )
c182d7dd 829
c0e46a7c 830 def test_can_seek_ns_from_origin_returns_false_cant_seek_beginning_forward_seekable(
75882e97 831 self,
c0e46a7c
SM
832 ):
833 # Test the case where:
834 #
835 # - can_seek_ns_from_origin: returns False
2e1b5615 836 # - seek_ns_from_origin provided: Yes
c0e46a7c
SM
837 # - can the iterator seek beginning: No
838 # - can the iterator seek forward: Yes
839 #
840 # We expect iter.can_seek_ns_from_origin to return False.
c0e46a7c
SM
841 self._can_seek_ns_from_origin_test(
842 expected_outcome=False,
843 user_can_seek_ns_from_origin_ret_val=False,
2e1b5615 844 user_seek_ns_from_origin_provided=True,
c0e46a7c
SM
845 iter_can_seek_beginning=False,
846 iter_can_seek_forward=True,
847 )
848
849 def test_can_seek_ns_from_origin_returns_false_cant_seek_beginning_not_forward_seekable(
75882e97 850 self,
c0e46a7c
SM
851 ):
852 # Test the case where:
853 #
854 # - can_seek_ns_from_origin: returns False
2e1b5615 855 # - seek_ns_from_origin provided: Yes
c0e46a7c
SM
856 # - can the iterator seek beginning: No
857 # - can the iterator seek forward: No
858 #
859 # We expect iter.can_seek_ns_from_origin to return False.
2e1b5615
SM
860 self._can_seek_ns_from_origin_test(
861 expected_outcome=False,
862 user_can_seek_ns_from_origin_ret_val=False,
863 user_seek_ns_from_origin_provided=True,
864 iter_can_seek_beginning=False,
865 iter_can_seek_forward=False,
866 )
c0e46a7c
SM
867
868 def test_no_can_seek_ns_from_origin_seek_ns_from_origin(self):
869 # Test the case where:
870 #
871 # - can_seek_ns_from_origin: Not provided
872 # - seek_ns_from_origin provided: Yes
873 # - can the iterator seek beginning: Don't care
874 # - can the iterator seek forward: Don't care
875 #
876 # We expect iter.can_seek_ns_from_origin to return True.
877 for iter_can_seek_beginning in (False, True):
878 for iter_can_seek_forward in (False, True):
879 self._can_seek_ns_from_origin_test(
880 expected_outcome=True,
881 user_can_seek_ns_from_origin_ret_val=None,
882 user_seek_ns_from_origin_provided=True,
883 iter_can_seek_beginning=iter_can_seek_beginning,
884 iter_can_seek_forward=iter_can_seek_forward,
c182d7dd
SM
885 )
886
c0e46a7c 887 def test_no_can_seek_ns_from_origin_no_seek_ns_from_origin_can_seek_beginning_forward_seekable(
75882e97 888 self,
c0e46a7c
SM
889 ):
890 # Test the case where:
891 #
892 # - can_seek_ns_from_origin: Not provided
893 # - seek_ns_from_origin provided: Not provided
894 # - can the iterator seek beginning: Yes
895 # - can the iterator seek forward: Yes
896 #
897 # We expect iter.can_seek_ns_from_origin to return True.
898 self._can_seek_ns_from_origin_test(
899 expected_outcome=True,
900 user_can_seek_ns_from_origin_ret_val=None,
901 user_seek_ns_from_origin_provided=False,
902 iter_can_seek_beginning=True,
903 iter_can_seek_forward=True,
904 )
c182d7dd 905
c0e46a7c 906 def test_no_can_seek_ns_from_origin_no_seek_ns_from_origin_can_seek_beginning_not_forward_seekable(
75882e97 907 self,
c0e46a7c
SM
908 ):
909 # Test the case where:
910 #
911 # - can_seek_ns_from_origin: Not provided
912 # - seek_ns_from_origin provided: Not provided
913 # - can the iterator seek beginning: Yes
914 # - can the iterator seek forward: No
915 #
916 # We expect iter.can_seek_ns_from_origin to return False.
917 self._can_seek_ns_from_origin_test(
918 expected_outcome=False,
919 user_can_seek_ns_from_origin_ret_val=None,
920 user_seek_ns_from_origin_provided=False,
921 iter_can_seek_beginning=True,
922 iter_can_seek_forward=False,
c182d7dd
SM
923 )
924
c0e46a7c 925 def test_no_can_seek_ns_from_origin_no_seek_ns_from_origin_cant_seek_beginning_forward_seekable(
75882e97 926 self,
c0e46a7c
SM
927 ):
928 # Test the case where:
929 #
930 # - can_seek_ns_from_origin: Not provided
931 # - seek_ns_from_origin provided: Not provided
932 # - can the iterator seek beginning: No
933 # - can the iterator seek forward: Yes
934 #
935 # We expect iter.can_seek_ns_from_origin to return False.
936 self._can_seek_ns_from_origin_test(
937 expected_outcome=False,
938 user_can_seek_ns_from_origin_ret_val=None,
939 user_seek_ns_from_origin_provided=False,
940 iter_can_seek_beginning=False,
941 iter_can_seek_forward=True,
942 )
c182d7dd 943
c0e46a7c 944 def test_no_can_seek_ns_from_origin_no_seek_ns_from_origin_cant_seek_beginning_not_forward_seekable(
75882e97 945 self,
c0e46a7c
SM
946 ):
947 # Test the case where:
948 #
949 # - can_seek_ns_from_origin: Not provided
950 # - seek_ns_from_origin provided: Not provided
951 # - can the iterator seek beginning: No
952 # - can the iterator seek forward: No
953 #
954 # We expect iter.can_seek_ns_from_origin to return False.
955 self._can_seek_ns_from_origin_test(
956 expected_outcome=False,
957 user_can_seek_ns_from_origin_ret_val=None,
958 user_seek_ns_from_origin_provided=False,
959 iter_can_seek_beginning=False,
960 iter_can_seek_forward=False,
961 )
c182d7dd 962
c0e46a7c
SM
963 def _can_seek_ns_from_origin_test(
964 self,
965 expected_outcome,
966 user_can_seek_ns_from_origin_ret_val,
967 user_seek_ns_from_origin_provided,
968 iter_can_seek_beginning,
969 iter_can_seek_forward,
970 ):
c182d7dd 971 class MySink(bt2._UserSinkComponent):
59225a3e 972 def __init__(self, config, params, obj):
f5567ea8 973 self._add_input_port("in")
c182d7dd
SM
974
975 def _user_graph_is_configured(self):
f5567ea8 976 self._msg_iter = self._create_message_iterator(self._input_ports["in"])
c182d7dd
SM
977
978 def _user_consume(self):
979 nonlocal can_seek_ns_from_origin
c182d7dd 980 can_seek_ns_from_origin = self._msg_iter.can_seek_ns_from_origin(
c0e46a7c 981 passed_ns_from_origin
c182d7dd
SM
982 )
983
c0e46a7c 984 if user_can_seek_ns_from_origin_ret_val is not None:
c182d7dd 985
c0e46a7c
SM
986 def user_can_seek_ns_from_origin(self, ns_from_origin):
987 nonlocal received_ns_from_origin
988 received_ns_from_origin = ns_from_origin
989 return user_can_seek_ns_from_origin_ret_val
c182d7dd 990
c0e46a7c
SM
991 else:
992 user_can_seek_ns_from_origin = None
c182d7dd 993
c0e46a7c 994 if user_seek_ns_from_origin_provided:
c182d7dd 995
c0e46a7c
SM
996 def user_seek_ns_from_origin(self, ns_from_origin):
997 pass
c182d7dd 998
c0e46a7c
SM
999 else:
1000 user_seek_ns_from_origin = None
c182d7dd 1001
c0e46a7c 1002 if iter_can_seek_beginning:
c182d7dd 1003
c0e46a7c
SM
1004 def user_seek_beginning(self):
1005 pass
c182d7dd 1006
c0e46a7c
SM
1007 else:
1008 user_seek_beginning = None
c182d7dd 1009
c0e46a7c
SM
1010 graph = _setup_seek_test(
1011 MySink,
1012 user_can_seek_ns_from_origin=user_can_seek_ns_from_origin,
1013 user_seek_ns_from_origin=user_seek_ns_from_origin,
1014 user_seek_beginning=user_seek_beginning,
1015 can_seek_forward=iter_can_seek_forward,
1016 )
c182d7dd 1017
c0e46a7c
SM
1018 passed_ns_from_origin = 77
1019 received_ns_from_origin = None
c182d7dd 1020 can_seek_ns_from_origin = None
c182d7dd 1021 graph.run_once()
c0e46a7c
SM
1022 self.assertIs(can_seek_ns_from_origin, expected_outcome)
1023
1024 if user_can_seek_ns_from_origin_ret_val is not None:
1025 self.assertEqual(received_ns_from_origin, passed_ns_from_origin)
c182d7dd
SM
1026
1027 def test_can_seek_ns_from_origin_user_error(self):
1028 class MySink(bt2._UserSinkComponent):
59225a3e 1029 def __init__(self, config, params, obj):
f5567ea8 1030 self._add_input_port("in")
c182d7dd
SM
1031
1032 def _user_graph_is_configured(self):
f5567ea8 1033 self._msg_iter = self._create_message_iterator(self._input_ports["in"])
c182d7dd
SM
1034
1035 def _user_consume(self):
1036 # This is expected to raise.
1037 self._msg_iter.can_seek_ns_from_origin(2)
1038
1039 def _user_can_seek_ns_from_origin(self, ns_from_origin):
f5567ea8 1040 raise ValueError("Joutel")
c182d7dd
SM
1041
1042 graph = _setup_seek_test(
2e1b5615
SM
1043 MySink,
1044 user_can_seek_ns_from_origin=_user_can_seek_ns_from_origin,
1045 user_seek_ns_from_origin=lambda: None,
c182d7dd
SM
1046 )
1047
1048 with self.assertRaises(bt2._Error) as ctx:
1049 graph.run_once()
1050
1051 cause = ctx.exception[0]
f5567ea8 1052 self.assertIn("ValueError: Joutel", cause.message)
c182d7dd
SM
1053
1054 def test_can_seek_ns_from_origin_wrong_return_value(self):
1055 class MySink(bt2._UserSinkComponent):
59225a3e 1056 def __init__(self, config, params, obj):
f5567ea8 1057 self._add_input_port("in")
c182d7dd
SM
1058
1059 def _user_graph_is_configured(self):
f5567ea8 1060 self._msg_iter = self._create_message_iterator(self._input_ports["in"])
c182d7dd
SM
1061
1062 def _user_consume(self):
1063 # This is expected to raise.
1064 self._msg_iter.can_seek_ns_from_origin(2)
1065
1066 def _user_can_seek_ns_from_origin(self, ns_from_origin):
f5567ea8 1067 return "Nitchequon"
c182d7dd
SM
1068
1069 graph = _setup_seek_test(
2e1b5615
SM
1070 MySink,
1071 user_can_seek_ns_from_origin=_user_can_seek_ns_from_origin,
1072 user_seek_ns_from_origin=lambda: None,
c182d7dd
SM
1073 )
1074
1075 with self.assertRaises(bt2._Error) as ctx:
1076 graph.run_once()
1077
1078 cause = ctx.exception[0]
1079 self.assertIn("TypeError: 'str' is not a 'bool' object", cause.message)
1080
1081 def test_seek_ns_from_origin(self):
1082 class MySink(bt2._UserSinkComponent):
59225a3e 1083 def __init__(self, config, params, obj):
f5567ea8 1084 self._add_input_port("in")
c182d7dd
SM
1085
1086 def _user_graph_is_configured(self):
f5567ea8 1087 self._msg_iter = self._create_message_iterator(self._input_ports["in"])
c182d7dd
SM
1088
1089 def _user_consume(self):
1090 self._msg_iter.seek_ns_from_origin(17)
1091
1092 def _user_seek_ns_from_origin(self, ns_from_origin):
1093 nonlocal actual_ns_from_origin
1094 actual_ns_from_origin = ns_from_origin
1095
c182d7dd
SM
1096 graph = _setup_seek_test(
1097 MySink, user_seek_ns_from_origin=_user_seek_ns_from_origin
1098 )
1099
1100 actual_ns_from_origin = None
1101 graph.run_once()
1102 self.assertEqual(actual_ns_from_origin, 17)
1103
1104
f5567ea8 1105if __name__ == "__main__":
f00b8d40 1106 unittest.main()
This page took 0.128846 seconds and 5 git commands to generate.