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")
392 src
= graph
.add_component(MySource
, "src")
393 it
= TestOutputPortMessageIterator(graph
, src
.output_ports
["out"])
395 # Three times the initial ref count of `None` iterations should
396 # be enough to catch the bug even if there are small differences
397 # between configurations.
398 none_ref_count
= sys
.getrefcount(None) * 3
400 for i
in range(none_ref_count
):
401 with self
.assertRaises(bt2
.TryAgain
):
404 def test_error_in_iterator_with_cycle_after_having_created_upstream_iterator(self
):
405 # Test a failure that triggered an abort in libbabeltrace2, in this situation:
407 # - The filter iterator creates an upstream iterator.
408 # - The filter iterator creates a reference cycle, including itself.
409 # - An exception is raised, causing the filter iterator's
410 # initialization method to fail.
411 class MySourceIter(bt2
._UserMessageIterator
):
414 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MySourceIter
):
415 def __init__(self
, config
, params
, obj
):
416 self
._add
_output
_port
("out")
418 class MyFilterIter(bt2
._UserMessageIterator
):
419 def __init__(self
, config
, port
):
420 # First, create an upstream iterator.
421 self
._upstream
_iter
= self
._create
_message
_iterator
(
422 self
._component
._input
_ports
["in"]
425 # Then, voluntarily make a reference cycle that will keep this
426 # Python object alive, which will keep the upstream iterator
427 # Babeltrace object alive.
430 # Finally, raise an exception to make __init__ fail.
431 raise ValueError("woops")
433 class MyFilter(bt2
._UserFilterComponent
, message_iterator_class
=MyFilterIter
):
434 def __init__(self
, config
, params
, obj
):
435 self
._in
= self
._add
_input
_port
("in")
436 self
._out
= self
._add
_output
_port
("out")
438 class MySink(bt2
._UserSinkComponent
):
439 def __init__(self
, config
, params
, obj
):
440 self
._input
_port
= self
._add
_input
_port
("in")
442 def _user_graph_is_configured(self
):
443 self
._upstream
_iter
= self
._create
_message
_iterator
(self
._input
_port
)
445 def _user_consume(self
):
446 # We should not reach this.
450 src
= g
.add_component(MySource
, "src")
451 flt
= g
.add_component(MyFilter
, "flt")
452 snk
= g
.add_component(MySink
, "snk")
453 g
.connect_ports(src
.output_ports
["out"], flt
.input_ports
["in"])
454 g
.connect_ports(flt
.output_ports
["out"], snk
.input_ports
["in"])
456 with self
.assertRaisesRegex(bt2
._Error
, "ValueError: woops"):
460 def _setup_seek_test(
462 user_seek_beginning
=None,
463 user_can_seek_beginning
=None,
464 user_seek_ns_from_origin
=None,
465 user_can_seek_ns_from_origin
=None,
466 can_seek_forward
=False,
468 class MySourceIter(bt2
._UserMessageIterator
):
469 def __init__(self
, config
, port
):
470 tc
, sc
, ec
= port
.user_data
472 stream
= trace
.create_stream(sc
)
473 packet
= stream
.create_packet()
476 self
._create
_stream
_beginning
_message
(stream
),
477 self
._create
_packet
_beginning
_message
(packet
),
478 self
._create
_event
_message
(ec
, packet
),
479 self
._create
_event
_message
(ec
, packet
),
480 self
._create
_packet
_end
_message
(packet
),
481 self
._create
_stream
_end
_message
(stream
),
484 config
.can_seek_forward
= can_seek_forward
487 if self
._at
< len(self
._msgs
):
488 msg
= self
._msgs
[self
._at
]
494 if user_seek_beginning
is not None:
495 MySourceIter
._user
_seek
_beginning
= user_seek_beginning
497 if user_can_seek_beginning
is not None:
498 MySourceIter
._user
_can
_seek
_beginning
= user_can_seek_beginning
500 if user_seek_ns_from_origin
is not None:
501 MySourceIter
._user
_seek
_ns
_from
_origin
= user_seek_ns_from_origin
503 if user_can_seek_ns_from_origin
is not None:
504 MySourceIter
._user
_can
_seek
_ns
_from
_origin
= user_can_seek_ns_from_origin
506 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MySourceIter
):
507 def __init__(self
, config
, params
, obj
):
508 tc
= self
._create
_trace
_class
()
509 sc
= tc
.create_stream_class(supports_packets
=True)
510 ec
= sc
.create_event_class()
512 self
._add
_output
_port
("out", (tc
, sc
, ec
))
514 class MyFilterIter(bt2
._UserMessageIterator
):
515 def __init__(self
, config
, port
):
516 self
._upstream
_iter
= self
._create
_message
_iterator
(
517 self
._component
._input
_ports
["in"]
519 config
.can_seek_forward
= self
._upstream
_iter
.can_seek_forward
522 return next(self
._upstream
_iter
)
524 def _user_can_seek_beginning(self
):
525 return self
._upstream
_iter
.can_seek_beginning()
527 def _user_seek_beginning(self
):
528 self
._upstream
_iter
.seek_beginning()
530 def _user_can_seek_ns_from_origin(self
, ns_from_origin
):
531 return self
._upstream
_iter
.can_seek_ns_from_origin(ns_from_origin
)
533 def _user_seek_ns_from_origin(self
, ns_from_origin
):
534 self
._upstream
_iter
.seek_ns_from_origin(ns_from_origin
)
536 class MyFilter(bt2
._UserFilterComponent
, message_iterator_class
=MyFilterIter
):
537 def __init__(self
, config
, params
, obj
):
538 self
._add
_input
_port
("in")
539 self
._add
_output
_port
("out")
541 return _create_graph(MySource
, sink_cls
, flt_comp_cls
=MyFilter
)
544 class UserMessageIteratorSeekBeginningTestCase(unittest
.TestCase
):
545 def test_can_seek_beginning_without_seek_beginning(self
):
546 with self
.assertRaisesRegex(
547 bt2
._IncompleteUserClass
,
548 "cannot create component class 'MySource': message iterator class implements _user_can_seek_beginning but not _user_seek_beginning",
550 _setup_seek_test(SimpleSink
, user_can_seek_beginning
=lambda: None)
552 def test_can_seek_beginning(self
):
553 class MySink(bt2
._UserSinkComponent
):
554 def __init__(self
, config
, params
, obj
):
555 self
._add
_input
_port
("in")
557 def _user_graph_is_configured(self
):
558 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
560 def _user_consume(self
):
561 nonlocal can_seek_beginning
562 can_seek_beginning
= self
._msg
_iter
.can_seek_beginning()
564 def _user_can_seek_beginning(self
):
565 nonlocal input_port_iter_can_seek_beginning
566 return input_port_iter_can_seek_beginning
568 graph
= _setup_seek_test(
570 user_can_seek_beginning
=_user_can_seek_beginning
,
571 user_seek_beginning
=lambda: None,
574 input_port_iter_can_seek_beginning
= True
575 can_seek_beginning
= None
577 self
.assertIs(can_seek_beginning
, True)
579 input_port_iter_can_seek_beginning
= False
580 can_seek_beginning
= None
582 self
.assertIs(can_seek_beginning
, False)
584 def test_no_can_seek_beginning_with_seek_beginning(self
):
585 # Test an iterator without a _user_can_seek_beginning method, but with
586 # a _user_seek_beginning method.
587 class MySink(bt2
._UserSinkComponent
):
588 def __init__(self
, config
, params
, obj
):
589 self
._add
_input
_port
("in")
591 def _user_graph_is_configured(self
):
592 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
594 def _user_consume(self
):
595 nonlocal can_seek_beginning
596 can_seek_beginning
= self
._msg
_iter
.can_seek_beginning()
598 def _user_seek_beginning(self
):
601 graph
= _setup_seek_test(MySink
, user_seek_beginning
=_user_seek_beginning
)
602 can_seek_beginning
= None
604 self
.assertIs(can_seek_beginning
, True)
606 def test_no_can_seek_beginning(self
):
607 # Test an iterator without a _user_can_seek_beginning method, without
608 # a _user_seek_beginning method.
609 class MySink(bt2
._UserSinkComponent
):
610 def __init__(self
, config
, params
, obj
):
611 self
._add
_input
_port
("in")
613 def _user_graph_is_configured(self
):
614 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
616 def _user_consume(self
):
617 nonlocal can_seek_beginning
618 can_seek_beginning
= self
._msg
_iter
.can_seek_beginning()
620 graph
= _setup_seek_test(MySink
)
621 can_seek_beginning
= None
623 self
.assertIs(can_seek_beginning
, False)
625 def test_can_seek_beginning_user_error(self
):
626 class MySink(bt2
._UserSinkComponent
):
627 def __init__(self
, config
, params
, obj
):
628 self
._add
_input
_port
("in")
630 def _user_graph_is_configured(self
):
631 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
633 def _user_consume(self
):
634 # This is expected to raise.
635 self
._msg
_iter
.can_seek_beginning()
637 def _user_can_seek_beginning(self
):
638 raise ValueError("moustiquaire")
640 graph
= _setup_seek_test(
642 user_can_seek_beginning
=_user_can_seek_beginning
,
643 user_seek_beginning
=lambda: None,
646 with self
.assertRaises(bt2
._Error
) as ctx
:
649 cause
= ctx
.exception
[0]
650 self
.assertIn("ValueError: moustiquaire", cause
.message
)
652 def test_can_seek_beginning_wrong_return_value(self
):
653 class MySink(bt2
._UserSinkComponent
):
654 def __init__(self
, config
, params
, obj
):
655 self
._add
_input
_port
("in")
657 def _user_graph_is_configured(self
):
658 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
660 def _user_consume(self
):
661 # This is expected to raise.
662 self
._msg
_iter
.can_seek_beginning()
664 def _user_can_seek_beginning(self
):
667 graph
= _setup_seek_test(
669 user_can_seek_beginning
=_user_can_seek_beginning
,
670 user_seek_beginning
=lambda: None,
673 with self
.assertRaises(bt2
._Error
) as ctx
:
676 cause
= ctx
.exception
[0]
677 self
.assertIn("TypeError: 'str' is not a 'bool' object", cause
.message
)
679 def test_seek_beginning(self
):
680 class MySink(bt2
._UserSinkComponent
):
681 def __init__(self
, config
, params
, obj
):
682 self
._add
_input
_port
("in")
684 def _user_graph_is_configured(self
):
685 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
687 def _user_consume(self
):
688 nonlocal do_seek_beginning
691 if do_seek_beginning
:
692 self
._msg
_iter
.seek_beginning()
695 msg
= next(self
._msg
_iter
)
697 def _user_seek_beginning(self
):
701 graph
= _setup_seek_test(MySink
, user_seek_beginning
=_user_seek_beginning
)
704 do_seek_beginning
= False
706 self
.assertIs(type(msg
), bt2
._StreamBeginningMessageConst
)
710 self
.assertIs(type(msg
), bt2
._PacketBeginningMessageConst
)
713 do_seek_beginning
= True
717 do_seek_beginning
= False
719 self
.assertIs(type(msg
), bt2
._StreamBeginningMessageConst
)
721 def test_seek_beginning_user_error(self
):
722 class MySink(bt2
._UserSinkComponent
):
723 def __init__(self
, config
, params
, obj
):
724 self
._add
_input
_port
("in")
726 def _user_graph_is_configured(self
):
727 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
729 def _user_consume(self
):
730 self
._msg
_iter
.seek_beginning()
732 def _user_seek_beginning(self
):
733 raise ValueError("ouch")
735 graph
= _setup_seek_test(MySink
, user_seek_beginning
=_user_seek_beginning
)
737 with self
.assertRaises(bt2
._Error
):
741 class UserMessageIteratorSeekNsFromOriginTestCase(unittest
.TestCase
):
742 def test_can_seek_ns_from_origin_without_seek_ns_from_origin(self
):
743 # Test the case where:
745 # - can_seek_ns_from_origin: Returns True (don't really care, as long
747 # - seek_ns_from_origin provided: No
748 # - can the iterator seek beginning: Don't care
749 # - can the iterator seek forward: Don't care
750 for can_seek_ns_from_origin
in (False, True):
751 for iter_can_seek_beginning
in (False, True):
752 for iter_can_seek_forward
in (False, True):
753 with self
.assertRaisesRegex(
754 bt2
._IncompleteUserClass
,
755 "cannot create component class 'MySource': message iterator class implements _user_can_seek_ns_from_origin but not _user_seek_ns_from_origin",
757 self
._can
_seek
_ns
_from
_origin
_test
(
759 user_can_seek_ns_from_origin_ret_val
=True,
760 user_seek_ns_from_origin_provided
=False,
761 iter_can_seek_beginning
=iter_can_seek_beginning
,
762 iter_can_seek_forward
=iter_can_seek_forward
,
765 def test_can_seek_ns_from_origin_returns_true(self
):
766 # Test the case where:
768 # - can_seek_ns_from_origin: returns True
769 # - seek_ns_from_origin provided: Yes
770 # - can the iterator seek beginning: Don't care
771 # - can the iterator seek forward: Don't care
773 # We expect iter.can_seek_ns_from_origin to return True.
774 for iter_can_seek_beginning
in (False, True):
775 for iter_can_seek_forward
in (False, True):
776 self
._can
_seek
_ns
_from
_origin
_test
(
777 expected_outcome
=True,
778 user_can_seek_ns_from_origin_ret_val
=True,
779 user_seek_ns_from_origin_provided
=True,
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_false_can_seek_beginning_forward_seekable(
787 # Test the case where:
789 # - can_seek_ns_from_origin: returns False
790 # - seek_ns_from_origin provided: Yes
791 # - can the iterator seek beginning: Yes
792 # - can the iterator seek forward: Yes
794 # We expect iter.can_seek_ns_from_origin to return True.
795 self
._can
_seek
_ns
_from
_origin
_test
(
796 expected_outcome
=True,
797 user_can_seek_ns_from_origin_ret_val
=False,
798 user_seek_ns_from_origin_provided
=True,
799 iter_can_seek_beginning
=True,
800 iter_can_seek_forward
=True,
803 def test_can_seek_ns_from_origin_returns_false_can_seek_beginning_not_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: No
813 # We expect iter.can_seek_ns_from_origin to return False.
814 self
._can
_seek
_ns
_from
_origin
_test
(
815 expected_outcome
=False,
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
=False,
822 def test_can_seek_ns_from_origin_returns_false_cant_seek_beginning_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: No
830 # - can the iterator seek forward: Yes
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
=False,
838 iter_can_seek_forward
=True,
841 def test_can_seek_ns_from_origin_returns_false_cant_seek_beginning_not_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: No
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
=False,
860 def test_no_can_seek_ns_from_origin_seek_ns_from_origin(self
):
861 # Test the case where:
863 # - can_seek_ns_from_origin: Not provided
864 # - seek_ns_from_origin provided: Yes
865 # - can the iterator seek beginning: Don't care
866 # - can the iterator seek forward: Don't care
868 # We expect iter.can_seek_ns_from_origin to return True.
869 for iter_can_seek_beginning
in (False, True):
870 for iter_can_seek_forward
in (False, True):
871 self
._can
_seek
_ns
_from
_origin
_test
(
872 expected_outcome
=True,
873 user_can_seek_ns_from_origin_ret_val
=None,
874 user_seek_ns_from_origin_provided
=True,
875 iter_can_seek_beginning
=iter_can_seek_beginning
,
876 iter_can_seek_forward
=iter_can_seek_forward
,
879 def test_no_can_seek_ns_from_origin_no_seek_ns_from_origin_can_seek_beginning_forward_seekable(
882 # Test the case where:
884 # - can_seek_ns_from_origin: Not provided
885 # - seek_ns_from_origin provided: Not provided
886 # - can the iterator seek beginning: Yes
887 # - can the iterator seek forward: Yes
889 # We expect iter.can_seek_ns_from_origin to return 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
=False,
894 iter_can_seek_beginning
=True,
895 iter_can_seek_forward
=True,
898 def test_no_can_seek_ns_from_origin_no_seek_ns_from_origin_can_seek_beginning_not_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: No
908 # We expect iter.can_seek_ns_from_origin to return False.
909 self
._can
_seek
_ns
_from
_origin
_test
(
910 expected_outcome
=False,
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
=False,
917 def test_no_can_seek_ns_from_origin_no_seek_ns_from_origin_cant_seek_beginning_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: No
925 # - can the iterator seek forward: Yes
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
=False,
933 iter_can_seek_forward
=True,
936 def test_no_can_seek_ns_from_origin_no_seek_ns_from_origin_cant_seek_beginning_not_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: No
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
=False,
955 def _can_seek_ns_from_origin_test(
958 user_can_seek_ns_from_origin_ret_val
,
959 user_seek_ns_from_origin_provided
,
960 iter_can_seek_beginning
,
961 iter_can_seek_forward
,
963 class MySink(bt2
._UserSinkComponent
):
964 def __init__(self
, config
, params
, obj
):
965 self
._add
_input
_port
("in")
967 def _user_graph_is_configured(self
):
968 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
970 def _user_consume(self
):
971 nonlocal can_seek_ns_from_origin
972 can_seek_ns_from_origin
= self
._msg
_iter
.can_seek_ns_from_origin(
973 passed_ns_from_origin
976 if user_can_seek_ns_from_origin_ret_val
is not None:
978 def user_can_seek_ns_from_origin(self
, ns_from_origin
):
979 nonlocal received_ns_from_origin
980 received_ns_from_origin
= ns_from_origin
981 return user_can_seek_ns_from_origin_ret_val
984 user_can_seek_ns_from_origin
= None
986 if user_seek_ns_from_origin_provided
:
988 def user_seek_ns_from_origin(self
, ns_from_origin
):
992 user_seek_ns_from_origin
= None
994 if iter_can_seek_beginning
:
996 def user_seek_beginning(self
):
1000 user_seek_beginning
= None
1002 graph
= _setup_seek_test(
1004 user_can_seek_ns_from_origin
=user_can_seek_ns_from_origin
,
1005 user_seek_ns_from_origin
=user_seek_ns_from_origin
,
1006 user_seek_beginning
=user_seek_beginning
,
1007 can_seek_forward
=iter_can_seek_forward
,
1010 passed_ns_from_origin
= 77
1011 received_ns_from_origin
= None
1012 can_seek_ns_from_origin
= None
1014 self
.assertIs(can_seek_ns_from_origin
, expected_outcome
)
1016 if user_can_seek_ns_from_origin_ret_val
is not None:
1017 self
.assertEqual(received_ns_from_origin
, passed_ns_from_origin
)
1019 def test_can_seek_ns_from_origin_user_error(self
):
1020 class MySink(bt2
._UserSinkComponent
):
1021 def __init__(self
, config
, params
, obj
):
1022 self
._add
_input
_port
("in")
1024 def _user_graph_is_configured(self
):
1025 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
1027 def _user_consume(self
):
1028 # This is expected to raise.
1029 self
._msg
_iter
.can_seek_ns_from_origin(2)
1031 def _user_can_seek_ns_from_origin(self
, ns_from_origin
):
1032 raise ValueError("Joutel")
1034 graph
= _setup_seek_test(
1036 user_can_seek_ns_from_origin
=_user_can_seek_ns_from_origin
,
1037 user_seek_ns_from_origin
=lambda: None,
1040 with self
.assertRaises(bt2
._Error
) as ctx
:
1043 cause
= ctx
.exception
[0]
1044 self
.assertIn("ValueError: Joutel", cause
.message
)
1046 def test_can_seek_ns_from_origin_wrong_return_value(self
):
1047 class MySink(bt2
._UserSinkComponent
):
1048 def __init__(self
, config
, params
, obj
):
1049 self
._add
_input
_port
("in")
1051 def _user_graph_is_configured(self
):
1052 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
1054 def _user_consume(self
):
1055 # This is expected to raise.
1056 self
._msg
_iter
.can_seek_ns_from_origin(2)
1058 def _user_can_seek_ns_from_origin(self
, ns_from_origin
):
1061 graph
= _setup_seek_test(
1063 user_can_seek_ns_from_origin
=_user_can_seek_ns_from_origin
,
1064 user_seek_ns_from_origin
=lambda: None,
1067 with self
.assertRaises(bt2
._Error
) as ctx
:
1070 cause
= ctx
.exception
[0]
1071 self
.assertIn("TypeError: 'str' is not a 'bool' object", cause
.message
)
1073 def test_seek_ns_from_origin(self
):
1074 class MySink(bt2
._UserSinkComponent
):
1075 def __init__(self
, config
, params
, obj
):
1076 self
._add
_input
_port
("in")
1078 def _user_graph_is_configured(self
):
1079 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
["in"])
1081 def _user_consume(self
):
1082 self
._msg
_iter
.seek_ns_from_origin(17)
1084 def _user_seek_ns_from_origin(self
, ns_from_origin
):
1085 nonlocal actual_ns_from_origin
1086 actual_ns_from_origin
= ns_from_origin
1088 graph
= _setup_seek_test(
1089 MySink
, user_seek_ns_from_origin
=_user_seek_ns_from_origin
1092 actual_ns_from_origin
= None
1094 self
.assertEqual(actual_ns_from_origin
, 17)
1097 if __name__
== "__main__":