2 # Copyright (C) 2019 EfficiOS Inc.
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; only version 2
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 from utils
import TestOutputPortMessageIterator
23 from bt2
import port
as bt2_port
24 from bt2
import message_iterator
as bt2_message_iterator
27 class SimpleSink(bt2
._UserSinkComponent
):
28 # Straightforward sink that creates one input port (`in`) and consumes from
31 def __init__(self
, config
, params
, obj
):
32 self
._add
_input
_port
('in')
34 def _user_consume(self
):
37 def _user_graph_is_configured(self
):
38 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
['in'])
41 def _create_graph(src_comp_cls
, sink_comp_cls
, flt_comp_cls
=None):
44 src_comp
= graph
.add_component(src_comp_cls
, 'src')
45 sink_comp
= graph
.add_component(sink_comp_cls
, 'sink')
47 if flt_comp_cls
is not None:
48 flt_comp
= graph
.add_component(flt_comp_cls
, 'flt')
49 graph
.connect_ports(src_comp
.output_ports
['out'], flt_comp
.input_ports
['in'])
50 graph
.connect_ports(flt_comp
.output_ports
['out'], sink_comp
.input_ports
['in'])
52 graph
.connect_ports(src_comp
.output_ports
['out'], sink_comp
.input_ports
['in'])
57 class UserMessageIteratorTestCase(unittest
.TestCase
):
59 the_output_port_from_source
= None
60 the_output_port_from_iter
= None
62 class MyIter(bt2
._UserMessageIterator
):
63 def __init__(self
, config
, self_port_output
):
65 nonlocal the_output_port_from_iter
67 the_output_port_from_iter
= self_port_output
69 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
70 def __init__(self
, config
, params
, obj
):
71 nonlocal the_output_port_from_source
72 the_output_port_from_source
= self
._add
_output
_port
('out', 'user data')
75 graph
= _create_graph(MySource
, SimpleSink
)
77 self
.assertTrue(initialized
)
79 the_output_port_from_source
.addr
, the_output_port_from_iter
.addr
81 self
.assertEqual(the_output_port_from_iter
.user_data
, 'user data')
83 def test_create_from_message_iterator(self
):
84 class MySourceIter(bt2
._UserMessageIterator
):
85 def __init__(self
, config
, self_port_output
):
86 nonlocal src_iter_initialized
87 src_iter_initialized
= True
89 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MySourceIter
):
90 def __init__(self
, config
, params
, obj
):
91 self
._add
_output
_port
('out')
93 class MyFilterIter(bt2
._UserMessageIterator
):
94 def __init__(self
, config
, self_port_output
):
95 nonlocal flt_iter_initialized
96 flt_iter_initialized
= True
97 self
._up
_iter
= self
._create
_message
_iterator
(
98 self
._component
._input
_ports
['in']
102 return next(self
._up
_iter
)
104 class MyFilter(bt2
._UserFilterComponent
, message_iterator_class
=MyFilterIter
):
105 def __init__(self
, config
, params
, obj
):
106 self
._add
_input
_port
('in')
107 self
._add
_output
_port
('out')
109 src_iter_initialized
= False
110 flt_iter_initialized
= False
111 graph
= _create_graph(MySource
, SimpleSink
, MyFilter
)
113 self
.assertTrue(src_iter_initialized
)
114 self
.assertTrue(flt_iter_initialized
)
116 def test_create_user_error(self
):
117 # This tests both error handling by
118 # _UserSinkComponent._create_message_iterator
119 # and _UserMessageIterator._create_message_iterator, as they
120 # are both used in the graph.
121 class MySourceIter(bt2
._UserMessageIterator
):
122 def __init__(self
, config
, self_port_output
):
123 raise ValueError('Very bad error')
125 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MySourceIter
):
126 def __init__(self
, config
, params
, obj
):
127 self
._add
_output
_port
('out')
129 class MyFilterIter(bt2
._UserMessageIterator
):
130 def __init__(self
, config
, self_port_output
):
131 # This is expected to raise because of the error in
132 # MySourceIter.__init__.
133 self
._create
_message
_iterator
(self
._component
._input
_ports
['in'])
135 class MyFilter(bt2
._UserFilterComponent
, message_iterator_class
=MyFilterIter
):
136 def __init__(self
, config
, params
, obj
):
137 self
._add
_input
_port
('in')
138 self
._add
_output
_port
('out')
140 graph
= _create_graph(MySource
, SimpleSink
, MyFilter
)
142 with self
.assertRaises(bt2
._Error
) as ctx
:
148 self
.assertIsInstance(cause
, bt2
._MessageIteratorErrorCause
)
149 self
.assertEqual(cause
.component_name
, 'src')
150 self
.assertEqual(cause
.component_output_port_name
, 'out')
151 self
.assertIn('ValueError: Very bad error', cause
.message
)
153 def test_finalize(self
):
154 class MyIter(bt2
._UserMessageIterator
):
155 def _user_finalize(self
):
159 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
160 def __init__(self
, config
, params
, obj
):
161 self
._add
_output
_port
('out')
164 graph
= _create_graph(MySource
, SimpleSink
)
167 self
.assertTrue(finalized
)
169 def test_config_parameter(self
):
170 class MyIter(bt2
._UserMessageIterator
):
171 def __init__(self
, config
, port
):
173 config_type
= type(config
)
175 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
176 def __init__(self
, config
, params
, obj
):
177 self
._add
_output
_port
('out')
180 graph
= _create_graph(MySource
, SimpleSink
)
182 self
.assertIs(config_type
, bt2_message_iterator
._MessageIteratorConfiguration
)
184 def _test_config_can_seek_forward(self
, set_can_seek_forward
):
185 class MyIter(bt2
._UserMessageIterator
):
186 def __init__(self
, config
, port
):
187 if set_can_seek_forward
:
188 config
.can_seek_forward
= True
190 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
191 def __init__(self
, config
, params
, obj
):
192 self
._add
_output
_port
('out')
194 class MySink(bt2
._UserSinkComponent
):
195 def __init__(self
, config
, params
, obj
):
196 self
._add
_input
_port
('in')
198 def _user_graph_is_configured(self
):
199 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
['in'])
201 def _user_consume(self
):
202 nonlocal can_seek_forward
203 can_seek_forward
= self
._msg
_iter
.can_seek_forward
205 can_seek_forward
= None
206 graph
= _create_graph(MySource
, MySink
)
208 self
.assertIs(can_seek_forward
, set_can_seek_forward
)
210 def test_config_can_seek_forward_default(self
):
211 self
._test
_config
_can
_seek
_forward
(False)
213 def test_config_can_seek_forward(self
):
214 self
._test
_config
_can
_seek
_forward
(True)
216 def test_config_can_seek_forward_wrong_type(self
):
217 class MyIter(bt2
._UserMessageIterator
):
218 def __init__(self
, config
, port
):
219 config
.can_seek_forward
= 1
221 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
222 def __init__(self
, config
, params
, obj
):
223 self
._add
_output
_port
('out')
225 graph
= _create_graph(MySource
, SimpleSink
)
226 with self
.assertRaises(bt2
._Error
) as ctx
:
229 root_cause
= ctx
.exception
[0]
230 self
.assertIn("TypeError: 'int' is not a 'bool' object", root_cause
.message
)
232 def test_component(self
):
233 class MyIter(bt2
._UserMessageIterator
):
234 def __init__(self
, config
, self_port_output
):
236 salut
= self
._component
._salut
238 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
239 def __init__(self
, config
, params
, obj
):
240 self
._add
_output
_port
('out')
244 graph
= _create_graph(MySource
, SimpleSink
)
246 self
.assertEqual(salut
, 23)
249 class MyIter(bt2
._UserMessageIterator
):
250 def __init__(self_iter
, config
, self_port_output
):
253 port
= self_iter
._port
254 self
.assertIs(type(self_port_output
), bt2_port
._UserComponentOutputPort
)
255 self
.assertIs(type(port
), bt2_port
._UserComponentOutputPort
)
256 self
.assertEqual(self_port_output
.addr
, port
.addr
)
258 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
259 def __init__(self
, config
, params
, obj
):
260 self
._add
_output
_port
('out')
263 graph
= _create_graph(MySource
, SimpleSink
)
265 self
.assertTrue(called
)
268 class MyIter(bt2
._UserMessageIterator
):
269 def __init__(self
, config
, self_port_output
):
273 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
274 def __init__(self
, config
, params
, obj
):
275 self
._add
_output
_port
('out')
278 graph
= _create_graph(MySource
, SimpleSink
)
280 self
.assertIsNotNone(addr
)
281 self
.assertNotEqual(addr
, 0)
283 # Test that messages returned by _UserMessageIterator.__next__ remain valid
284 # and can be re-used.
285 def test_reuse_message(self
):
286 class MyIter(bt2
._UserMessageIterator
):
287 def __init__(self
, config
, port
):
288 tc
, sc
, ec
= port
.user_data
290 stream
= trace
.create_stream(sc
)
291 packet
= stream
.create_packet()
293 # This message will be returned twice by __next__.
294 event_message
= self
._create
_event
_message
(ec
, packet
)
297 self
._create
_stream
_beginning
_message
(stream
),
298 self
._create
_packet
_beginning
_message
(packet
),
304 return self
._msgs
.pop(0)
306 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
307 def __init__(self
, config
, params
, obj
):
308 tc
= self
._create
_trace
_class
()
309 sc
= tc
.create_stream_class(supports_packets
=True)
310 ec
= sc
.create_event_class()
311 self
._add
_output
_port
('out', (tc
, sc
, ec
))
314 src
= graph
.add_component(MySource
, 'src')
315 it
= TestOutputPortMessageIterator(graph
, src
.output_ports
['out'])
317 # Skip beginning messages.
319 self
.assertIs(type(msg
), bt2
._StreamBeginningMessageConst
)
321 self
.assertIs(type(msg
), bt2
._PacketBeginningMessageConst
)
326 self
.assertIs(type(msg_ev1
), bt2
._EventMessageConst
)
327 self
.assertIs(type(msg_ev2
), bt2
._EventMessageConst
)
328 self
.assertEqual(msg_ev1
.addr
, msg_ev2
.addr
)
330 # Try consuming many times from an iterator that always returns TryAgain.
331 # This verifies that we are not missing an incref of Py_None, making the
332 # refcount of Py_None reach 0.
333 def test_try_again_many_times(self
):
334 # Starting with Python 3.12, `None` is immortal: its reference
335 # count operations are no-op. Skip this test in that case.
336 before
= sys
.getrefcount(None)
337 dummy
= None # noqa: F841
339 if before
== sys
.getrefcount(None):
340 raise unittest
.SkipTest("`None` is immortal")
342 class MyIter(bt2
._UserMessageIterator
):
346 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
347 def __init__(self
, config
, params
, obj
):
348 self
._add
_output
_port
('out')
350 class MyFilterIter(bt2
._UserMessageIterator
):
351 def __init__(self
, port
):
352 input_port
= port
.user_data
353 self
._upstream
_iter
= self
._create
_message
_iterator
(input_port
)
356 return next(self
._upstream
_iter
)
358 def _user_seek_beginning(self
):
359 self
._upstream
_iter
.seek_beginning()
361 def _user_can_seek_beginning(self
):
362 return self
._upstream
_iter
.can_seek_beginning()
364 class MyFilter(bt2
._UserFilterComponent
, message_iterator_class
=MyFilterIter
):
365 def __init__(self
, config
, params
, obj
):
366 input_port
= self
._add
_input
_port
('in')
367 self
._add
_output
_port
('out', input_port
)
370 src
= graph
.add_component(MySource
, 'src')
371 it
= TestOutputPortMessageIterator(graph
, src
.output_ports
['out'])
373 # Three times the initial ref count of `None` iterations should
374 # be enough to catch the bug even if there are small differences
375 # between configurations.
376 none_ref_count
= sys
.getrefcount(None) * 3
378 for i
in range(none_ref_count
):
379 with self
.assertRaises(bt2
.TryAgain
):
382 def test_error_in_iterator_with_cycle_after_having_created_upstream_iterator(self
):
383 # Test a failure that triggered an abort in libbabeltrace2, in this situation:
385 # - The filter iterator creates an upstream iterator.
386 # - The filter iterator creates a reference cycle, including itself.
387 # - An exception is raised, causing the filter iterator's
388 # initialization method to fail.
389 class MySourceIter(bt2
._UserMessageIterator
):
392 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MySourceIter
):
393 def __init__(self
, config
, params
, obj
):
394 self
._add
_output
_port
('out')
396 class MyFilterIter(bt2
._UserMessageIterator
):
397 def __init__(self
, config
, port
):
398 # First, create an upstream iterator.
399 self
._upstream
_iter
= self
._create
_message
_iterator
(
400 self
._component
._input
_ports
['in']
403 # Then, voluntarily make a reference cycle that will keep this
404 # Python object alive, which will keep the upstream iterator
405 # Babeltrace object alive.
408 # Finally, raise an exception to make __init__ fail.
409 raise ValueError('woops')
411 class MyFilter(bt2
._UserFilterComponent
, message_iterator_class
=MyFilterIter
):
412 def __init__(self
, config
, params
, obj
):
413 self
._in
= self
._add
_input
_port
('in')
414 self
._out
= self
._add
_output
_port
('out')
416 class MySink(bt2
._UserSinkComponent
):
417 def __init__(self
, config
, params
, obj
):
418 self
._input
_port
= self
._add
_input
_port
('in')
420 def _user_graph_is_configured(self
):
421 self
._upstream
_iter
= self
._create
_message
_iterator
(self
._input
_port
)
423 def _user_consume(self
):
424 # We should not reach this.
428 src
= g
.add_component(MySource
, 'src')
429 flt
= g
.add_component(MyFilter
, 'flt')
430 snk
= g
.add_component(MySink
, 'snk')
431 g
.connect_ports(src
.output_ports
['out'], flt
.input_ports
['in'])
432 g
.connect_ports(flt
.output_ports
['out'], snk
.input_ports
['in'])
434 with self
.assertRaisesRegex(bt2
._Error
, 'ValueError: woops'):
438 def _setup_seek_test(
440 user_seek_beginning
=None,
441 user_can_seek_beginning
=None,
442 user_seek_ns_from_origin
=None,
443 user_can_seek_ns_from_origin
=None,
444 can_seek_forward
=False,
446 class MySourceIter(bt2
._UserMessageIterator
):
447 def __init__(self
, config
, port
):
448 tc
, sc
, ec
= port
.user_data
450 stream
= trace
.create_stream(sc
)
451 packet
= stream
.create_packet()
454 self
._create
_stream
_beginning
_message
(stream
),
455 self
._create
_packet
_beginning
_message
(packet
),
456 self
._create
_event
_message
(ec
, packet
),
457 self
._create
_event
_message
(ec
, packet
),
458 self
._create
_packet
_end
_message
(packet
),
459 self
._create
_stream
_end
_message
(stream
),
462 config
.can_seek_forward
= can_seek_forward
465 if self
._at
< len(self
._msgs
):
466 msg
= self
._msgs
[self
._at
]
472 if user_seek_beginning
is not None:
473 MySourceIter
._user
_seek
_beginning
= user_seek_beginning
475 if user_can_seek_beginning
is not None:
476 MySourceIter
._user
_can
_seek
_beginning
= user_can_seek_beginning
478 if user_seek_ns_from_origin
is not None:
479 MySourceIter
._user
_seek
_ns
_from
_origin
= user_seek_ns_from_origin
481 if user_can_seek_ns_from_origin
is not None:
482 MySourceIter
._user
_can
_seek
_ns
_from
_origin
= user_can_seek_ns_from_origin
484 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MySourceIter
):
485 def __init__(self
, config
, params
, obj
):
486 tc
= self
._create
_trace
_class
()
487 sc
= tc
.create_stream_class(supports_packets
=True)
488 ec
= sc
.create_event_class()
490 self
._add
_output
_port
('out', (tc
, sc
, ec
))
492 class MyFilterIter(bt2
._UserMessageIterator
):
493 def __init__(self
, config
, port
):
494 self
._upstream
_iter
= self
._create
_message
_iterator
(
495 self
._component
._input
_ports
['in']
497 config
.can_seek_forward
= self
._upstream
_iter
.can_seek_forward
500 return next(self
._upstream
_iter
)
502 def _user_can_seek_beginning(self
):
503 return self
._upstream
_iter
.can_seek_beginning()
505 def _user_seek_beginning(self
):
506 self
._upstream
_iter
.seek_beginning()
508 def _user_can_seek_ns_from_origin(self
, ns_from_origin
):
509 return self
._upstream
_iter
.can_seek_ns_from_origin(ns_from_origin
)
511 def _user_seek_ns_from_origin(self
, ns_from_origin
):
512 self
._upstream
_iter
.seek_ns_from_origin(ns_from_origin
)
514 class MyFilter(bt2
._UserFilterComponent
, message_iterator_class
=MyFilterIter
):
515 def __init__(self
, config
, params
, obj
):
516 self
._add
_input
_port
('in')
517 self
._add
_output
_port
('out')
519 return _create_graph(MySource
, sink_cls
, flt_comp_cls
=MyFilter
)
522 class UserMessageIteratorSeekBeginningTestCase(unittest
.TestCase
):
523 def test_can_seek_beginning_without_seek_beginning(self
):
524 with self
.assertRaisesRegex(
525 bt2
._IncompleteUserClass
,
526 "cannot create component class 'MySource': message iterator class implements _user_can_seek_beginning but not _user_seek_beginning",
528 _setup_seek_test(SimpleSink
, user_can_seek_beginning
=lambda: None)
530 def test_can_seek_beginning(self
):
531 class MySink(bt2
._UserSinkComponent
):
532 def __init__(self
, config
, params
, obj
):
533 self
._add
_input
_port
('in')
535 def _user_graph_is_configured(self
):
536 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
['in'])
538 def _user_consume(self
):
539 nonlocal can_seek_beginning
540 can_seek_beginning
= self
._msg
_iter
.can_seek_beginning()
542 def _user_can_seek_beginning(self
):
543 nonlocal input_port_iter_can_seek_beginning
544 return input_port_iter_can_seek_beginning
546 graph
= _setup_seek_test(
548 user_can_seek_beginning
=_user_can_seek_beginning
,
549 user_seek_beginning
=lambda: None,
552 input_port_iter_can_seek_beginning
= True
553 can_seek_beginning
= None
555 self
.assertIs(can_seek_beginning
, True)
557 input_port_iter_can_seek_beginning
= False
558 can_seek_beginning
= None
560 self
.assertIs(can_seek_beginning
, False)
562 def test_no_can_seek_beginning_with_seek_beginning(self
):
563 # Test an iterator without a _user_can_seek_beginning method, but with
564 # a _user_seek_beginning method.
565 class MySink(bt2
._UserSinkComponent
):
566 def __init__(self
, config
, params
, obj
):
567 self
._add
_input
_port
('in')
569 def _user_graph_is_configured(self
):
570 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
['in'])
572 def _user_consume(self
):
573 nonlocal can_seek_beginning
574 can_seek_beginning
= self
._msg
_iter
.can_seek_beginning()
576 def _user_seek_beginning(self
):
579 graph
= _setup_seek_test(MySink
, user_seek_beginning
=_user_seek_beginning
)
580 can_seek_beginning
= None
582 self
.assertIs(can_seek_beginning
, True)
584 def test_no_can_seek_beginning(self
):
585 # Test an iterator without a _user_can_seek_beginning method, without
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 graph
= _setup_seek_test(MySink
)
599 can_seek_beginning
= None
601 self
.assertIs(can_seek_beginning
, False)
603 def test_can_seek_beginning_user_error(self
):
604 class MySink(bt2
._UserSinkComponent
):
605 def __init__(self
, config
, params
, obj
):
606 self
._add
_input
_port
('in')
608 def _user_graph_is_configured(self
):
609 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
['in'])
611 def _user_consume(self
):
612 # This is expected to raise.
613 self
._msg
_iter
.can_seek_beginning()
615 def _user_can_seek_beginning(self
):
616 raise ValueError('moustiquaire')
618 graph
= _setup_seek_test(
620 user_can_seek_beginning
=_user_can_seek_beginning
,
621 user_seek_beginning
=lambda: None,
624 with self
.assertRaises(bt2
._Error
) as ctx
:
627 cause
= ctx
.exception
[0]
628 self
.assertIn('ValueError: moustiquaire', cause
.message
)
630 def test_can_seek_beginning_wrong_return_value(self
):
631 class MySink(bt2
._UserSinkComponent
):
632 def __init__(self
, config
, params
, obj
):
633 self
._add
_input
_port
('in')
635 def _user_graph_is_configured(self
):
636 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
['in'])
638 def _user_consume(self
):
639 # This is expected to raise.
640 self
._msg
_iter
.can_seek_beginning()
642 def _user_can_seek_beginning(self
):
645 graph
= _setup_seek_test(
647 user_can_seek_beginning
=_user_can_seek_beginning
,
648 user_seek_beginning
=lambda: None,
651 with self
.assertRaises(bt2
._Error
) as ctx
:
654 cause
= ctx
.exception
[0]
655 self
.assertIn("TypeError: 'str' is not a 'bool' object", cause
.message
)
657 def test_seek_beginning(self
):
658 class MySink(bt2
._UserSinkComponent
):
659 def __init__(self
, config
, params
, obj
):
660 self
._add
_input
_port
('in')
662 def _user_graph_is_configured(self
):
663 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
['in'])
665 def _user_consume(self
):
666 nonlocal do_seek_beginning
669 if do_seek_beginning
:
670 self
._msg
_iter
.seek_beginning()
673 msg
= next(self
._msg
_iter
)
675 def _user_seek_beginning(self
):
679 graph
= _setup_seek_test(MySink
, user_seek_beginning
=_user_seek_beginning
)
682 do_seek_beginning
= False
684 self
.assertIs(type(msg
), bt2
._StreamBeginningMessageConst
)
688 self
.assertIs(type(msg
), bt2
._PacketBeginningMessageConst
)
691 do_seek_beginning
= True
695 do_seek_beginning
= False
697 self
.assertIs(type(msg
), bt2
._StreamBeginningMessageConst
)
699 def test_seek_beginning_user_error(self
):
700 class MySink(bt2
._UserSinkComponent
):
701 def __init__(self
, config
, params
, obj
):
702 self
._add
_input
_port
('in')
704 def _user_graph_is_configured(self
):
705 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
['in'])
707 def _user_consume(self
):
708 self
._msg
_iter
.seek_beginning()
710 def _user_seek_beginning(self
):
711 raise ValueError('ouch')
713 graph
= _setup_seek_test(MySink
, user_seek_beginning
=_user_seek_beginning
)
715 with self
.assertRaises(bt2
._Error
):
719 class UserMessageIteratorSeekNsFromOriginTestCase(unittest
.TestCase
):
720 def test_can_seek_ns_from_origin_without_seek_ns_from_origin(self
):
721 # Test the case where:
723 # - can_seek_ns_from_origin: Returns True (don't really care, as long
725 # - seek_ns_from_origin provided: No
726 # - can the iterator seek beginning: Don't care
727 # - can the iterator seek forward: Don't care
728 for can_seek_ns_from_origin
in (False, True):
729 for iter_can_seek_beginning
in (False, True):
730 for iter_can_seek_forward
in (False, True):
731 with self
.assertRaisesRegex(
732 bt2
._IncompleteUserClass
,
733 "cannot create component class 'MySource': message iterator class implements _user_can_seek_ns_from_origin but not _user_seek_ns_from_origin",
735 self
._can
_seek
_ns
_from
_origin
_test
(
737 user_can_seek_ns_from_origin_ret_val
=True,
738 user_seek_ns_from_origin_provided
=False,
739 iter_can_seek_beginning
=iter_can_seek_beginning
,
740 iter_can_seek_forward
=iter_can_seek_forward
,
743 def test_can_seek_ns_from_origin_returns_true(self
):
744 # Test the case where:
746 # - can_seek_ns_from_origin: returns True
747 # - seek_ns_from_origin provided: Yes
748 # - can the iterator seek beginning: Don't care
749 # - can the iterator seek forward: Don't care
751 # We expect iter.can_seek_ns_from_origin to return True.
752 for iter_can_seek_beginning
in (False, True):
753 for iter_can_seek_forward
in (False, True):
754 self
._can
_seek
_ns
_from
_origin
_test
(
755 expected_outcome
=True,
756 user_can_seek_ns_from_origin_ret_val
=True,
757 user_seek_ns_from_origin_provided
=True,
758 iter_can_seek_beginning
=iter_can_seek_beginning
,
759 iter_can_seek_forward
=iter_can_seek_forward
,
762 def test_can_seek_ns_from_origin_returns_false_can_seek_beginning_forward_seekable(
765 # Test the case where:
767 # - can_seek_ns_from_origin: returns False
768 # - seek_ns_from_origin provided: Yes
769 # - can the iterator seek beginning: Yes
770 # - can the iterator seek forward: Yes
772 # We expect iter.can_seek_ns_from_origin to return True.
773 self
._can
_seek
_ns
_from
_origin
_test
(
774 expected_outcome
=True,
775 user_can_seek_ns_from_origin_ret_val
=False,
776 user_seek_ns_from_origin_provided
=True,
777 iter_can_seek_beginning
=True,
778 iter_can_seek_forward
=True,
781 def test_can_seek_ns_from_origin_returns_false_can_seek_beginning_not_forward_seekable(
784 # Test the case where:
786 # - can_seek_ns_from_origin: returns False
787 # - seek_ns_from_origin provided: Yes
788 # - can the iterator seek beginning: Yes
789 # - can the iterator seek forward: No
791 # We expect iter.can_seek_ns_from_origin to return False.
792 self
._can
_seek
_ns
_from
_origin
_test
(
793 expected_outcome
=False,
794 user_can_seek_ns_from_origin_ret_val
=False,
795 user_seek_ns_from_origin_provided
=True,
796 iter_can_seek_beginning
=True,
797 iter_can_seek_forward
=False,
800 def test_can_seek_ns_from_origin_returns_false_cant_seek_beginning_forward_seekable(
803 # Test the case where:
805 # - can_seek_ns_from_origin: returns False
806 # - seek_ns_from_origin provided: Yes
807 # - can the iterator seek beginning: No
808 # - can the iterator seek forward: Yes
810 # We expect iter.can_seek_ns_from_origin to return False.
811 self
._can
_seek
_ns
_from
_origin
_test
(
812 expected_outcome
=False,
813 user_can_seek_ns_from_origin_ret_val
=False,
814 user_seek_ns_from_origin_provided
=True,
815 iter_can_seek_beginning
=False,
816 iter_can_seek_forward
=True,
819 def test_can_seek_ns_from_origin_returns_false_cant_seek_beginning_not_forward_seekable(
822 # Test the case where:
824 # - can_seek_ns_from_origin: returns False
825 # - seek_ns_from_origin provided: Yes
826 # - can the iterator seek beginning: No
827 # - can the iterator seek forward: No
829 # We expect iter.can_seek_ns_from_origin to return False.
830 self
._can
_seek
_ns
_from
_origin
_test
(
831 expected_outcome
=False,
832 user_can_seek_ns_from_origin_ret_val
=False,
833 user_seek_ns_from_origin_provided
=True,
834 iter_can_seek_beginning
=False,
835 iter_can_seek_forward
=False,
838 def test_no_can_seek_ns_from_origin_seek_ns_from_origin(self
):
839 # Test the case where:
841 # - can_seek_ns_from_origin: Not provided
842 # - seek_ns_from_origin provided: Yes
843 # - can the iterator seek beginning: Don't care
844 # - can the iterator seek forward: Don't care
846 # We expect iter.can_seek_ns_from_origin to return True.
847 for iter_can_seek_beginning
in (False, True):
848 for iter_can_seek_forward
in (False, True):
849 self
._can
_seek
_ns
_from
_origin
_test
(
850 expected_outcome
=True,
851 user_can_seek_ns_from_origin_ret_val
=None,
852 user_seek_ns_from_origin_provided
=True,
853 iter_can_seek_beginning
=iter_can_seek_beginning
,
854 iter_can_seek_forward
=iter_can_seek_forward
,
857 def test_no_can_seek_ns_from_origin_no_seek_ns_from_origin_can_seek_beginning_forward_seekable(
860 # Test the case where:
862 # - can_seek_ns_from_origin: Not provided
863 # - seek_ns_from_origin provided: Not provided
864 # - can the iterator seek beginning: Yes
865 # - can the iterator seek forward: Yes
867 # We expect iter.can_seek_ns_from_origin to return True.
868 self
._can
_seek
_ns
_from
_origin
_test
(
869 expected_outcome
=True,
870 user_can_seek_ns_from_origin_ret_val
=None,
871 user_seek_ns_from_origin_provided
=False,
872 iter_can_seek_beginning
=True,
873 iter_can_seek_forward
=True,
876 def test_no_can_seek_ns_from_origin_no_seek_ns_from_origin_can_seek_beginning_not_forward_seekable(
879 # Test the case where:
881 # - can_seek_ns_from_origin: Not provided
882 # - seek_ns_from_origin provided: Not provided
883 # - can the iterator seek beginning: Yes
884 # - can the iterator seek forward: No
886 # We expect iter.can_seek_ns_from_origin to return False.
887 self
._can
_seek
_ns
_from
_origin
_test
(
888 expected_outcome
=False,
889 user_can_seek_ns_from_origin_ret_val
=None,
890 user_seek_ns_from_origin_provided
=False,
891 iter_can_seek_beginning
=True,
892 iter_can_seek_forward
=False,
895 def test_no_can_seek_ns_from_origin_no_seek_ns_from_origin_cant_seek_beginning_forward_seekable(
898 # Test the case where:
900 # - can_seek_ns_from_origin: Not provided
901 # - seek_ns_from_origin provided: Not provided
902 # - can the iterator seek beginning: No
903 # - can the iterator seek forward: Yes
905 # We expect iter.can_seek_ns_from_origin to return False.
906 self
._can
_seek
_ns
_from
_origin
_test
(
907 expected_outcome
=False,
908 user_can_seek_ns_from_origin_ret_val
=None,
909 user_seek_ns_from_origin_provided
=False,
910 iter_can_seek_beginning
=False,
911 iter_can_seek_forward
=True,
914 def test_no_can_seek_ns_from_origin_no_seek_ns_from_origin_cant_seek_beginning_not_forward_seekable(
917 # Test the case where:
919 # - can_seek_ns_from_origin: Not provided
920 # - seek_ns_from_origin provided: Not provided
921 # - can the iterator seek beginning: No
922 # - can the iterator seek forward: No
924 # We expect iter.can_seek_ns_from_origin to return False.
925 self
._can
_seek
_ns
_from
_origin
_test
(
926 expected_outcome
=False,
927 user_can_seek_ns_from_origin_ret_val
=None,
928 user_seek_ns_from_origin_provided
=False,
929 iter_can_seek_beginning
=False,
930 iter_can_seek_forward
=False,
933 def _can_seek_ns_from_origin_test(
936 user_can_seek_ns_from_origin_ret_val
,
937 user_seek_ns_from_origin_provided
,
938 iter_can_seek_beginning
,
939 iter_can_seek_forward
,
941 class MySink(bt2
._UserSinkComponent
):
942 def __init__(self
, config
, params
, obj
):
943 self
._add
_input
_port
('in')
945 def _user_graph_is_configured(self
):
946 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
['in'])
948 def _user_consume(self
):
949 nonlocal can_seek_ns_from_origin
950 can_seek_ns_from_origin
= self
._msg
_iter
.can_seek_ns_from_origin(
951 passed_ns_from_origin
954 if user_can_seek_ns_from_origin_ret_val
is not None:
956 def user_can_seek_ns_from_origin(self
, ns_from_origin
):
957 nonlocal received_ns_from_origin
958 received_ns_from_origin
= ns_from_origin
959 return user_can_seek_ns_from_origin_ret_val
962 user_can_seek_ns_from_origin
= None
964 if user_seek_ns_from_origin_provided
:
966 def user_seek_ns_from_origin(self
, ns_from_origin
):
970 user_seek_ns_from_origin
= None
972 if iter_can_seek_beginning
:
974 def user_seek_beginning(self
):
978 user_seek_beginning
= None
980 graph
= _setup_seek_test(
982 user_can_seek_ns_from_origin
=user_can_seek_ns_from_origin
,
983 user_seek_ns_from_origin
=user_seek_ns_from_origin
,
984 user_seek_beginning
=user_seek_beginning
,
985 can_seek_forward
=iter_can_seek_forward
,
988 passed_ns_from_origin
= 77
989 received_ns_from_origin
= None
990 can_seek_ns_from_origin
= None
992 self
.assertIs(can_seek_ns_from_origin
, expected_outcome
)
994 if user_can_seek_ns_from_origin_ret_val
is not None:
995 self
.assertEqual(received_ns_from_origin
, passed_ns_from_origin
)
997 def test_can_seek_ns_from_origin_user_error(self
):
998 class MySink(bt2
._UserSinkComponent
):
999 def __init__(self
, config
, params
, obj
):
1000 self
._add
_input
_port
('in')
1002 def _user_graph_is_configured(self
):
1003 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
['in'])
1005 def _user_consume(self
):
1006 # This is expected to raise.
1007 self
._msg
_iter
.can_seek_ns_from_origin(2)
1009 def _user_can_seek_ns_from_origin(self
, ns_from_origin
):
1010 raise ValueError('Joutel')
1012 graph
= _setup_seek_test(
1014 user_can_seek_ns_from_origin
=_user_can_seek_ns_from_origin
,
1015 user_seek_ns_from_origin
=lambda: None,
1018 with self
.assertRaises(bt2
._Error
) as ctx
:
1021 cause
= ctx
.exception
[0]
1022 self
.assertIn('ValueError: Joutel', cause
.message
)
1024 def test_can_seek_ns_from_origin_wrong_return_value(self
):
1025 class MySink(bt2
._UserSinkComponent
):
1026 def __init__(self
, config
, params
, obj
):
1027 self
._add
_input
_port
('in')
1029 def _user_graph_is_configured(self
):
1030 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
['in'])
1032 def _user_consume(self
):
1033 # This is expected to raise.
1034 self
._msg
_iter
.can_seek_ns_from_origin(2)
1036 def _user_can_seek_ns_from_origin(self
, ns_from_origin
):
1039 graph
= _setup_seek_test(
1041 user_can_seek_ns_from_origin
=_user_can_seek_ns_from_origin
,
1042 user_seek_ns_from_origin
=lambda: None,
1045 with self
.assertRaises(bt2
._Error
) as ctx
:
1048 cause
= ctx
.exception
[0]
1049 self
.assertIn("TypeError: 'str' is not a 'bool' object", cause
.message
)
1051 def test_seek_ns_from_origin(self
):
1052 class MySink(bt2
._UserSinkComponent
):
1053 def __init__(self
, config
, params
, obj
):
1054 self
._add
_input
_port
('in')
1056 def _user_graph_is_configured(self
):
1057 self
._msg
_iter
= self
._create
_message
_iterator
(self
._input
_ports
['in'])
1059 def _user_consume(self
):
1060 self
._msg
_iter
.seek_ns_from_origin(17)
1062 def _user_seek_ns_from_origin(self
, ns_from_origin
):
1063 nonlocal actual_ns_from_origin
1064 actual_ns_from_origin
= ns_from_origin
1066 graph
= _setup_seek_test(
1067 MySink
, user_seek_ns_from_origin
=_user_seek_ns_from_origin
1070 actual_ns_from_origin
= None
1072 self
.assertEqual(actual_ns_from_origin
, 17)
1075 if __name__
== '__main__':