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 inport 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 iteartor on a
128 # non-connected inport 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 class MyIter(bt2
._UserMessageIterator
):
387 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
388 def __init__(self
, config
, params
, obj
):
389 self
._add
_output
_port
("out")
391 class MyFilterIter(bt2
._UserMessageIterator
):
392 def __init__(self
, port
):
393 input_port
= port
.user_data
394 self
._upstream
_iter
= self
._create
_message
_iterator
(input_port
)
397 return next(self
._upstream
_iter
)
399 def _user_seek_beginning(self
):
400 self
._upstream
_iter
.seek_beginning()
402 def _user_can_seek_beginning(self
):
403 return self
._upstream
_iter
.can_seek_beginning()
405 class MyFilter(bt2
._UserFilterComponent
, message_iterator_class
=MyFilterIter
):
406 def __init__(self
, config
, params
, obj
):
407 input_port
= self
._add
_input
_port
("in")
408 self
._add
_output
_port
("out", input_port
)
411 src
= graph
.add_component(MySource
, "src")
412 it
= TestOutputPortMessageIterator(graph
, src
.output_ports
["out"])
414 # Three times the initial ref count of `None` iterations should
415 # be enough to catch the bug even if there are small differences
416 # between configurations.
417 none_ref_count
= sys
.getrefcount(None) * 3
419 for i
in range(none_ref_count
):
420 with self
.assertRaises(bt2
.TryAgain
):
423 def test_error_in_iterator_with_cycle_after_having_created_upstream_iterator(self
):
424 # Test a failure that triggered an abort in libbabeltrace2, in this situation:
426 # - The filter iterator creates an upstream iterator.
427 # - The filter iterator creates a reference cycle, including itself.
428 # - An exception is raised, causing the filter iterator's
429 # initialization method to fail.
430 class MySourceIter(bt2
._UserMessageIterator
):
433 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MySourceIter
):
434 def __init__(self
, config
, params
, obj
):
435 self
._add
_output
_port
("out")
437 class MyFilterIter(bt2
._UserMessageIterator
):
438 def __init__(self
, config
, port
):
439 # First, create an upstream iterator.
440 self
._upstream
_iter
= self
._create
_message
_iterator
(
441 self
._component
._input
_ports
["in"]
444 # Then, voluntarily make a reference cycle that will keep this
445 # Python object alive, which will keep the upstream iterator
446 # Babeltrace object alive.
449 # Finally, raise an exception to make __init__ fail.
450 raise ValueError("woops")
452 class MyFilter(bt2
._UserFilterComponent
, message_iterator_class
=MyFilterIter
):
453 def __init__(self
, config
, params
, obj
):
454 self
._in
= self
._add
_input
_port
("in")
455 self
._out
= self
._add
_output
_port
("out")
457 class MySink(bt2
._UserSinkComponent
):
458 def __init__(self
, config
, params
, obj
):
459 self
._input
_port
= self
._add
_input
_port
("in")
461 def _user_graph_is_configured(self
):
462 self
._upstream
_iter
= self
._create
_message
_iterator
(self
._input
_port
)
464 def _user_consume(self
):
465 # We should not reach this.
469 src
= g
.add_component(MySource
, "src")
470 flt
= g
.add_component(MyFilter
, "flt")
471 snk
= g
.add_component(MySink
, "snk")
472 g
.connect_ports(src
.output_ports
["out"], flt
.input_ports
["in"])
473 g
.connect_ports(flt
.output_ports
["out"], snk
.input_ports
["in"])
475 with self
.assertRaisesRegex(bt2
._Error
, "ValueError: woops"):
479 def _setup_seek_test(
481 user_seek_beginning
=None,
482 user_can_seek_beginning
=None,
483 user_seek_ns_from_origin
=None,
484 user_can_seek_ns_from_origin
=None,
485 can_seek_forward
=False,
487 class MySourceIter(bt2
._UserMessageIterator
):
488 def __init__(self
, config
, port
):
489 tc
, sc
, ec
= port
.user_data
491 stream
= trace
.create_stream(sc
)
492 packet
= stream
.create_packet()
495 self
._create
_stream
_beginning
_message
(stream
),
496 self
._create
_packet
_beginning
_message
(packet
),
497 self
._create
_event
_message
(ec
, packet
),
498 self
._create
_event
_message
(ec
, packet
),
499 self
._create
_packet
_end
_message
(packet
),
500 self
._create
_stream
_end
_message
(stream
),
503 config
.can_seek_forward
= can_seek_forward
506 if self
._at
< len(self
._msgs
):
507 msg
= self
._msgs
[self
._at
]
513 if user_seek_beginning
is not None:
514 MySourceIter
._user
_seek
_beginning
= user_seek_beginning
516 if user_can_seek_beginning
is not None:
517 MySourceIter
._user
_can
_seek
_beginning
= user_can_seek_beginning
519 if user_seek_ns_from_origin
is not None:
520 MySourceIter
._user
_seek
_ns
_from
_origin
= user_seek_ns_from_origin
522 if user_can_seek_ns_from_origin
is not None:
523 MySourceIter
._user
_can
_seek
_ns
_from
_origin
= user_can_seek_ns_from_origin
525 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MySourceIter
):
526 def __init__(self
, config
, params
, obj
):
527 tc
= self
._create
_trace
_class
()
528 sc
= tc
.create_stream_class(supports_packets
=True)
529 ec
= sc
.create_event_class()
531 self
._add
_output
_port
("out", (tc
, sc
, ec
))
533 class MyFilterIter(bt2
._UserMessageIterator
):
534 def __init__(self
, config
, port
):
535 self
._upstream
_iter
= self
._create
_message
_iterator
(
536 self
._component
._input
_ports
["in"]
538 config
.can_seek_forward
= self
._upstream
_iter
.can_seek_forward
541 return next(self
._upstream
_iter
)
543 def _user_can_seek_beginning(self
):
544 return self
._upstream
_iter
.can_seek_beginning()
546 def _user_seek_beginning(self
):
547 self
._upstream
_iter
.seek_beginning()
549 def _user_can_seek_ns_from_origin(self
, ns_from_origin
):
550 return self
._upstream
_iter
.can_seek_ns_from_origin(ns_from_origin
)
552 def _user_seek_ns_from_origin(self
, ns_from_origin
):
553 self
._upstream
_iter
.seek_ns_from_origin(ns_from_origin
)
555 class MyFilter(bt2
._UserFilterComponent
, message_iterator_class
=MyFilterIter
):
556 def __init__(self
, config
, params
, obj
):
557 self
._add
_input
_port
("in")
558 self
._add
_output
_port
("out")
560 return _create_graph(MySource
, sink_cls
, flt_comp_cls
=MyFilter
)
563 class UserMessageIteratorSeekBeginningTestCase(unittest
.TestCase
):
564 def test_can_seek_beginning_without_seek_beginning(self
):
565 with self
.assertRaisesRegex(
566 bt2
._IncompleteUserClass
,
567 "cannot create component class 'MySource': message iterator class implements _user_can_seek_beginning but not _user_seek_beginning",
569 _setup_seek_test(SimpleSink
, user_can_seek_beginning
=lambda: None)
571 def test_can_seek_beginning(self
):
572 class MySink(bt2
._UserSinkComponent
):
573 def __init__(self
, config
, params
, obj
):
574 self
._add
_input
_port
("in")
576 def _user_graph_is_configured(self
):
577 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
579 def _user_consume(self
):
580 nonlocal can_seek_beginning
581 can_seek_beginning
= self
._msg
_iter
.can_seek_beginning()
583 def _user_can_seek_beginning(self
):
584 nonlocal input_port_iter_can_seek_beginning
585 return input_port_iter_can_seek_beginning
587 graph
= _setup_seek_test(
589 user_can_seek_beginning
=_user_can_seek_beginning
,
590 user_seek_beginning
=lambda: None,
593 input_port_iter_can_seek_beginning
= True
594 can_seek_beginning
= None
596 self
.assertIs(can_seek_beginning
, True)
598 input_port_iter_can_seek_beginning
= False
599 can_seek_beginning
= None
601 self
.assertIs(can_seek_beginning
, False)
603 def test_no_can_seek_beginning_with_seek_beginning(self
):
604 # Test an iterator without a _user_can_seek_beginning method, but with
605 # a _user_seek_beginning method.
606 class MySink(bt2
._UserSinkComponent
):
607 def __init__(self
, config
, params
, obj
):
608 self
._add
_input
_port
("in")
610 def _user_graph_is_configured(self
):
611 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
613 def _user_consume(self
):
614 nonlocal can_seek_beginning
615 can_seek_beginning
= self
._msg
_iter
.can_seek_beginning()
617 def _user_seek_beginning(self
):
620 graph
= _setup_seek_test(MySink
, user_seek_beginning
=_user_seek_beginning
)
621 can_seek_beginning
= None
623 self
.assertIs(can_seek_beginning
, True)
625 def test_no_can_seek_beginning(self
):
626 # Test an iterator without a _user_can_seek_beginning method, without
627 # a _user_seek_beginning method.
628 class MySink(bt2
._UserSinkComponent
):
629 def __init__(self
, config
, params
, obj
):
630 self
._add
_input
_port
("in")
632 def _user_graph_is_configured(self
):
633 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
635 def _user_consume(self
):
636 nonlocal can_seek_beginning
637 can_seek_beginning
= self
._msg
_iter
.can_seek_beginning()
639 graph
= _setup_seek_test(MySink
)
640 can_seek_beginning
= None
642 self
.assertIs(can_seek_beginning
, False)
644 def test_can_seek_beginning_user_error(self
):
645 class MySink(bt2
._UserSinkComponent
):
646 def __init__(self
, config
, params
, obj
):
647 self
._add
_input
_port
("in")
649 def _user_graph_is_configured(self
):
650 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
652 def _user_consume(self
):
653 # This is expected to raise.
654 self
._msg
_iter
.can_seek_beginning()
656 def _user_can_seek_beginning(self
):
657 raise ValueError("moustiquaire")
659 graph
= _setup_seek_test(
661 user_can_seek_beginning
=_user_can_seek_beginning
,
662 user_seek_beginning
=lambda: None,
665 with self
.assertRaises(bt2
._Error
) as ctx
:
668 cause
= ctx
.exception
[0]
669 self
.assertIn("ValueError: moustiquaire", cause
.message
)
671 def test_can_seek_beginning_wrong_return_value(self
):
672 class MySink(bt2
._UserSinkComponent
):
673 def __init__(self
, config
, params
, obj
):
674 self
._add
_input
_port
("in")
676 def _user_graph_is_configured(self
):
677 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
679 def _user_consume(self
):
680 # This is expected to raise.
681 self
._msg
_iter
.can_seek_beginning()
683 def _user_can_seek_beginning(self
):
686 graph
= _setup_seek_test(
688 user_can_seek_beginning
=_user_can_seek_beginning
,
689 user_seek_beginning
=lambda: None,
692 with self
.assertRaises(bt2
._Error
) as ctx
:
695 cause
= ctx
.exception
[0]
696 self
.assertIn("TypeError: 'str' is not a 'bool' object", cause
.message
)
698 def test_seek_beginning(self
):
699 class MySink(bt2
._UserSinkComponent
):
700 def __init__(self
, config
, params
, obj
):
701 self
._add
_input
_port
("in")
703 def _user_graph_is_configured(self
):
704 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
706 def _user_consume(self
):
707 nonlocal do_seek_beginning
710 if do_seek_beginning
:
711 self
._msg
_iter
.seek_beginning()
714 msg
= next(self
._msg
_iter
)
716 def _user_seek_beginning(self
):
720 graph
= _setup_seek_test(MySink
, user_seek_beginning
=_user_seek_beginning
)
723 do_seek_beginning
= False
725 self
.assertIs(type(msg
), bt2
._StreamBeginningMessageConst
)
729 self
.assertIs(type(msg
), bt2
._PacketBeginningMessageConst
)
732 do_seek_beginning
= True
736 do_seek_beginning
= False
738 self
.assertIs(type(msg
), bt2
._StreamBeginningMessageConst
)
740 def test_seek_beginning_user_error(self
):
741 class MySink(bt2
._UserSinkComponent
):
742 def __init__(self
, config
, params
, obj
):
743 self
._add
_input
_port
("in")
745 def _user_graph_is_configured(self
):
746 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
748 def _user_consume(self
):
749 self
._msg
_iter
.seek_beginning()
751 def _user_seek_beginning(self
):
752 raise ValueError("ouch")
754 graph
= _setup_seek_test(MySink
, user_seek_beginning
=_user_seek_beginning
)
756 with self
.assertRaises(bt2
._Error
):
760 class UserMessageIteratorSeekNsFromOriginTestCase(unittest
.TestCase
):
761 def test_can_seek_ns_from_origin_without_seek_ns_from_origin(self
):
762 # Test the case where:
764 # - can_seek_ns_from_origin: Returns True (don't really care, as long
766 # - seek_ns_from_origin provided: No
767 # - can the iterator seek beginning: Don't care
768 # - can the iterator seek forward: Don't care
769 for can_seek_ns_from_origin
in (False, True):
770 for iter_can_seek_beginning
in (False, True):
771 for iter_can_seek_forward
in (False, True):
772 with self
.assertRaisesRegex(
773 bt2
._IncompleteUserClass
,
774 "cannot create component class 'MySource': message iterator class implements _user_can_seek_ns_from_origin but not _user_seek_ns_from_origin",
776 self
._can
_seek
_ns
_from
_origin
_test
(
778 user_can_seek_ns_from_origin_ret_val
=True,
779 user_seek_ns_from_origin_provided
=False,
780 iter_can_seek_beginning
=iter_can_seek_beginning
,
781 iter_can_seek_forward
=iter_can_seek_forward
,
784 def test_can_seek_ns_from_origin_returns_true(self
):
785 # Test the case where:
787 # - can_seek_ns_from_origin: returns True
788 # - seek_ns_from_origin provided: Yes
789 # - can the iterator seek beginning: Don't care
790 # - can the iterator seek forward: Don't care
792 # We expect iter.can_seek_ns_from_origin to return True.
793 for iter_can_seek_beginning
in (False, True):
794 for iter_can_seek_forward
in (False, True):
795 self
._can
_seek
_ns
_from
_origin
_test
(
796 expected_outcome
=True,
797 user_can_seek_ns_from_origin_ret_val
=True,
798 user_seek_ns_from_origin_provided
=True,
799 iter_can_seek_beginning
=iter_can_seek_beginning
,
800 iter_can_seek_forward
=iter_can_seek_forward
,
803 def test_can_seek_ns_from_origin_returns_false_can_seek_beginning_forward_seekable(
806 # Test the case where:
808 # - can_seek_ns_from_origin: returns False
809 # - seek_ns_from_origin provided: Yes
810 # - can the iterator seek beginning: Yes
811 # - can the iterator seek forward: Yes
813 # We expect iter.can_seek_ns_from_origin to return True.
814 self
._can
_seek
_ns
_from
_origin
_test
(
815 expected_outcome
=True,
816 user_can_seek_ns_from_origin_ret_val
=False,
817 user_seek_ns_from_origin_provided
=True,
818 iter_can_seek_beginning
=True,
819 iter_can_seek_forward
=True,
822 def test_can_seek_ns_from_origin_returns_false_can_seek_beginning_not_forward_seekable(
825 # Test the case where:
827 # - can_seek_ns_from_origin: returns False
828 # - seek_ns_from_origin provided: Yes
829 # - can the iterator seek beginning: Yes
830 # - can the iterator seek forward: No
832 # We expect iter.can_seek_ns_from_origin to return False.
833 self
._can
_seek
_ns
_from
_origin
_test
(
834 expected_outcome
=False,
835 user_can_seek_ns_from_origin_ret_val
=False,
836 user_seek_ns_from_origin_provided
=True,
837 iter_can_seek_beginning
=True,
838 iter_can_seek_forward
=False,
841 def test_can_seek_ns_from_origin_returns_false_cant_seek_beginning_forward_seekable(
844 # Test the case where:
846 # - can_seek_ns_from_origin: returns False
847 # - seek_ns_from_origin provided: Yes
848 # - can the iterator seek beginning: No
849 # - can the iterator seek forward: Yes
851 # We expect iter.can_seek_ns_from_origin to return False.
852 self
._can
_seek
_ns
_from
_origin
_test
(
853 expected_outcome
=False,
854 user_can_seek_ns_from_origin_ret_val
=False,
855 user_seek_ns_from_origin_provided
=True,
856 iter_can_seek_beginning
=False,
857 iter_can_seek_forward
=True,
860 def test_can_seek_ns_from_origin_returns_false_cant_seek_beginning_not_forward_seekable(
863 # Test the case where:
865 # - can_seek_ns_from_origin: returns False
866 # - seek_ns_from_origin provided: Yes
867 # - can the iterator seek beginning: No
868 # - can the iterator seek forward: No
870 # We expect iter.can_seek_ns_from_origin to return False.
871 self
._can
_seek
_ns
_from
_origin
_test
(
872 expected_outcome
=False,
873 user_can_seek_ns_from_origin_ret_val
=False,
874 user_seek_ns_from_origin_provided
=True,
875 iter_can_seek_beginning
=False,
876 iter_can_seek_forward
=False,
879 def test_no_can_seek_ns_from_origin_seek_ns_from_origin(self
):
880 # Test the case where:
882 # - can_seek_ns_from_origin: Not provided
883 # - seek_ns_from_origin provided: Yes
884 # - can the iterator seek beginning: Don't care
885 # - can the iterator seek forward: Don't care
887 # We expect iter.can_seek_ns_from_origin to return True.
888 for iter_can_seek_beginning
in (False, True):
889 for iter_can_seek_forward
in (False, True):
890 self
._can
_seek
_ns
_from
_origin
_test
(
891 expected_outcome
=True,
892 user_can_seek_ns_from_origin_ret_val
=None,
893 user_seek_ns_from_origin_provided
=True,
894 iter_can_seek_beginning
=iter_can_seek_beginning
,
895 iter_can_seek_forward
=iter_can_seek_forward
,
898 def test_no_can_seek_ns_from_origin_no_seek_ns_from_origin_can_seek_beginning_forward_seekable(
901 # Test the case where:
903 # - can_seek_ns_from_origin: Not provided
904 # - seek_ns_from_origin provided: Not provided
905 # - can the iterator seek beginning: Yes
906 # - can the iterator seek forward: Yes
908 # We expect iter.can_seek_ns_from_origin to return True.
909 self
._can
_seek
_ns
_from
_origin
_test
(
910 expected_outcome
=True,
911 user_can_seek_ns_from_origin_ret_val
=None,
912 user_seek_ns_from_origin_provided
=False,
913 iter_can_seek_beginning
=True,
914 iter_can_seek_forward
=True,
917 def test_no_can_seek_ns_from_origin_no_seek_ns_from_origin_can_seek_beginning_not_forward_seekable(
920 # Test the case where:
922 # - can_seek_ns_from_origin: Not provided
923 # - seek_ns_from_origin provided: Not provided
924 # - can the iterator seek beginning: Yes
925 # - can the iterator seek forward: No
927 # We expect iter.can_seek_ns_from_origin to return False.
928 self
._can
_seek
_ns
_from
_origin
_test
(
929 expected_outcome
=False,
930 user_can_seek_ns_from_origin_ret_val
=None,
931 user_seek_ns_from_origin_provided
=False,
932 iter_can_seek_beginning
=True,
933 iter_can_seek_forward
=False,
936 def test_no_can_seek_ns_from_origin_no_seek_ns_from_origin_cant_seek_beginning_forward_seekable(
939 # Test the case where:
941 # - can_seek_ns_from_origin: Not provided
942 # - seek_ns_from_origin provided: Not provided
943 # - can the iterator seek beginning: No
944 # - can the iterator seek forward: Yes
946 # We expect iter.can_seek_ns_from_origin to return False.
947 self
._can
_seek
_ns
_from
_origin
_test
(
948 expected_outcome
=False,
949 user_can_seek_ns_from_origin_ret_val
=None,
950 user_seek_ns_from_origin_provided
=False,
951 iter_can_seek_beginning
=False,
952 iter_can_seek_forward
=True,
955 def test_no_can_seek_ns_from_origin_no_seek_ns_from_origin_cant_seek_beginning_not_forward_seekable(
958 # Test the case where:
960 # - can_seek_ns_from_origin: Not provided
961 # - seek_ns_from_origin provided: Not provided
962 # - can the iterator seek beginning: No
963 # - can the iterator seek forward: No
965 # We expect iter.can_seek_ns_from_origin to return False.
966 self
._can
_seek
_ns
_from
_origin
_test
(
967 expected_outcome
=False,
968 user_can_seek_ns_from_origin_ret_val
=None,
969 user_seek_ns_from_origin_provided
=False,
970 iter_can_seek_beginning
=False,
971 iter_can_seek_forward
=False,
974 def _can_seek_ns_from_origin_test(
977 user_can_seek_ns_from_origin_ret_val
,
978 user_seek_ns_from_origin_provided
,
979 iter_can_seek_beginning
,
980 iter_can_seek_forward
,
982 class MySink(bt2
._UserSinkComponent
):
983 def __init__(self
, config
, params
, obj
):
984 self
._add
_input
_port
("in")
986 def _user_graph_is_configured(self
):
987 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
989 def _user_consume(self
):
990 nonlocal can_seek_ns_from_origin
991 can_seek_ns_from_origin
= self
._msg
_iter
.can_seek_ns_from_origin(
992 passed_ns_from_origin
995 if user_can_seek_ns_from_origin_ret_val
is not None:
997 def user_can_seek_ns_from_origin(self
, ns_from_origin
):
998 nonlocal received_ns_from_origin
999 received_ns_from_origin
= ns_from_origin
1000 return user_can_seek_ns_from_origin_ret_val
1003 user_can_seek_ns_from_origin
= None
1005 if user_seek_ns_from_origin_provided
:
1007 def user_seek_ns_from_origin(self
, ns_from_origin
):
1011 user_seek_ns_from_origin
= None
1013 if iter_can_seek_beginning
:
1015 def user_seek_beginning(self
):
1019 user_seek_beginning
= None
1021 graph
= _setup_seek_test(
1023 user_can_seek_ns_from_origin
=user_can_seek_ns_from_origin
,
1024 user_seek_ns_from_origin
=user_seek_ns_from_origin
,
1025 user_seek_beginning
=user_seek_beginning
,
1026 can_seek_forward
=iter_can_seek_forward
,
1029 passed_ns_from_origin
= 77
1030 received_ns_from_origin
= None
1031 can_seek_ns_from_origin
= None
1033 self
.assertIs(can_seek_ns_from_origin
, expected_outcome
)
1035 if user_can_seek_ns_from_origin_ret_val
is not None:
1036 self
.assertEqual(received_ns_from_origin
, passed_ns_from_origin
)
1038 def test_can_seek_ns_from_origin_user_error(self
):
1039 class MySink(bt2
._UserSinkComponent
):
1040 def __init__(self
, config
, params
, obj
):
1041 self
._add
_input
_port
("in")
1043 def _user_graph_is_configured(self
):
1044 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
1046 def _user_consume(self
):
1047 # This is expected to raise.
1048 self
._msg
_iter
.can_seek_ns_from_origin(2)
1050 def _user_can_seek_ns_from_origin(self
, ns_from_origin
):
1051 raise ValueError("Joutel")
1053 graph
= _setup_seek_test(
1055 user_can_seek_ns_from_origin
=_user_can_seek_ns_from_origin
,
1056 user_seek_ns_from_origin
=lambda: None,
1059 with self
.assertRaises(bt2
._Error
) as ctx
:
1062 cause
= ctx
.exception
[0]
1063 self
.assertIn("ValueError: Joutel", cause
.message
)
1065 def test_can_seek_ns_from_origin_wrong_return_value(self
):
1066 class MySink(bt2
._UserSinkComponent
):
1067 def __init__(self
, config
, params
, obj
):
1068 self
._add
_input
_port
("in")
1070 def _user_graph_is_configured(self
):
1071 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
1073 def _user_consume(self
):
1074 # This is expected to raise.
1075 self
._msg
_iter
.can_seek_ns_from_origin(2)
1077 def _user_can_seek_ns_from_origin(self
, ns_from_origin
):
1080 graph
= _setup_seek_test(
1082 user_can_seek_ns_from_origin
=_user_can_seek_ns_from_origin
,
1083 user_seek_ns_from_origin
=lambda: None,
1086 with self
.assertRaises(bt2
._Error
) as ctx
:
1089 cause
= ctx
.exception
[0]
1090 self
.assertIn("TypeError: 'str' is not a 'bool' object", cause
.message
)
1092 def test_seek_ns_from_origin(self
):
1093 class MySink(bt2
._UserSinkComponent
):
1094 def __init__(self
, config
, params
, obj
):
1095 self
._add
_input
_port
("in")
1097 def _user_graph_is_configured(self
):
1098 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
1100 def _user_consume(self
):
1101 self
._msg
_iter
.seek_ns_from_origin(17)
1103 def _user_seek_ns_from_origin(self
, ns_from_origin
):
1104 nonlocal actual_ns_from_origin
1105 actual_ns_from_origin
= ns_from_origin
1107 graph
= _setup_seek_test(
1108 MySink
, user_seek_ns_from_origin
=_user_seek_ns_from_origin
1111 actual_ns_from_origin
= None
1113 self
.assertEqual(actual_ns_from_origin
, 17)
1116 if __name__
== "__main__":