1 # SPDX-License-Identifier: GPL-2.0-only
3 # Copyright (C) 2019 EfficiOS Inc.
9 from utils
import TestOutputPortMessageIterator
10 from bt2
import port
as bt2_port
11 from bt2
import message_iterator
as bt2_message_iterator
14 class SimpleSink(bt2
._UserSinkComponent
):
15 # Straightforward sink that creates one input port (`in`) and consumes from
18 def __init__(self
, config
, params
, obj
):
19 self
._add
_input
_port
("in")
21 def _user_consume(self
):
24 def _user_graph_is_configured(self
):
25 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
28 def _create_graph(src_comp_cls
, sink_comp_cls
, flt_comp_cls
=None):
31 src_comp
= graph
.add_component(src_comp_cls
, "src")
32 sink_comp
= graph
.add_component(sink_comp_cls
, "sink")
34 if flt_comp_cls
is not None:
35 flt_comp
= graph
.add_component(flt_comp_cls
, "flt")
36 graph
.connect_ports(src_comp
.output_ports
["out"], flt_comp
.input_ports
["in"])
37 graph
.connect_ports(flt_comp
.output_ports
["out"], sink_comp
.input_ports
["in"])
39 graph
.connect_ports(src_comp
.output_ports
["out"], sink_comp
.input_ports
["in"])
44 class UserMessageIteratorTestCase(unittest
.TestCase
):
46 the_output_port_from_source
= None
47 the_output_port_from_iter
= None
49 class MyIter(bt2
._UserMessageIterator
):
50 def __init__(self
, config
, self_port_output
):
52 nonlocal the_output_port_from_iter
54 the_output_port_from_iter
= self_port_output
56 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
57 def __init__(self
, config
, params
, obj
):
58 nonlocal the_output_port_from_source
59 the_output_port_from_source
= self
._add
_output
_port
("out", "user data")
62 graph
= _create_graph(MySource
, SimpleSink
)
64 self
.assertTrue(initialized
)
66 the_output_port_from_source
.addr
, the_output_port_from_iter
.addr
68 self
.assertEqual(the_output_port_from_iter
.user_data
, "user data")
70 def test_create_from_message_iterator(self
):
71 class MySourceIter(bt2
._UserMessageIterator
):
72 def __init__(self
, config
, self_port_output
):
73 nonlocal src_iter_initialized
74 src_iter_initialized
= True
76 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MySourceIter
):
77 def __init__(self
, config
, params
, obj
):
78 self
._add
_output
_port
("out")
80 class MyFilterIter(bt2
._UserMessageIterator
):
81 def __init__(self
, config
, self_port_output
):
82 nonlocal flt_iter_initialized
83 flt_iter_initialized
= True
84 self
._up
_iter
= self
._create
_message
_iterator
(
85 self
._component
._input
_ports
["in"]
89 return next(self
._up
_iter
)
91 class MyFilter(bt2
._UserFilterComponent
, message_iterator_class
=MyFilterIter
):
92 def __init__(self
, config
, params
, obj
):
93 self
._add
_input
_port
("in")
94 self
._add
_output
_port
("out")
96 src_iter_initialized
= False
97 flt_iter_initialized
= False
98 graph
= _create_graph(MySource
, SimpleSink
, MyFilter
)
100 self
.assertTrue(src_iter_initialized
)
101 self
.assertTrue(flt_iter_initialized
)
103 # Test that creating a message iterator from a sink component on a
104 # non-connected inport port raises.
105 def test_create_from_sink_component_unconnected_port_raises(self
):
106 class MySink(bt2
._UserSinkComponent
):
107 def __init__(comp_self
, config
, params
, obj
):
108 comp_self
._input
_port
= comp_self
._add
_input
_port
("in")
110 def _user_graph_is_configured(comp_self
):
111 with self
.assertRaisesRegex(ValueError, "input port is not connected"):
112 comp_self
._create
_message
_iterator
(comp_self
._input
_port
)
117 def _user_consume(self
):
122 graph
.add_component(MySink
, "snk")
124 self
.assertTrue(seen
)
126 # Test that creating a message iterator from a message iteartor on a
127 # non-connected inport port raises.
128 def test_create_from_message_iterator_unconnected_port_raises(self
):
129 class MyFilterIter(bt2
._UserMessageIterator
):
130 def __init__(iter_self
, config
, port
):
131 input_port
= iter_self
._component
._input
_ports
["in"]
133 with self
.assertRaisesRegex(ValueError, "input port is not connected"):
134 iter_self
._create
_message
_iterator
(input_port
)
139 class MyFilter(bt2
._UserFilterComponent
, message_iterator_class
=MyFilterIter
):
140 def __init__(comp_self
, config
, params
, obj
):
141 comp_self
._add
_input
_port
("in")
142 comp_self
._add
_output
_port
("out")
144 class MySink(bt2
._UserSinkComponent
):
145 def __init__(comp_self
, config
, params
, obj
):
146 comp_self
._input
_port
= comp_self
._add
_input
_port
("in")
148 def _user_graph_is_configured(comp_self
):
149 comp_self
._input
_iter
= comp_self
._create
_message
_iterator
(
150 comp_self
._input
_port
153 def _user_consume(self
):
158 flt
= graph
.add_component(MyFilter
, "flt")
159 snk
= graph
.add_component(MySink
, "snk")
160 graph
.connect_ports(flt
.output_ports
["out"], snk
.input_ports
["in"])
162 self
.assertTrue(seen
)
164 def test_create_user_error(self
):
165 # This tests both error handling by
166 # _UserSinkComponent._create_message_iterator
167 # and _UserMessageIterator._create_message_iterator, as they
168 # are both used in the graph.
169 class MySourceIter(bt2
._UserMessageIterator
):
170 def __init__(self
, config
, self_port_output
):
171 raise ValueError("Very bad error")
173 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MySourceIter
):
174 def __init__(self
, config
, params
, obj
):
175 self
._add
_output
_port
("out")
177 class MyFilterIter(bt2
._UserMessageIterator
):
178 def __init__(self
, config
, self_port_output
):
179 # This is expected to raise because of the error in
180 # MySourceIter.__init__.
181 self
._create
_message
_iterator
(self
._component
._input
_ports
["in"])
183 class MyFilter(bt2
._UserFilterComponent
, message_iterator_class
=MyFilterIter
):
184 def __init__(self
, config
, params
, obj
):
185 self
._add
_input
_port
("in")
186 self
._add
_output
_port
("out")
188 graph
= _create_graph(MySource
, SimpleSink
, MyFilter
)
190 with self
.assertRaises(bt2
._Error
) as ctx
:
196 self
.assertIsInstance(cause
, bt2
._MessageIteratorErrorCause
)
197 self
.assertEqual(cause
.component_name
, "src")
198 self
.assertEqual(cause
.component_output_port_name
, "out")
199 self
.assertIn("ValueError: Very bad error", cause
.message
)
201 def test_finalize(self
):
202 class MyIter(bt2
._UserMessageIterator
):
203 def _user_finalize(self
):
207 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
208 def __init__(self
, config
, params
, obj
):
209 self
._add
_output
_port
("out")
212 graph
= _create_graph(MySource
, SimpleSink
)
215 self
.assertTrue(finalized
)
217 def test_config_parameter(self
):
218 class MyIter(bt2
._UserMessageIterator
):
219 def __init__(self
, config
, port
):
221 config_type
= type(config
)
223 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
224 def __init__(self
, config
, params
, obj
):
225 self
._add
_output
_port
("out")
228 graph
= _create_graph(MySource
, SimpleSink
)
230 self
.assertIs(config_type
, bt2_message_iterator
._MessageIteratorConfiguration
)
232 def _test_config_can_seek_forward(self
, set_can_seek_forward
):
233 class MyIter(bt2
._UserMessageIterator
):
234 def __init__(self
, config
, port
):
235 if set_can_seek_forward
:
236 config
.can_seek_forward
= True
238 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
239 def __init__(self
, config
, params
, obj
):
240 self
._add
_output
_port
("out")
242 class MySink(bt2
._UserSinkComponent
):
243 def __init__(self
, config
, params
, obj
):
244 self
._add
_input
_port
("in")
246 def _user_graph_is_configured(self
):
247 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
249 def _user_consume(self
):
250 nonlocal can_seek_forward
251 can_seek_forward
= self
._msg
_iter
.can_seek_forward
253 can_seek_forward
= None
254 graph
= _create_graph(MySource
, MySink
)
256 self
.assertIs(can_seek_forward
, set_can_seek_forward
)
258 def test_config_can_seek_forward_default(self
):
259 self
._test
_config
_can
_seek
_forward
(False)
261 def test_config_can_seek_forward(self
):
262 self
._test
_config
_can
_seek
_forward
(True)
264 def test_config_can_seek_forward_wrong_type(self
):
265 class MyIter(bt2
._UserMessageIterator
):
266 def __init__(self
, config
, port
):
267 config
.can_seek_forward
= 1
269 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
270 def __init__(self
, config
, params
, obj
):
271 self
._add
_output
_port
("out")
273 graph
= _create_graph(MySource
, SimpleSink
)
274 with self
.assertRaises(bt2
._Error
) as ctx
:
277 root_cause
= ctx
.exception
[0]
278 self
.assertIn("TypeError: 'int' is not a 'bool' object", root_cause
.message
)
280 def test_component(self
):
281 class MyIter(bt2
._UserMessageIterator
):
282 def __init__(self
, config
, self_port_output
):
284 salut
= self
._component
._salut
286 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
287 def __init__(self
, config
, params
, obj
):
288 self
._add
_output
_port
("out")
292 graph
= _create_graph(MySource
, SimpleSink
)
294 self
.assertEqual(salut
, 23)
297 class MyIter(bt2
._UserMessageIterator
):
298 def __init__(self_iter
, config
, self_port_output
):
301 port
= self_iter
._port
302 self
.assertIs(type(self_port_output
), bt2_port
._UserComponentOutputPort
)
303 self
.assertIs(type(port
), bt2_port
._UserComponentOutputPort
)
304 self
.assertEqual(self_port_output
.addr
, port
.addr
)
306 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
307 def __init__(self
, config
, params
, obj
):
308 self
._add
_output
_port
("out")
311 graph
= _create_graph(MySource
, SimpleSink
)
313 self
.assertTrue(called
)
316 class MyIter(bt2
._UserMessageIterator
):
317 def __init__(self
, config
, self_port_output
):
321 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
322 def __init__(self
, config
, params
, obj
):
323 self
._add
_output
_port
("out")
326 graph
= _create_graph(MySource
, SimpleSink
)
328 self
.assertIsNotNone(addr
)
329 self
.assertNotEqual(addr
, 0)
331 # Test that messages returned by _UserMessageIterator.__next__ remain valid
332 # and can be re-used.
333 def test_reuse_message(self
):
334 class MyIter(bt2
._UserMessageIterator
):
335 def __init__(self
, config
, port
):
336 tc
, sc
, ec
= port
.user_data
338 stream
= trace
.create_stream(sc
)
339 packet
= stream
.create_packet()
341 # This message will be returned twice by __next__.
342 event_message
= self
._create
_event
_message
(ec
, packet
)
345 self
._create
_stream
_beginning
_message
(stream
),
346 self
._create
_packet
_beginning
_message
(packet
),
352 return self
._msgs
.pop(0)
354 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
355 def __init__(self
, config
, params
, obj
):
356 tc
= self
._create
_trace
_class
()
357 sc
= tc
.create_stream_class(supports_packets
=True)
358 ec
= sc
.create_event_class()
359 self
._add
_output
_port
("out", (tc
, sc
, ec
))
362 src
= graph
.add_component(MySource
, "src")
363 it
= TestOutputPortMessageIterator(graph
, src
.output_ports
["out"])
365 # Skip beginning messages.
367 self
.assertIs(type(msg
), bt2
._StreamBeginningMessageConst
)
369 self
.assertIs(type(msg
), bt2
._PacketBeginningMessageConst
)
374 self
.assertIs(type(msg_ev1
), bt2
._EventMessageConst
)
375 self
.assertIs(type(msg_ev2
), bt2
._EventMessageConst
)
376 self
.assertEqual(msg_ev1
.addr
, msg_ev2
.addr
)
378 # Try consuming many times from an iterator that always returns TryAgain.
379 # This verifies that we are not missing an incref of Py_None, making the
380 # refcount of Py_None reach 0.
381 def test_try_again_many_times(self
):
382 class MyIter(bt2
._UserMessageIterator
):
386 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
387 def __init__(self
, config
, params
, obj
):
388 self
._add
_output
_port
("out")
390 class MyFilterIter(bt2
._UserMessageIterator
):
391 def __init__(self
, port
):
392 input_port
= port
.user_data
393 self
._upstream
_iter
= self
._create
_message
_iterator
(input_port
)
396 return next(self
._upstream
_iter
)
398 def _user_seek_beginning(self
):
399 self
._upstream
_iter
.seek_beginning()
401 def _user_can_seek_beginning(self
):
402 return self
._upstream
_iter
.can_seek_beginning()
404 class MyFilter(bt2
._UserFilterComponent
, message_iterator_class
=MyFilterIter
):
405 def __init__(self
, config
, params
, obj
):
406 input_port
= self
._add
_input
_port
("in")
407 self
._add
_output
_port
("out", input_port
)
410 src
= graph
.add_component(MySource
, "src")
411 it
= TestOutputPortMessageIterator(graph
, src
.output_ports
["out"])
413 # Three times the initial ref count of `None` iterations should
414 # be enough to catch the bug even if there are small differences
415 # between configurations.
416 none_ref_count
= sys
.getrefcount(None) * 3
418 for i
in range(none_ref_count
):
419 with self
.assertRaises(bt2
.TryAgain
):
422 def test_error_in_iterator_with_cycle_after_having_created_upstream_iterator(self
):
423 # Test a failure that triggered an abort in libbabeltrace2, in this situation:
425 # - The filter iterator creates an upstream iterator.
426 # - The filter iterator creates a reference cycle, including itself.
427 # - An exception is raised, causing the filter iterator's
428 # initialization method to fail.
429 class MySourceIter(bt2
._UserMessageIterator
):
432 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MySourceIter
):
433 def __init__(self
, config
, params
, obj
):
434 self
._add
_output
_port
("out")
436 class MyFilterIter(bt2
._UserMessageIterator
):
437 def __init__(self
, config
, port
):
438 # First, create an upstream iterator.
439 self
._upstream
_iter
= self
._create
_message
_iterator
(
440 self
._component
._input
_ports
["in"]
443 # Then, voluntarily make a reference cycle that will keep this
444 # Python object alive, which will keep the upstream iterator
445 # Babeltrace object alive.
448 # Finally, raise an exception to make __init__ fail.
449 raise ValueError("woops")
451 class MyFilter(bt2
._UserFilterComponent
, message_iterator_class
=MyFilterIter
):
452 def __init__(self
, config
, params
, obj
):
453 self
._in
= self
._add
_input
_port
("in")
454 self
._out
= self
._add
_output
_port
("out")
456 class MySink(bt2
._UserSinkComponent
):
457 def __init__(self
, config
, params
, obj
):
458 self
._input
_port
= self
._add
_input
_port
("in")
460 def _user_graph_is_configured(self
):
461 self
._upstream
_iter
= self
._create
_message
_iterator
(self
._input
_port
)
463 def _user_consume(self
):
464 # We should not reach this.
468 src
= g
.add_component(MySource
, "src")
469 flt
= g
.add_component(MyFilter
, "flt")
470 snk
= g
.add_component(MySink
, "snk")
471 g
.connect_ports(src
.output_ports
["out"], flt
.input_ports
["in"])
472 g
.connect_ports(flt
.output_ports
["out"], snk
.input_ports
["in"])
474 with self
.assertRaisesRegex(bt2
._Error
, "ValueError: woops"):
478 def _setup_seek_test(
480 user_seek_beginning
=None,
481 user_can_seek_beginning
=None,
482 user_seek_ns_from_origin
=None,
483 user_can_seek_ns_from_origin
=None,
484 can_seek_forward
=False,
486 class MySourceIter(bt2
._UserMessageIterator
):
487 def __init__(self
, config
, port
):
488 tc
, sc
, ec
= port
.user_data
490 stream
= trace
.create_stream(sc
)
491 packet
= stream
.create_packet()
494 self
._create
_stream
_beginning
_message
(stream
),
495 self
._create
_packet
_beginning
_message
(packet
),
496 self
._create
_event
_message
(ec
, packet
),
497 self
._create
_event
_message
(ec
, packet
),
498 self
._create
_packet
_end
_message
(packet
),
499 self
._create
_stream
_end
_message
(stream
),
502 config
.can_seek_forward
= can_seek_forward
505 if self
._at
< len(self
._msgs
):
506 msg
= self
._msgs
[self
._at
]
512 if user_seek_beginning
is not None:
513 MySourceIter
._user
_seek
_beginning
= user_seek_beginning
515 if user_can_seek_beginning
is not None:
516 MySourceIter
._user
_can
_seek
_beginning
= user_can_seek_beginning
518 if user_seek_ns_from_origin
is not None:
519 MySourceIter
._user
_seek
_ns
_from
_origin
= user_seek_ns_from_origin
521 if user_can_seek_ns_from_origin
is not None:
522 MySourceIter
._user
_can
_seek
_ns
_from
_origin
= user_can_seek_ns_from_origin
524 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MySourceIter
):
525 def __init__(self
, config
, params
, obj
):
526 tc
= self
._create
_trace
_class
()
527 sc
= tc
.create_stream_class(supports_packets
=True)
528 ec
= sc
.create_event_class()
530 self
._add
_output
_port
("out", (tc
, sc
, ec
))
532 class MyFilterIter(bt2
._UserMessageIterator
):
533 def __init__(self
, config
, port
):
534 self
._upstream
_iter
= self
._create
_message
_iterator
(
535 self
._component
._input
_ports
["in"]
537 config
.can_seek_forward
= self
._upstream
_iter
.can_seek_forward
540 return next(self
._upstream
_iter
)
542 def _user_can_seek_beginning(self
):
543 return self
._upstream
_iter
.can_seek_beginning()
545 def _user_seek_beginning(self
):
546 self
._upstream
_iter
.seek_beginning()
548 def _user_can_seek_ns_from_origin(self
, ns_from_origin
):
549 return self
._upstream
_iter
.can_seek_ns_from_origin(ns_from_origin
)
551 def _user_seek_ns_from_origin(self
, ns_from_origin
):
552 self
._upstream
_iter
.seek_ns_from_origin(ns_from_origin
)
554 class MyFilter(bt2
._UserFilterComponent
, message_iterator_class
=MyFilterIter
):
555 def __init__(self
, config
, params
, obj
):
556 self
._add
_input
_port
("in")
557 self
._add
_output
_port
("out")
559 return _create_graph(MySource
, sink_cls
, flt_comp_cls
=MyFilter
)
562 class UserMessageIteratorSeekBeginningTestCase(unittest
.TestCase
):
563 def test_can_seek_beginning_without_seek_beginning(self
):
564 with self
.assertRaisesRegex(
565 bt2
._IncompleteUserClass
,
566 "cannot create component class 'MySource': message iterator class implements _user_can_seek_beginning but not _user_seek_beginning",
568 _setup_seek_test(SimpleSink
, user_can_seek_beginning
=lambda: None)
570 def test_can_seek_beginning(self
):
571 class MySink(bt2
._UserSinkComponent
):
572 def __init__(self
, config
, params
, obj
):
573 self
._add
_input
_port
("in")
575 def _user_graph_is_configured(self
):
576 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
578 def _user_consume(self
):
579 nonlocal can_seek_beginning
580 can_seek_beginning
= self
._msg
_iter
.can_seek_beginning()
582 def _user_can_seek_beginning(self
):
583 nonlocal input_port_iter_can_seek_beginning
584 return input_port_iter_can_seek_beginning
586 graph
= _setup_seek_test(
588 user_can_seek_beginning
=_user_can_seek_beginning
,
589 user_seek_beginning
=lambda: None,
592 input_port_iter_can_seek_beginning
= True
593 can_seek_beginning
= None
595 self
.assertIs(can_seek_beginning
, True)
597 input_port_iter_can_seek_beginning
= False
598 can_seek_beginning
= None
600 self
.assertIs(can_seek_beginning
, False)
602 def test_no_can_seek_beginning_with_seek_beginning(self
):
603 # Test an iterator without a _user_can_seek_beginning method, but with
604 # a _user_seek_beginning method.
605 class MySink(bt2
._UserSinkComponent
):
606 def __init__(self
, config
, params
, obj
):
607 self
._add
_input
_port
("in")
609 def _user_graph_is_configured(self
):
610 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
612 def _user_consume(self
):
613 nonlocal can_seek_beginning
614 can_seek_beginning
= self
._msg
_iter
.can_seek_beginning()
616 def _user_seek_beginning(self
):
619 graph
= _setup_seek_test(MySink
, user_seek_beginning
=_user_seek_beginning
)
620 can_seek_beginning
= None
622 self
.assertIs(can_seek_beginning
, True)
624 def test_no_can_seek_beginning(self
):
625 # Test an iterator without a _user_can_seek_beginning method, without
626 # a _user_seek_beginning method.
627 class MySink(bt2
._UserSinkComponent
):
628 def __init__(self
, config
, params
, obj
):
629 self
._add
_input
_port
("in")
631 def _user_graph_is_configured(self
):
632 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
634 def _user_consume(self
):
635 nonlocal can_seek_beginning
636 can_seek_beginning
= self
._msg
_iter
.can_seek_beginning()
638 graph
= _setup_seek_test(MySink
)
639 can_seek_beginning
= None
641 self
.assertIs(can_seek_beginning
, False)
643 def test_can_seek_beginning_user_error(self
):
644 class MySink(bt2
._UserSinkComponent
):
645 def __init__(self
, config
, params
, obj
):
646 self
._add
_input
_port
("in")
648 def _user_graph_is_configured(self
):
649 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
651 def _user_consume(self
):
652 # This is expected to raise.
653 self
._msg
_iter
.can_seek_beginning()
655 def _user_can_seek_beginning(self
):
656 raise ValueError("moustiquaire")
658 graph
= _setup_seek_test(
660 user_can_seek_beginning
=_user_can_seek_beginning
,
661 user_seek_beginning
=lambda: None,
664 with self
.assertRaises(bt2
._Error
) as ctx
:
667 cause
= ctx
.exception
[0]
668 self
.assertIn("ValueError: moustiquaire", cause
.message
)
670 def test_can_seek_beginning_wrong_return_value(self
):
671 class MySink(bt2
._UserSinkComponent
):
672 def __init__(self
, config
, params
, obj
):
673 self
._add
_input
_port
("in")
675 def _user_graph_is_configured(self
):
676 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
678 def _user_consume(self
):
679 # This is expected to raise.
680 self
._msg
_iter
.can_seek_beginning()
682 def _user_can_seek_beginning(self
):
685 graph
= _setup_seek_test(
687 user_can_seek_beginning
=_user_can_seek_beginning
,
688 user_seek_beginning
=lambda: None,
691 with self
.assertRaises(bt2
._Error
) as ctx
:
694 cause
= ctx
.exception
[0]
695 self
.assertIn("TypeError: 'str' is not a 'bool' object", cause
.message
)
697 def test_seek_beginning(self
):
698 class MySink(bt2
._UserSinkComponent
):
699 def __init__(self
, config
, params
, obj
):
700 self
._add
_input
_port
("in")
702 def _user_graph_is_configured(self
):
703 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
705 def _user_consume(self
):
706 nonlocal do_seek_beginning
709 if do_seek_beginning
:
710 self
._msg
_iter
.seek_beginning()
713 msg
= next(self
._msg
_iter
)
715 def _user_seek_beginning(self
):
719 graph
= _setup_seek_test(MySink
, user_seek_beginning
=_user_seek_beginning
)
722 do_seek_beginning
= False
724 self
.assertIs(type(msg
), bt2
._StreamBeginningMessageConst
)
728 self
.assertIs(type(msg
), bt2
._PacketBeginningMessageConst
)
731 do_seek_beginning
= True
735 do_seek_beginning
= False
737 self
.assertIs(type(msg
), bt2
._StreamBeginningMessageConst
)
739 def test_seek_beginning_user_error(self
):
740 class MySink(bt2
._UserSinkComponent
):
741 def __init__(self
, config
, params
, obj
):
742 self
._add
_input
_port
("in")
744 def _user_graph_is_configured(self
):
745 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
747 def _user_consume(self
):
748 self
._msg
_iter
.seek_beginning()
750 def _user_seek_beginning(self
):
751 raise ValueError("ouch")
753 graph
= _setup_seek_test(MySink
, user_seek_beginning
=_user_seek_beginning
)
755 with self
.assertRaises(bt2
._Error
):
759 class UserMessageIteratorSeekNsFromOriginTestCase(unittest
.TestCase
):
760 def test_can_seek_ns_from_origin_without_seek_ns_from_origin(self
):
761 # Test the case where:
763 # - can_seek_ns_from_origin: Returns True (don't really care, as long
765 # - seek_ns_from_origin provided: No
766 # - can the iterator seek beginning: Don't care
767 # - can the iterator seek forward: Don't care
768 for can_seek_ns_from_origin
in (False, True):
769 for iter_can_seek_beginning
in (False, True):
770 for iter_can_seek_forward
in (False, True):
771 with self
.assertRaisesRegex(
772 bt2
._IncompleteUserClass
,
773 "cannot create component class 'MySource': message iterator class implements _user_can_seek_ns_from_origin but not _user_seek_ns_from_origin",
775 self
._can
_seek
_ns
_from
_origin
_test
(
777 user_can_seek_ns_from_origin_ret_val
=True,
778 user_seek_ns_from_origin_provided
=False,
779 iter_can_seek_beginning
=iter_can_seek_beginning
,
780 iter_can_seek_forward
=iter_can_seek_forward
,
783 def test_can_seek_ns_from_origin_returns_true(self
):
784 # Test the case where:
786 # - can_seek_ns_from_origin: returns True
787 # - seek_ns_from_origin provided: Yes
788 # - can the iterator seek beginning: Don't care
789 # - can the iterator seek forward: Don't care
791 # We expect iter.can_seek_ns_from_origin to return True.
792 for iter_can_seek_beginning
in (False, True):
793 for iter_can_seek_forward
in (False, True):
794 self
._can
_seek
_ns
_from
_origin
_test
(
795 expected_outcome
=True,
796 user_can_seek_ns_from_origin_ret_val
=True,
797 user_seek_ns_from_origin_provided
=True,
798 iter_can_seek_beginning
=iter_can_seek_beginning
,
799 iter_can_seek_forward
=iter_can_seek_forward
,
802 def test_can_seek_ns_from_origin_returns_false_can_seek_beginning_forward_seekable(
805 # Test the case where:
807 # - can_seek_ns_from_origin: returns False
808 # - seek_ns_from_origin provided: Yes
809 # - can the iterator seek beginning: Yes
810 # - can the iterator seek forward: Yes
812 # We expect iter.can_seek_ns_from_origin to return True.
813 self
._can
_seek
_ns
_from
_origin
_test
(
814 expected_outcome
=True,
815 user_can_seek_ns_from_origin_ret_val
=False,
816 user_seek_ns_from_origin_provided
=True,
817 iter_can_seek_beginning
=True,
818 iter_can_seek_forward
=True,
821 def test_can_seek_ns_from_origin_returns_false_can_seek_beginning_not_forward_seekable(
824 # Test the case where:
826 # - can_seek_ns_from_origin: returns False
827 # - seek_ns_from_origin provided: Yes
828 # - can the iterator seek beginning: Yes
829 # - can the iterator seek forward: No
831 # We expect iter.can_seek_ns_from_origin to return False.
832 self
._can
_seek
_ns
_from
_origin
_test
(
833 expected_outcome
=False,
834 user_can_seek_ns_from_origin_ret_val
=False,
835 user_seek_ns_from_origin_provided
=True,
836 iter_can_seek_beginning
=True,
837 iter_can_seek_forward
=False,
840 def test_can_seek_ns_from_origin_returns_false_cant_seek_beginning_forward_seekable(
843 # Test the case where:
845 # - can_seek_ns_from_origin: returns False
846 # - seek_ns_from_origin provided: Yes
847 # - can the iterator seek beginning: No
848 # - can the iterator seek forward: Yes
850 # We expect iter.can_seek_ns_from_origin to return False.
851 self
._can
_seek
_ns
_from
_origin
_test
(
852 expected_outcome
=False,
853 user_can_seek_ns_from_origin_ret_val
=False,
854 user_seek_ns_from_origin_provided
=True,
855 iter_can_seek_beginning
=False,
856 iter_can_seek_forward
=True,
859 def test_can_seek_ns_from_origin_returns_false_cant_seek_beginning_not_forward_seekable(
862 # Test the case where:
864 # - can_seek_ns_from_origin: returns False
865 # - seek_ns_from_origin provided: Yes
866 # - can the iterator seek beginning: No
867 # - can the iterator seek forward: No
869 # We expect iter.can_seek_ns_from_origin to return False.
870 self
._can
_seek
_ns
_from
_origin
_test
(
871 expected_outcome
=False,
872 user_can_seek_ns_from_origin_ret_val
=False,
873 user_seek_ns_from_origin_provided
=True,
874 iter_can_seek_beginning
=False,
875 iter_can_seek_forward
=False,
878 def test_no_can_seek_ns_from_origin_seek_ns_from_origin(self
):
879 # Test the case where:
881 # - can_seek_ns_from_origin: Not provided
882 # - seek_ns_from_origin provided: Yes
883 # - can the iterator seek beginning: Don't care
884 # - can the iterator seek forward: Don't care
886 # We expect iter.can_seek_ns_from_origin to return True.
887 for iter_can_seek_beginning
in (False, True):
888 for iter_can_seek_forward
in (False, True):
889 self
._can
_seek
_ns
_from
_origin
_test
(
890 expected_outcome
=True,
891 user_can_seek_ns_from_origin_ret_val
=None,
892 user_seek_ns_from_origin_provided
=True,
893 iter_can_seek_beginning
=iter_can_seek_beginning
,
894 iter_can_seek_forward
=iter_can_seek_forward
,
897 def test_no_can_seek_ns_from_origin_no_seek_ns_from_origin_can_seek_beginning_forward_seekable(
900 # Test the case where:
902 # - can_seek_ns_from_origin: Not provided
903 # - seek_ns_from_origin provided: Not provided
904 # - can the iterator seek beginning: Yes
905 # - can the iterator seek forward: Yes
907 # We expect iter.can_seek_ns_from_origin to return True.
908 self
._can
_seek
_ns
_from
_origin
_test
(
909 expected_outcome
=True,
910 user_can_seek_ns_from_origin_ret_val
=None,
911 user_seek_ns_from_origin_provided
=False,
912 iter_can_seek_beginning
=True,
913 iter_can_seek_forward
=True,
916 def test_no_can_seek_ns_from_origin_no_seek_ns_from_origin_can_seek_beginning_not_forward_seekable(
919 # Test the case where:
921 # - can_seek_ns_from_origin: Not provided
922 # - seek_ns_from_origin provided: Not provided
923 # - can the iterator seek beginning: Yes
924 # - can the iterator seek forward: No
926 # We expect iter.can_seek_ns_from_origin to return False.
927 self
._can
_seek
_ns
_from
_origin
_test
(
928 expected_outcome
=False,
929 user_can_seek_ns_from_origin_ret_val
=None,
930 user_seek_ns_from_origin_provided
=False,
931 iter_can_seek_beginning
=True,
932 iter_can_seek_forward
=False,
935 def test_no_can_seek_ns_from_origin_no_seek_ns_from_origin_cant_seek_beginning_forward_seekable(
938 # Test the case where:
940 # - can_seek_ns_from_origin: Not provided
941 # - seek_ns_from_origin provided: Not provided
942 # - can the iterator seek beginning: No
943 # - can the iterator seek forward: Yes
945 # We expect iter.can_seek_ns_from_origin to return False.
946 self
._can
_seek
_ns
_from
_origin
_test
(
947 expected_outcome
=False,
948 user_can_seek_ns_from_origin_ret_val
=None,
949 user_seek_ns_from_origin_provided
=False,
950 iter_can_seek_beginning
=False,
951 iter_can_seek_forward
=True,
954 def test_no_can_seek_ns_from_origin_no_seek_ns_from_origin_cant_seek_beginning_not_forward_seekable(
957 # Test the case where:
959 # - can_seek_ns_from_origin: Not provided
960 # - seek_ns_from_origin provided: Not provided
961 # - can the iterator seek beginning: No
962 # - can the iterator seek forward: No
964 # We expect iter.can_seek_ns_from_origin to return False.
965 self
._can
_seek
_ns
_from
_origin
_test
(
966 expected_outcome
=False,
967 user_can_seek_ns_from_origin_ret_val
=None,
968 user_seek_ns_from_origin_provided
=False,
969 iter_can_seek_beginning
=False,
970 iter_can_seek_forward
=False,
973 def _can_seek_ns_from_origin_test(
976 user_can_seek_ns_from_origin_ret_val
,
977 user_seek_ns_from_origin_provided
,
978 iter_can_seek_beginning
,
979 iter_can_seek_forward
,
981 class MySink(bt2
._UserSinkComponent
):
982 def __init__(self
, config
, params
, obj
):
983 self
._add
_input
_port
("in")
985 def _user_graph_is_configured(self
):
986 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
988 def _user_consume(self
):
989 nonlocal can_seek_ns_from_origin
990 can_seek_ns_from_origin
= self
._msg
_iter
.can_seek_ns_from_origin(
991 passed_ns_from_origin
994 if user_can_seek_ns_from_origin_ret_val
is not None:
996 def user_can_seek_ns_from_origin(self
, ns_from_origin
):
997 nonlocal received_ns_from_origin
998 received_ns_from_origin
= ns_from_origin
999 return user_can_seek_ns_from_origin_ret_val
1002 user_can_seek_ns_from_origin
= None
1004 if user_seek_ns_from_origin_provided
:
1006 def user_seek_ns_from_origin(self
, ns_from_origin
):
1010 user_seek_ns_from_origin
= None
1012 if iter_can_seek_beginning
:
1014 def user_seek_beginning(self
):
1018 user_seek_beginning
= None
1020 graph
= _setup_seek_test(
1022 user_can_seek_ns_from_origin
=user_can_seek_ns_from_origin
,
1023 user_seek_ns_from_origin
=user_seek_ns_from_origin
,
1024 user_seek_beginning
=user_seek_beginning
,
1025 can_seek_forward
=iter_can_seek_forward
,
1028 passed_ns_from_origin
= 77
1029 received_ns_from_origin
= None
1030 can_seek_ns_from_origin
= None
1032 self
.assertIs(can_seek_ns_from_origin
, expected_outcome
)
1034 if user_can_seek_ns_from_origin_ret_val
is not None:
1035 self
.assertEqual(received_ns_from_origin
, passed_ns_from_origin
)
1037 def test_can_seek_ns_from_origin_user_error(self
):
1038 class MySink(bt2
._UserSinkComponent
):
1039 def __init__(self
, config
, params
, obj
):
1040 self
._add
_input
_port
("in")
1042 def _user_graph_is_configured(self
):
1043 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
1045 def _user_consume(self
):
1046 # This is expected to raise.
1047 self
._msg
_iter
.can_seek_ns_from_origin(2)
1049 def _user_can_seek_ns_from_origin(self
, ns_from_origin
):
1050 raise ValueError("Joutel")
1052 graph
= _setup_seek_test(
1054 user_can_seek_ns_from_origin
=_user_can_seek_ns_from_origin
,
1055 user_seek_ns_from_origin
=lambda: None,
1058 with self
.assertRaises(bt2
._Error
) as ctx
:
1061 cause
= ctx
.exception
[0]
1062 self
.assertIn("ValueError: Joutel", cause
.message
)
1064 def test_can_seek_ns_from_origin_wrong_return_value(self
):
1065 class MySink(bt2
._UserSinkComponent
):
1066 def __init__(self
, config
, params
, obj
):
1067 self
._add
_input
_port
("in")
1069 def _user_graph_is_configured(self
):
1070 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
1072 def _user_consume(self
):
1073 # This is expected to raise.
1074 self
._msg
_iter
.can_seek_ns_from_origin(2)
1076 def _user_can_seek_ns_from_origin(self
, ns_from_origin
):
1079 graph
= _setup_seek_test(
1081 user_can_seek_ns_from_origin
=_user_can_seek_ns_from_origin
,
1082 user_seek_ns_from_origin
=lambda: None,
1085 with self
.assertRaises(bt2
._Error
) as ctx
:
1088 cause
= ctx
.exception
[0]
1089 self
.assertIn("TypeError: 'str' is not a 'bool' object", cause
.message
)
1091 def test_seek_ns_from_origin(self
):
1092 class MySink(bt2
._UserSinkComponent
):
1093 def __init__(self
, config
, params
, obj
):
1094 self
._add
_input
_port
("in")
1096 def _user_graph_is_configured(self
):
1097 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
1099 def _user_consume(self
):
1100 self
._msg
_iter
.seek_ns_from_origin(17)
1102 def _user_seek_ns_from_origin(self
, ns_from_origin
):
1103 nonlocal actual_ns_from_origin
1104 actual_ns_from_origin
= ns_from_origin
1106 graph
= _setup_seek_test(
1107 MySink
, user_seek_ns_from_origin
=_user_seek_ns_from_origin
1110 actual_ns_from_origin
= None
1112 self
.assertEqual(actual_ns_from_origin
, 17)
1115 if __name__
== "__main__":