1 # SPDX-License-Identifier: GPL-2.0-only
3 # Copyright (C) 2019 EfficiOS Inc.
10 from bt2
import port
as bt2_port
11 from bt2
import message_iterator
as bt2_message_iterator
12 from utils
import TestOutputPortMessageIterator
15 class SimpleSink(bt2
._UserSinkComponent
):
16 # Straightforward sink that creates one input port (`in`) and consumes from
19 def __init__(self
, config
, params
, obj
):
20 self
._add
_input
_port
("in")
22 def _user_consume(self
):
25 def _user_graph_is_configured(self
):
26 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
29 def _create_graph(src_comp_cls
, sink_comp_cls
, flt_comp_cls
=None):
32 src_comp
= graph
.add_component(src_comp_cls
, "src")
33 sink_comp
= graph
.add_component(sink_comp_cls
, "sink")
35 if flt_comp_cls
is not None:
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"])
40 graph
.connect_ports(src_comp
.output_ports
["out"], sink_comp
.input_ports
["in"])
45 class UserMessageIteratorTestCase(unittest
.TestCase
):
47 the_output_port_from_source
= None
48 the_output_port_from_iter
= None
50 class MyIter(bt2
._UserMessageIterator
):
51 def __init__(self
, config
, self_port_output
):
53 nonlocal the_output_port_from_iter
55 the_output_port_from_iter
= self_port_output
57 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
58 def __init__(self
, config
, params
, obj
):
59 nonlocal the_output_port_from_source
60 the_output_port_from_source
= self
._add
_output
_port
("out", "user data")
63 graph
= _create_graph(MySource
, SimpleSink
)
65 self
.assertTrue(initialized
)
67 the_output_port_from_source
.addr
, the_output_port_from_iter
.addr
69 self
.assertEqual(the_output_port_from_iter
.user_data
, "user data")
71 def test_create_from_message_iterator(self
):
72 class MySourceIter(bt2
._UserMessageIterator
):
73 def __init__(self
, config
, self_port_output
):
74 nonlocal src_iter_initialized
75 src_iter_initialized
= True
77 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MySourceIter
):
78 def __init__(self
, config
, params
, obj
):
79 self
._add
_output
_port
("out")
81 class MyFilterIter(bt2
._UserMessageIterator
):
82 def __init__(self
, config
, self_port_output
):
83 nonlocal flt_iter_initialized
84 flt_iter_initialized
= True
85 self
._up
_iter
= self
._create
_message
_iterator
(
86 self
._component
._input
_ports
["in"]
90 return next(self
._up
_iter
)
92 class MyFilter(bt2
._UserFilterComponent
, message_iterator_class
=MyFilterIter
):
93 def __init__(self
, config
, params
, obj
):
94 self
._add
_input
_port
("in")
95 self
._add
_output
_port
("out")
97 src_iter_initialized
= False
98 flt_iter_initialized
= False
99 graph
= _create_graph(MySource
, SimpleSink
, MyFilter
)
101 self
.assertTrue(src_iter_initialized
)
102 self
.assertTrue(flt_iter_initialized
)
104 # Test that creating a message iterator from a sink component on a
105 # non-connected input port raises.
106 def test_create_from_sink_component_unconnected_port_raises(self
):
107 class MySink(bt2
._UserSinkComponent
):
108 def __init__(comp_self
, config
, params
, obj
):
109 comp_self
._input
_port
= comp_self
._add
_input
_port
("in")
111 def _user_graph_is_configured(comp_self
):
112 with self
.assertRaisesRegex(ValueError, "input port is not connected"):
113 comp_self
._create
_message
_iterator
(comp_self
._input
_port
)
118 def _user_consume(self
):
123 graph
.add_component(MySink
, "snk")
125 self
.assertTrue(seen
)
127 # Test that creating a message iterator from a message iterator on a
128 # non-connected input port raises.
129 def test_create_from_message_iterator_unconnected_port_raises(self
):
130 class MyFilterIter(bt2
._UserMessageIterator
):
131 def __init__(iter_self
, config
, port
):
132 input_port
= iter_self
._component
._input
_ports
["in"]
134 with self
.assertRaisesRegex(ValueError, "input port is not connected"):
135 iter_self
._create
_message
_iterator
(input_port
)
140 class MyFilter(bt2
._UserFilterComponent
, message_iterator_class
=MyFilterIter
):
141 def __init__(comp_self
, config
, params
, obj
):
142 comp_self
._add
_input
_port
("in")
143 comp_self
._add
_output
_port
("out")
145 class MySink(bt2
._UserSinkComponent
):
146 def __init__(comp_self
, config
, params
, obj
):
147 comp_self
._input
_port
= comp_self
._add
_input
_port
("in")
149 def _user_graph_is_configured(comp_self
):
150 comp_self
._input
_iter
= comp_self
._create
_message
_iterator
(
151 comp_self
._input
_port
154 def _user_consume(self
):
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"])
163 self
.assertTrue(seen
)
165 def test_create_user_error(self
):
166 # This tests both error handling by
167 # _UserSinkComponent._create_message_iterator
168 # and _UserMessageIterator._create_message_iterator, as they
169 # are both used in the graph.
170 class MySourceIter(bt2
._UserMessageIterator
):
171 def __init__(self
, config
, self_port_output
):
172 raise ValueError("Very bad error")
174 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MySourceIter
):
175 def __init__(self
, config
, params
, obj
):
176 self
._add
_output
_port
("out")
178 class MyFilterIter(bt2
._UserMessageIterator
):
179 def __init__(self
, config
, self_port_output
):
180 # This is expected to raise because of the error in
181 # MySourceIter.__init__.
182 self
._create
_message
_iterator
(self
._component
._input
_ports
["in"])
184 class MyFilter(bt2
._UserFilterComponent
, message_iterator_class
=MyFilterIter
):
185 def __init__(self
, config
, params
, obj
):
186 self
._add
_input
_port
("in")
187 self
._add
_output
_port
("out")
189 graph
= _create_graph(MySource
, SimpleSink
, MyFilter
)
191 with self
.assertRaises(bt2
._Error
) as ctx
:
197 self
.assertIsInstance(cause
, bt2
._MessageIteratorErrorCause
)
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
)
202 def test_finalize(self
):
203 class MyIter(bt2
._UserMessageIterator
):
204 def _user_finalize(self
):
208 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
209 def __init__(self
, config
, params
, obj
):
210 self
._add
_output
_port
("out")
213 graph
= _create_graph(MySource
, SimpleSink
)
216 self
.assertTrue(finalized
)
218 def test_config_parameter(self
):
219 class MyIter(bt2
._UserMessageIterator
):
220 def __init__(self
, config
, port
):
222 config_type
= type(config
)
224 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
225 def __init__(self
, config
, params
, obj
):
226 self
._add
_output
_port
("out")
229 graph
= _create_graph(MySource
, SimpleSink
)
231 self
.assertIs(config_type
, bt2_message_iterator
._MessageIteratorConfiguration
)
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
239 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
240 def __init__(self
, config
, params
, obj
):
241 self
._add
_output
_port
("out")
243 class MySink(bt2
._UserSinkComponent
):
244 def __init__(self
, config
, params
, obj
):
245 self
._add
_input
_port
("in")
247 def _user_graph_is_configured(self
):
248 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
250 def _user_consume(self
):
251 nonlocal can_seek_forward
252 can_seek_forward
= self
._msg
_iter
.can_seek_forward
254 can_seek_forward
= None
255 graph
= _create_graph(MySource
, MySink
)
257 self
.assertIs(can_seek_forward
, set_can_seek_forward
)
259 def test_config_can_seek_forward_default(self
):
260 self
._test
_config
_can
_seek
_forward
(False)
262 def test_config_can_seek_forward(self
):
263 self
._test
_config
_can
_seek
_forward
(True)
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
270 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
271 def __init__(self
, config
, params
, obj
):
272 self
._add
_output
_port
("out")
274 graph
= _create_graph(MySource
, SimpleSink
)
275 with self
.assertRaises(bt2
._Error
) as ctx
:
278 root_cause
= ctx
.exception
[0]
279 self
.assertIn("TypeError: 'int' is not a 'bool' object", root_cause
.message
)
281 def test_component(self
):
282 class MyIter(bt2
._UserMessageIterator
):
283 def __init__(self
, config
, self_port_output
):
285 salut
= self
._component
._salut
287 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
288 def __init__(self
, config
, params
, obj
):
289 self
._add
_output
_port
("out")
293 graph
= _create_graph(MySource
, SimpleSink
)
295 self
.assertEqual(salut
, 23)
298 class MyIter(bt2
._UserMessageIterator
):
299 def __init__(self_iter
, config
, self_port_output
):
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
)
307 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
308 def __init__(self
, config
, params
, obj
):
309 self
._add
_output
_port
("out")
312 graph
= _create_graph(MySource
, SimpleSink
)
314 self
.assertTrue(called
)
317 class MyIter(bt2
._UserMessageIterator
):
318 def __init__(self
, config
, self_port_output
):
322 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
323 def __init__(self
, config
, params
, obj
):
324 self
._add
_output
_port
("out")
327 graph
= _create_graph(MySource
, SimpleSink
)
329 self
.assertIsNotNone(addr
)
330 self
.assertNotEqual(addr
, 0)
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
):
336 def __init__(self
, config
, port
):
337 tc
, sc
, ec
= port
.user_data
339 stream
= trace
.create_stream(sc
)
340 packet
= stream
.create_packet()
342 # This message will be returned twice by __next__.
343 event_message
= self
._create
_event
_message
(ec
, packet
)
346 self
._create
_stream
_beginning
_message
(stream
),
347 self
._create
_packet
_beginning
_message
(packet
),
353 return self
._msgs
.pop(0)
355 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
356 def __init__(self
, config
, params
, obj
):
357 tc
= self
._create
_trace
_class
()
358 sc
= tc
.create_stream_class(supports_packets
=True)
359 ec
= sc
.create_event_class()
360 self
._add
_output
_port
("out", (tc
, sc
, ec
))
363 src
= graph
.add_component(MySource
, "src")
364 it
= TestOutputPortMessageIterator(graph
, src
.output_ports
["out"])
366 # Skip beginning messages.
368 self
.assertIs(type(msg
), bt2
._StreamBeginningMessageConst
)
370 self
.assertIs(type(msg
), bt2
._PacketBeginningMessageConst
)
375 self
.assertIs(type(msg_ev1
), bt2
._EventMessageConst
)
376 self
.assertIs(type(msg_ev2
), bt2
._EventMessageConst
)
377 self
.assertEqual(msg_ev1
.addr
, msg_ev2
.addr
)
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
):
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
388 if before
== sys
.getrefcount(None):
389 raise unittest
.SkipTest("`None` is immortal")
391 class MyIter(bt2
._UserMessageIterator
):
395 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
396 def __init__(self
, config
, params
, obj
):
397 self
._add
_output
_port
("out")
400 src
= graph
.add_component(MySource
, "src")
401 it
= TestOutputPortMessageIterator(graph
, src
.output_ports
["out"])
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
408 for i
in range(none_ref_count
):
409 with self
.assertRaises(bt2
.TryAgain
):
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:
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
):
422 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MySourceIter
):
423 def __init__(self
, config
, params
, obj
):
424 self
._add
_output
_port
("out")
426 class MyFilterIter(bt2
._UserMessageIterator
):
427 def __init__(self
, config
, port
):
428 # First, create an upstream iterator.
429 self
._upstream
_iter
= self
._create
_message
_iterator
(
430 self
._component
._input
_ports
["in"]
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.
438 # Finally, raise an exception to make __init__ fail.
439 raise ValueError("woops")
441 class MyFilter(bt2
._UserFilterComponent
, message_iterator_class
=MyFilterIter
):
442 def __init__(self
, config
, params
, obj
):
443 self
._in
= self
._add
_input
_port
("in")
444 self
._out
= 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")
450 def _user_graph_is_configured(self
):
451 self
._upstream
_iter
= self
._create
_message
_iterator
(self
._input
_port
)
453 def _user_consume(self
):
454 # We should not reach this.
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"])
464 with self
.assertRaisesRegex(bt2
._Error
, "ValueError: woops"):
468 def _setup_seek_test(
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,
474 can_seek_forward
=False,
476 class MySourceIter(bt2
._UserMessageIterator
):
477 def __init__(self
, config
, port
):
478 tc
, sc
, ec
= port
.user_data
480 stream
= trace
.create_stream(sc
)
481 packet
= stream
.create_packet()
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
),
492 config
.can_seek_forward
= can_seek_forward
495 if self
._at
< len(self
._msgs
):
496 msg
= self
._msgs
[self
._at
]
502 if user_seek_beginning
is not None:
503 MySourceIter
._user
_seek
_beginning
= user_seek_beginning
505 if user_can_seek_beginning
is not None:
506 MySourceIter
._user
_can
_seek
_beginning
= user_can_seek_beginning
508 if user_seek_ns_from_origin
is not None:
509 MySourceIter
._user
_seek
_ns
_from
_origin
= user_seek_ns_from_origin
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
514 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MySourceIter
):
515 def __init__(self
, config
, params
, obj
):
516 tc
= self
._create
_trace
_class
()
517 sc
= tc
.create_stream_class(supports_packets
=True)
518 ec
= sc
.create_event_class()
520 self
._add
_output
_port
("out", (tc
, sc
, ec
))
522 class MyFilterIter(bt2
._UserMessageIterator
):
523 def __init__(self
, config
, port
):
524 self
._upstream
_iter
= self
._create
_message
_iterator
(
525 self
._component
._input
_ports
["in"]
527 config
.can_seek_forward
= self
._upstream
_iter
.can_seek_forward
530 return next(self
._upstream
_iter
)
532 def _user_can_seek_beginning(self
):
533 return self
._upstream
_iter
.can_seek_beginning()
535 def _user_seek_beginning(self
):
536 self
._upstream
_iter
.seek_beginning()
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
)
541 def _user_seek_ns_from_origin(self
, ns_from_origin
):
542 self
._upstream
_iter
.seek_ns_from_origin(ns_from_origin
)
544 class MyFilter(bt2
._UserFilterComponent
, message_iterator_class
=MyFilterIter
):
545 def __init__(self
, config
, params
, obj
):
546 self
._add
_input
_port
("in")
547 self
._add
_output
_port
("out")
549 return _create_graph(MySource
, sink_cls
, flt_comp_cls
=MyFilter
)
552 class UserMessageIteratorSeekBeginningTestCase(unittest
.TestCase
):
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",
558 _setup_seek_test(SimpleSink
, user_can_seek_beginning
=lambda: None)
560 def test_can_seek_beginning(self
):
561 class MySink(bt2
._UserSinkComponent
):
562 def __init__(self
, config
, params
, obj
):
563 self
._add
_input
_port
("in")
565 def _user_graph_is_configured(self
):
566 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
568 def _user_consume(self
):
569 nonlocal can_seek_beginning
570 can_seek_beginning
= self
._msg
_iter
.can_seek_beginning()
572 def _user_can_seek_beginning(self
):
573 nonlocal input_port_iter_can_seek_beginning
574 return input_port_iter_can_seek_beginning
576 graph
= _setup_seek_test(
578 user_can_seek_beginning
=_user_can_seek_beginning
,
579 user_seek_beginning
=lambda: None,
582 input_port_iter_can_seek_beginning
= True
583 can_seek_beginning
= None
585 self
.assertIs(can_seek_beginning
, True)
587 input_port_iter_can_seek_beginning
= False
588 can_seek_beginning
= None
590 self
.assertIs(can_seek_beginning
, False)
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
):
596 def __init__(self
, config
, params
, obj
):
597 self
._add
_input
_port
("in")
599 def _user_graph_is_configured(self
):
600 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
602 def _user_consume(self
):
603 nonlocal can_seek_beginning
604 can_seek_beginning
= self
._msg
_iter
.can_seek_beginning()
606 def _user_seek_beginning(self
):
609 graph
= _setup_seek_test(MySink
, user_seek_beginning
=_user_seek_beginning
)
610 can_seek_beginning
= None
612 self
.assertIs(can_seek_beginning
, True)
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
):
618 def __init__(self
, config
, params
, obj
):
619 self
._add
_input
_port
("in")
621 def _user_graph_is_configured(self
):
622 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
624 def _user_consume(self
):
625 nonlocal can_seek_beginning
626 can_seek_beginning
= self
._msg
_iter
.can_seek_beginning()
628 graph
= _setup_seek_test(MySink
)
629 can_seek_beginning
= None
631 self
.assertIs(can_seek_beginning
, False)
633 def test_can_seek_beginning_user_error(self
):
634 class MySink(bt2
._UserSinkComponent
):
635 def __init__(self
, config
, params
, obj
):
636 self
._add
_input
_port
("in")
638 def _user_graph_is_configured(self
):
639 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
641 def _user_consume(self
):
642 # This is expected to raise.
643 self
._msg
_iter
.can_seek_beginning()
645 def _user_can_seek_beginning(self
):
646 raise ValueError("moustiquaire")
648 graph
= _setup_seek_test(
650 user_can_seek_beginning
=_user_can_seek_beginning
,
651 user_seek_beginning
=lambda: None,
654 with self
.assertRaises(bt2
._Error
) as ctx
:
657 cause
= ctx
.exception
[0]
658 self
.assertIn("ValueError: moustiquaire", cause
.message
)
660 def test_can_seek_beginning_wrong_return_value(self
):
661 class MySink(bt2
._UserSinkComponent
):
662 def __init__(self
, config
, params
, obj
):
663 self
._add
_input
_port
("in")
665 def _user_graph_is_configured(self
):
666 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
668 def _user_consume(self
):
669 # This is expected to raise.
670 self
._msg
_iter
.can_seek_beginning()
672 def _user_can_seek_beginning(self
):
675 graph
= _setup_seek_test(
677 user_can_seek_beginning
=_user_can_seek_beginning
,
678 user_seek_beginning
=lambda: None,
681 with self
.assertRaises(bt2
._Error
) as ctx
:
684 cause
= ctx
.exception
[0]
685 self
.assertIn("TypeError: 'str' is not a 'bool' object", cause
.message
)
687 def test_seek_beginning(self
):
688 class MySink(bt2
._UserSinkComponent
):
689 def __init__(self
, config
, params
, obj
):
690 self
._add
_input
_port
("in")
692 def _user_graph_is_configured(self
):
693 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
695 def _user_consume(self
):
696 nonlocal do_seek_beginning
699 if do_seek_beginning
:
700 self
._msg
_iter
.seek_beginning()
703 msg
= next(self
._msg
_iter
)
705 def _user_seek_beginning(self
):
709 graph
= _setup_seek_test(MySink
, user_seek_beginning
=_user_seek_beginning
)
712 do_seek_beginning
= False
714 self
.assertIs(type(msg
), bt2
._StreamBeginningMessageConst
)
718 self
.assertIs(type(msg
), bt2
._PacketBeginningMessageConst
)
721 do_seek_beginning
= True
725 do_seek_beginning
= False
727 self
.assertIs(type(msg
), bt2
._StreamBeginningMessageConst
)
729 def test_seek_beginning_user_error(self
):
730 class MySink(bt2
._UserSinkComponent
):
731 def __init__(self
, config
, params
, obj
):
732 self
._add
_input
_port
("in")
734 def _user_graph_is_configured(self
):
735 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
737 def _user_consume(self
):
738 self
._msg
_iter
.seek_beginning()
740 def _user_seek_beginning(self
):
741 raise ValueError("ouch")
743 graph
= _setup_seek_test(MySink
, user_seek_beginning
=_user_seek_beginning
)
745 with self
.assertRaises(bt2
._Error
):
749 class UserMessageIteratorSeekNsFromOriginTestCase(unittest
.TestCase
):
750 def test_can_seek_ns_from_origin_without_seek_ns_from_origin(self
):
751 # Test the case where:
753 # - can_seek_ns_from_origin: Returns True (don't really care, as long
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",
765 self
._can
_seek
_ns
_from
_origin
_test
(
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
,
773 def test_can_seek_ns_from_origin_returns_true(self
):
774 # Test the case where:
776 # - can_seek_ns_from_origin: returns True
777 # - seek_ns_from_origin provided: Yes
778 # - can the iterator seek beginning: Don't care
779 # - can the iterator seek forward: Don't care
781 # We expect iter.can_seek_ns_from_origin to return True.
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
,
792 def test_can_seek_ns_from_origin_returns_false_can_seek_beginning_forward_seekable(
795 # Test the case where:
797 # - can_seek_ns_from_origin: returns False
798 # - seek_ns_from_origin provided: Yes
799 # - can the iterator seek beginning: Yes
800 # - can the iterator seek forward: Yes
802 # We expect iter.can_seek_ns_from_origin to return True.
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,
811 def test_can_seek_ns_from_origin_returns_false_can_seek_beginning_not_forward_seekable(
814 # Test the case where:
816 # - can_seek_ns_from_origin: returns False
817 # - seek_ns_from_origin provided: Yes
818 # - can the iterator seek beginning: Yes
819 # - can the iterator seek forward: No
821 # We expect iter.can_seek_ns_from_origin to return False.
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,
830 def test_can_seek_ns_from_origin_returns_false_cant_seek_beginning_forward_seekable(
833 # Test the case where:
835 # - can_seek_ns_from_origin: returns False
836 # - seek_ns_from_origin provided: Yes
837 # - can the iterator seek beginning: No
838 # - can the iterator seek forward: Yes
840 # We expect iter.can_seek_ns_from_origin to return False.
841 self
._can
_seek
_ns
_from
_origin
_test
(
842 expected_outcome
=False,
843 user_can_seek_ns_from_origin_ret_val
=False,
844 user_seek_ns_from_origin_provided
=True,
845 iter_can_seek_beginning
=False,
846 iter_can_seek_forward
=True,
849 def test_can_seek_ns_from_origin_returns_false_cant_seek_beginning_not_forward_seekable(
852 # Test the case where:
854 # - can_seek_ns_from_origin: returns False
855 # - seek_ns_from_origin provided: Yes
856 # - can the iterator seek beginning: No
857 # - can the iterator seek forward: No
859 # We expect iter.can_seek_ns_from_origin to return False.
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,
868 def test_no_can_seek_ns_from_origin_seek_ns_from_origin(self
):
869 # Test the case where:
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
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
,
887 def test_no_can_seek_ns_from_origin_no_seek_ns_from_origin_can_seek_beginning_forward_seekable(
890 # Test the case where:
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
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,
906 def test_no_can_seek_ns_from_origin_no_seek_ns_from_origin_can_seek_beginning_not_forward_seekable(
909 # Test the case where:
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
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,
925 def test_no_can_seek_ns_from_origin_no_seek_ns_from_origin_cant_seek_beginning_forward_seekable(
928 # Test the case where:
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
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,
944 def test_no_can_seek_ns_from_origin_no_seek_ns_from_origin_cant_seek_beginning_not_forward_seekable(
947 # Test the case where:
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
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,
963 def _can_seek_ns_from_origin_test(
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
,
971 class MySink(bt2
._UserSinkComponent
):
972 def __init__(self
, config
, params
, obj
):
973 self
._add
_input
_port
("in")
975 def _user_graph_is_configured(self
):
976 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
978 def _user_consume(self
):
979 nonlocal can_seek_ns_from_origin
980 can_seek_ns_from_origin
= self
._msg
_iter
.can_seek_ns_from_origin(
981 passed_ns_from_origin
984 if user_can_seek_ns_from_origin_ret_val
is not None:
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
992 user_can_seek_ns_from_origin
= None
994 if user_seek_ns_from_origin_provided
:
996 def user_seek_ns_from_origin(self
, ns_from_origin
):
1000 user_seek_ns_from_origin
= None
1002 if iter_can_seek_beginning
:
1004 def user_seek_beginning(self
):
1008 user_seek_beginning
= None
1010 graph
= _setup_seek_test(
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
,
1018 passed_ns_from_origin
= 77
1019 received_ns_from_origin
= None
1020 can_seek_ns_from_origin
= None
1022 self
.assertIs(can_seek_ns_from_origin
, expected_outcome
)
1024 if user_can_seek_ns_from_origin_ret_val
is not None:
1025 self
.assertEqual(received_ns_from_origin
, passed_ns_from_origin
)
1027 def test_can_seek_ns_from_origin_user_error(self
):
1028 class MySink(bt2
._UserSinkComponent
):
1029 def __init__(self
, config
, params
, obj
):
1030 self
._add
_input
_port
("in")
1032 def _user_graph_is_configured(self
):
1033 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
1035 def _user_consume(self
):
1036 # This is expected to raise.
1037 self
._msg
_iter
.can_seek_ns_from_origin(2)
1039 def _user_can_seek_ns_from_origin(self
, ns_from_origin
):
1040 raise ValueError("Joutel")
1042 graph
= _setup_seek_test(
1044 user_can_seek_ns_from_origin
=_user_can_seek_ns_from_origin
,
1045 user_seek_ns_from_origin
=lambda: None,
1048 with self
.assertRaises(bt2
._Error
) as ctx
:
1051 cause
= ctx
.exception
[0]
1052 self
.assertIn("ValueError: Joutel", cause
.message
)
1054 def test_can_seek_ns_from_origin_wrong_return_value(self
):
1055 class MySink(bt2
._UserSinkComponent
):
1056 def __init__(self
, config
, params
, obj
):
1057 self
._add
_input
_port
("in")
1059 def _user_graph_is_configured(self
):
1060 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
1062 def _user_consume(self
):
1063 # This is expected to raise.
1064 self
._msg
_iter
.can_seek_ns_from_origin(2)
1066 def _user_can_seek_ns_from_origin(self
, ns_from_origin
):
1069 graph
= _setup_seek_test(
1071 user_can_seek_ns_from_origin
=_user_can_seek_ns_from_origin
,
1072 user_seek_ns_from_origin
=lambda: None,
1075 with self
.assertRaises(bt2
._Error
) as ctx
:
1078 cause
= ctx
.exception
[0]
1079 self
.assertIn("TypeError: 'str' is not a 'bool' object", cause
.message
)
1081 def test_seek_ns_from_origin(self
):
1082 class MySink(bt2
._UserSinkComponent
):
1083 def __init__(self
, config
, params
, obj
):
1084 self
._add
_input
_port
("in")
1086 def _user_graph_is_configured(self
):
1087 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
1089 def _user_consume(self
):
1090 self
._msg
_iter
.seek_ns_from_origin(17)
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
1096 graph
= _setup_seek_test(
1097 MySink
, user_seek_ns_from_origin
=_user_seek_ns_from_origin
1100 actual_ns_from_origin
= None
1102 self
.assertEqual(actual_ns_from_origin
, 17)
1105 if __name__
== "__main__":