Fix: src.ctf.fs: initialize the other_entry variable
[babeltrace.git] / tests / bindings / python / bt2 / test_message_iterator.py
CommitLineData
d2d857a8
MJ
1#
2# Copyright (C) 2019 EfficiOS Inc.
3#
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
7# of the License.
8#
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.
13#
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.
17#
18
811644b8 19import unittest
811644b8 20import bt2
8e97c333 21import sys
6c373cc9 22from utils import TestOutputPortMessageIterator
14503fb1 23from bt2 import port as bt2_port
8d8b141d 24from bt2 import message_iterator as bt2_message_iterator
811644b8
PP
25
26
0a6d7302
SM
27class SimpleSink(bt2._UserSinkComponent):
28 # Straightforward sink that creates one input port (`in`) and consumes from
29 # it.
811644b8 30
59225a3e 31 def __init__(self, config, params, obj):
0a6d7302 32 self._add_input_port('in')
811644b8 33
0a6d7302
SM
34 def _user_consume(self):
35 next(self._msg_iter)
811644b8 36
0a6d7302 37 def _user_graph_is_configured(self):
9a2c8b8e 38 self._msg_iter = self._create_message_iterator(self._input_ports['in'])
ca02df0a 39
ca02df0a 40
0a6d7302
SM
41def _create_graph(src_comp_cls, sink_comp_cls, flt_comp_cls=None):
42 graph = bt2.Graph()
ca02df0a 43
0a6d7302
SM
44 src_comp = graph.add_component(src_comp_cls, 'src')
45 sink_comp = graph.add_component(sink_comp_cls, 'sink')
ca02df0a 46
0a6d7302
SM
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'])
51 else:
52 graph.connect_ports(src_comp.output_ports['out'], sink_comp.input_ports['in'])
811644b8 53
0a6d7302
SM
54 return graph
55
56
57class UserMessageIteratorTestCase(unittest.TestCase):
811644b8 58 def test_init(self):
c5f330cd
SM
59 the_output_port_from_source = None
60 the_output_port_from_iter = None
61
5602ef81 62 class MyIter(bt2._UserMessageIterator):
8d8b141d 63 def __init__(self, config, self_port_output):
811644b8 64 nonlocal initialized
c5f330cd 65 nonlocal the_output_port_from_iter
811644b8 66 initialized = True
c5f330cd 67 the_output_port_from_iter = self_port_output
811644b8 68
cfbd7cf3 69 class MySource(bt2._UserSourceComponent, message_iterator_class=MyIter):
59225a3e 70 def __init__(self, config, params, obj):
c5f330cd 71 nonlocal the_output_port_from_source
2e00bc76 72 the_output_port_from_source = self._add_output_port('out', 'user data')
811644b8
PP
73
74 initialized = False
0a6d7302 75 graph = _create_graph(MySource, SimpleSink)
c5f330cd 76 graph.run()
811644b8 77 self.assertTrue(initialized)
cfbd7cf3
FD
78 self.assertEqual(
79 the_output_port_from_source.addr, the_output_port_from_iter.addr
80 )
2e00bc76 81 self.assertEqual(the_output_port_from_iter.user_data, 'user data')
811644b8 82
ca02df0a
PP
83 def test_create_from_message_iterator(self):
84 class MySourceIter(bt2._UserMessageIterator):
8d8b141d 85 def __init__(self, config, self_port_output):
ca02df0a
PP
86 nonlocal src_iter_initialized
87 src_iter_initialized = True
88
89 class MySource(bt2._UserSourceComponent, message_iterator_class=MySourceIter):
59225a3e 90 def __init__(self, config, params, obj):
ca02df0a
PP
91 self._add_output_port('out')
92
93 class MyFilterIter(bt2._UserMessageIterator):
8d8b141d 94 def __init__(self, config, self_port_output):
ca02df0a
PP
95 nonlocal flt_iter_initialized
96 flt_iter_initialized = True
9a2c8b8e 97 self._up_iter = self._create_message_iterator(
ca02df0a
PP
98 self._component._input_ports['in']
99 )
100
101 def __next__(self):
102 return next(self._up_iter)
103
104 class MyFilter(bt2._UserFilterComponent, message_iterator_class=MyFilterIter):
59225a3e 105 def __init__(self, config, params, obj):
ca02df0a
PP
106 self._add_input_port('in')
107 self._add_output_port('out')
108
109 src_iter_initialized = False
110 flt_iter_initialized = False
0a6d7302 111 graph = _create_graph(MySource, SimpleSink, MyFilter)
ca02df0a
PP
112 graph.run()
113 self.assertTrue(src_iter_initialized)
114 self.assertTrue(flt_iter_initialized)
115
e803df70
SM
116 def test_create_user_error(self):
117 # This tests both error handling by
9a2c8b8e
PP
118 # _UserSinkComponent._create_message_iterator
119 # and _UserMessageIterator._create_message_iterator, as they
e803df70
SM
120 # are both used in the graph.
121 class MySourceIter(bt2._UserMessageIterator):
8d8b141d 122 def __init__(self, config, self_port_output):
e803df70
SM
123 raise ValueError('Very bad error')
124
125 class MySource(bt2._UserSourceComponent, message_iterator_class=MySourceIter):
59225a3e 126 def __init__(self, config, params, obj):
e803df70
SM
127 self._add_output_port('out')
128
129 class MyFilterIter(bt2._UserMessageIterator):
8d8b141d 130 def __init__(self, config, self_port_output):
e803df70
SM
131 # This is expected to raise because of the error in
132 # MySourceIter.__init__.
9a2c8b8e 133 self._create_message_iterator(self._component._input_ports['in'])
e803df70
SM
134
135 class MyFilter(bt2._UserFilterComponent, message_iterator_class=MyFilterIter):
59225a3e 136 def __init__(self, config, params, obj):
e803df70
SM
137 self._add_input_port('in')
138 self._add_output_port('out')
139
0a6d7302 140 graph = _create_graph(MySource, SimpleSink, MyFilter)
e803df70
SM
141
142 with self.assertRaises(bt2._Error) as ctx:
143 graph.run()
144
145 exc = ctx.exception
146 cause = exc[0]
147
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)
152
811644b8 153 def test_finalize(self):
5602ef81 154 class MyIter(bt2._UserMessageIterator):
6a91742b 155 def _user_finalize(self):
811644b8
PP
156 nonlocal finalized
157 finalized = True
158
cfbd7cf3 159 class MySource(bt2._UserSourceComponent, message_iterator_class=MyIter):
59225a3e 160 def __init__(self, config, params, obj):
811644b8
PP
161 self._add_output_port('out')
162
163 finalized = False
0a6d7302 164 graph = _create_graph(MySource, SimpleSink)
c5f330cd 165 graph.run()
811644b8
PP
166 del graph
167 self.assertTrue(finalized)
168
8d8b141d
SM
169 def test_config_parameter(self):
170 class MyIter(bt2._UserMessageIterator):
171 def __init__(self, config, port):
172 nonlocal config_type
173 config_type = type(config)
174
175 class MySource(bt2._UserSourceComponent, message_iterator_class=MyIter):
176 def __init__(self, config, params, obj):
177 self._add_output_port('out')
178
179 config_type = None
180 graph = _create_graph(MySource, SimpleSink)
181 graph.run()
182 self.assertIs(config_type, bt2_message_iterator._MessageIteratorConfiguration)
183
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
189
190 class MySource(bt2._UserSourceComponent, message_iterator_class=MyIter):
191 def __init__(self, config, params, obj):
192 self._add_output_port('out')
193
194 class MySink(bt2._UserSinkComponent):
195 def __init__(self, config, params, obj):
196 self._add_input_port('in')
197
198 def _user_graph_is_configured(self):
9a2c8b8e 199 self._msg_iter = self._create_message_iterator(self._input_ports['in'])
8d8b141d
SM
200
201 def _user_consume(self):
202 nonlocal can_seek_forward
203 can_seek_forward = self._msg_iter.can_seek_forward
204
205 can_seek_forward = None
206 graph = _create_graph(MySource, MySink)
207 graph.run_once()
208 self.assertIs(can_seek_forward, set_can_seek_forward)
209
210 def test_config_can_seek_forward_default(self):
211 self._test_config_can_seek_forward(False)
212
213 def test_config_can_seek_forward(self):
214 self._test_config_can_seek_forward(True)
215
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
220
221 class MySource(bt2._UserSourceComponent, message_iterator_class=MyIter):
222 def __init__(self, config, params, obj):
223 self._add_output_port('out')
224
225 graph = _create_graph(MySource, SimpleSink)
226 with self.assertRaises(bt2._Error) as ctx:
227 graph.run()
228
229 root_cause = ctx.exception[0]
230 self.assertIn("TypeError: 'int' is not a 'bool' object", root_cause.message)
231
811644b8 232 def test_component(self):
5602ef81 233 class MyIter(bt2._UserMessageIterator):
8d8b141d 234 def __init__(self, config, self_port_output):
811644b8
PP
235 nonlocal salut
236 salut = self._component._salut
237
cfbd7cf3 238 class MySource(bt2._UserSourceComponent, message_iterator_class=MyIter):
59225a3e 239 def __init__(self, config, params, obj):
811644b8
PP
240 self._add_output_port('out')
241 self._salut = 23
242
243 salut = None
0a6d7302 244 graph = _create_graph(MySource, SimpleSink)
c5f330cd 245 graph.run()
811644b8
PP
246 self.assertEqual(salut, 23)
247
14503fb1
SM
248 def test_port(self):
249 class MyIter(bt2._UserMessageIterator):
8d8b141d 250 def __init__(self_iter, config, self_port_output):
14503fb1
SM
251 nonlocal called
252 called = True
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)
257
258 class MySource(bt2._UserSourceComponent, message_iterator_class=MyIter):
59225a3e 259 def __init__(self, config, params, obj):
14503fb1
SM
260 self._add_output_port('out')
261
262 called = False
0a6d7302 263 graph = _create_graph(MySource, SimpleSink)
14503fb1
SM
264 graph.run()
265 self.assertTrue(called)
266
811644b8 267 def test_addr(self):
5602ef81 268 class MyIter(bt2._UserMessageIterator):
8d8b141d 269 def __init__(self, config, self_port_output):
811644b8
PP
270 nonlocal addr
271 addr = self.addr
272
cfbd7cf3 273 class MySource(bt2._UserSourceComponent, message_iterator_class=MyIter):
59225a3e 274 def __init__(self, config, params, obj):
811644b8
PP
275 self._add_output_port('out')
276
277 addr = None
0a6d7302 278 graph = _create_graph(MySource, SimpleSink)
c5f330cd 279 graph.run()
811644b8
PP
280 self.assertIsNotNone(addr)
281 self.assertNotEqual(addr, 0)
282
d79a8353
SM
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):
8d8b141d 287 def __init__(self, config, port):
d79a8353
SM
288 tc, sc, ec = port.user_data
289 trace = tc()
290 stream = trace.create_stream(sc)
291 packet = stream.create_packet()
292
293 # This message will be returned twice by __next__.
294 event_message = self._create_event_message(ec, packet)
295
296 self._msgs = [
297 self._create_stream_beginning_message(stream),
d79a8353
SM
298 self._create_packet_beginning_message(packet),
299 event_message,
300 event_message,
301 ]
302
303 def __next__(self):
304 return self._msgs.pop(0)
305
306 class MySource(bt2._UserSourceComponent, message_iterator_class=MyIter):
59225a3e 307 def __init__(self, config, params, obj):
d79a8353 308 tc = self._create_trace_class()
26fc5aed 309 sc = tc.create_stream_class(supports_packets=True)
d79a8353
SM
310 ec = sc.create_event_class()
311 self._add_output_port('out', (tc, sc, ec))
312
313 graph = bt2.Graph()
314 src = graph.add_component(MySource, 'src')
6c373cc9 315 it = TestOutputPortMessageIterator(graph, src.output_ports['out'])
d79a8353
SM
316
317 # Skip beginning messages.
188edac1 318 msg = next(it)
f0a42b33 319 self.assertIs(type(msg), bt2._StreamBeginningMessageConst)
188edac1 320 msg = next(it)
f0a42b33 321 self.assertIs(type(msg), bt2._PacketBeginningMessageConst)
d79a8353
SM
322
323 msg_ev1 = next(it)
324 msg_ev2 = next(it)
325
f0a42b33
FD
326 self.assertIs(type(msg_ev1), bt2._EventMessageConst)
327 self.assertIs(type(msg_ev2), bt2._EventMessageConst)
d79a8353
SM
328 self.assertEqual(msg_ev1.addr, msg_ev2.addr)
329
0a6d7302
SM
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 class MyIter(bt2._UserMessageIterator):
f00b8d40 335 def __next__(self):
0a6d7302 336 raise bt2.TryAgain
f00b8d40 337
0a6d7302 338 class MySource(bt2._UserSourceComponent, message_iterator_class=MyIter):
59225a3e 339 def __init__(self, config, params, obj):
0a6d7302 340 self._add_output_port('out')
f00b8d40
SM
341
342 class MyFilterIter(bt2._UserMessageIterator):
343 def __init__(self, port):
344 input_port = port.user_data
9a2c8b8e 345 self._upstream_iter = self._create_message_iterator(input_port)
f00b8d40
SM
346
347 def __next__(self):
348 return next(self._upstream_iter)
349
6a91742b 350 def _user_seek_beginning(self):
f00b8d40
SM
351 self._upstream_iter.seek_beginning()
352
6a91742b 353 def _user_can_seek_beginning(self):
14cfc8ce 354 return self._upstream_iter.can_seek_beginning()
f00b8d40
SM
355
356 class MyFilter(bt2._UserFilterComponent, message_iterator_class=MyFilterIter):
59225a3e 357 def __init__(self, config, params, obj):
f00b8d40
SM
358 input_port = self._add_input_port('in')
359 self._add_output_port('out', input_port)
360
f00b8d40
SM
361 graph = bt2.Graph()
362 src = graph.add_component(MySource, 'src')
0a6d7302
SM
363 it = TestOutputPortMessageIterator(graph, src.output_ports['out'])
364
365 # Three times the initial ref count of `None` iterations should
366 # be enough to catch the bug even if there are small differences
367 # between configurations.
368 none_ref_count = sys.getrefcount(None) * 3
369
370 for i in range(none_ref_count):
371 with self.assertRaises(bt2.TryAgain):
372 next(it)
373
fca28f75
SM
374 def test_error_in_iterator_with_cycle_after_having_created_upstream_iterator(self):
375 # Test a failure that triggered an abort in libbabeltrace2, in this situation:
376 #
377 # - The filter iterator creates an upstream iterator.
378 # - The filter iterator creates a reference cycle, including itself.
379 # - An exception is raised, causing the filter iterator's
380 # initialization method to fail.
381 class MySourceIter(bt2._UserMessageIterator):
382 pass
383
384 class MySource(bt2._UserSourceComponent, message_iterator_class=MySourceIter):
385 def __init__(self, config, params, obj):
386 self._add_output_port('out')
387
388 class MyFilterIter(bt2._UserMessageIterator):
389 def __init__(self, config, port):
390 # First, create an upstream iterator.
9a2c8b8e 391 self._upstream_iter = self._create_message_iterator(
fca28f75
SM
392 self._component._input_ports['in']
393 )
394
395 # Then, voluntarily make a reference cycle that will keep this
396 # Python object alive, which will keep the upstream iterator
397 # Babeltrace object alive.
398 self._self = self
399
400 # Finally, raise an exception to make __init__ fail.
401 raise ValueError('woops')
402
403 class MyFilter(bt2._UserFilterComponent, message_iterator_class=MyFilterIter):
404 def __init__(self, config, params, obj):
405 self._in = self._add_input_port('in')
406 self._out = self._add_output_port('out')
407
408 class MySink(bt2._UserSinkComponent):
409 def __init__(self, config, params, obj):
410 self._input_port = self._add_input_port('in')
411
412 def _user_graph_is_configured(self):
9a2c8b8e 413 self._upstream_iter = self._create_message_iterator(self._input_port)
fca28f75
SM
414
415 def _user_consume(self):
416 # We should not reach this.
417 assert False
418
419 g = bt2.Graph()
420 src = g.add_component(MySource, 'src')
421 flt = g.add_component(MyFilter, 'flt')
422 snk = g.add_component(MySink, 'snk')
423 g.connect_ports(src.output_ports['out'], flt.input_ports['in'])
424 g.connect_ports(flt.output_ports['out'], snk.input_ports['in'])
425
426 with self.assertRaisesRegex(bt2._Error, 'ValueError: woops'):
427 g.run()
428
0a6d7302 429
c182d7dd
SM
430def _setup_seek_test(
431 sink_cls,
432 user_seek_beginning=None,
433 user_can_seek_beginning=None,
434 user_seek_ns_from_origin=None,
435 user_can_seek_ns_from_origin=None,
c0e46a7c 436 can_seek_forward=False,
c182d7dd 437):
0a6d7302 438 class MySourceIter(bt2._UserMessageIterator):
8d8b141d 439 def __init__(self, config, port):
0a6d7302
SM
440 tc, sc, ec = port.user_data
441 trace = tc()
442 stream = trace.create_stream(sc)
443 packet = stream.create_packet()
444
445 self._msgs = [
446 self._create_stream_beginning_message(stream),
447 self._create_packet_beginning_message(packet),
448 self._create_event_message(ec, packet),
449 self._create_event_message(ec, packet),
450 self._create_packet_end_message(packet),
451 self._create_stream_end_message(stream),
452 ]
453 self._at = 0
c0e46a7c 454 config.can_seek_forward = can_seek_forward
0a6d7302
SM
455
456 def __next__(self):
457 if self._at < len(self._msgs):
458 msg = self._msgs[self._at]
459 self._at += 1
460 return msg
461 else:
462 raise StopIteration
463
464 if user_seek_beginning is not None:
465 MySourceIter._user_seek_beginning = user_seek_beginning
466
467 if user_can_seek_beginning is not None:
14cfc8ce 468 MySourceIter._user_can_seek_beginning = user_can_seek_beginning
0a6d7302 469
c182d7dd
SM
470 if user_seek_ns_from_origin is not None:
471 MySourceIter._user_seek_ns_from_origin = user_seek_ns_from_origin
472
473 if user_can_seek_ns_from_origin is not None:
474 MySourceIter._user_can_seek_ns_from_origin = user_can_seek_ns_from_origin
475
0a6d7302 476 class MySource(bt2._UserSourceComponent, message_iterator_class=MySourceIter):
59225a3e 477 def __init__(self, config, params, obj):
0a6d7302
SM
478 tc = self._create_trace_class()
479 sc = tc.create_stream_class(supports_packets=True)
480 ec = sc.create_event_class()
481
482 self._add_output_port('out', (tc, sc, ec))
483
484 class MyFilterIter(bt2._UserMessageIterator):
8d8b141d 485 def __init__(self, config, port):
9a2c8b8e 486 self._upstream_iter = self._create_message_iterator(
0a6d7302
SM
487 self._component._input_ports['in']
488 )
c0e46a7c 489 config.can_seek_forward = self._upstream_iter.can_seek_forward
0a6d7302
SM
490
491 def __next__(self):
492 return next(self._upstream_iter)
493
0a6d7302 494 def _user_can_seek_beginning(self):
14cfc8ce 495 return self._upstream_iter.can_seek_beginning()
0a6d7302
SM
496
497 def _user_seek_beginning(self):
498 self._upstream_iter.seek_beginning()
499
c182d7dd
SM
500 def _user_can_seek_ns_from_origin(self, ns_from_origin):
501 return self._upstream_iter.can_seek_ns_from_origin(ns_from_origin)
502
503 def _user_seek_ns_from_origin(self, ns_from_origin):
504 self._upstream_iter.seek_ns_from_origin(ns_from_origin)
505
0a6d7302 506 class MyFilter(bt2._UserFilterComponent, message_iterator_class=MyFilterIter):
59225a3e 507 def __init__(self, config, params, obj):
0a6d7302
SM
508 self._add_input_port('in')
509 self._add_output_port('out')
510
511 return _create_graph(MySource, sink_cls, flt_comp_cls=MyFilter)
f00b8d40 512
0a6d7302
SM
513
514class UserMessageIteratorSeekBeginningTestCase(unittest.TestCase):
2e1b5615
SM
515 def test_can_seek_beginning_without_seek_beginning(self):
516 with self.assertRaisesRegex(
517 bt2._IncompleteUserClass,
518 "cannot create component class 'MySource': message iterator class implements _user_can_seek_beginning but not _user_seek_beginning",
519 ):
520 _setup_seek_test(SimpleSink, user_can_seek_beginning=lambda: None)
521
f00b8d40 522 def test_can_seek_beginning(self):
6c373cc9 523 class MySink(bt2._UserSinkComponent):
59225a3e 524 def __init__(self, config, params, obj):
6c373cc9
PP
525 self._add_input_port('in')
526
527 def _user_graph_is_configured(self):
9a2c8b8e 528 self._msg_iter = self._create_message_iterator(self._input_ports['in'])
6c373cc9
PP
529
530 def _user_consume(self):
531 nonlocal can_seek_beginning
14cfc8ce 532 can_seek_beginning = self._msg_iter.can_seek_beginning()
6c373cc9 533
6a91742b 534 def _user_can_seek_beginning(self):
6c373cc9
PP
535 nonlocal input_port_iter_can_seek_beginning
536 return input_port_iter_can_seek_beginning
f00b8d40 537
0a6d7302 538 graph = _setup_seek_test(
2e1b5615
SM
539 MySink,
540 user_can_seek_beginning=_user_can_seek_beginning,
541 user_seek_beginning=lambda: None,
0a6d7302 542 )
f00b8d40 543
6c373cc9
PP
544 input_port_iter_can_seek_beginning = True
545 can_seek_beginning = None
546 graph.run_once()
7f0c21bb 547 self.assertIs(can_seek_beginning, True)
f00b8d40 548
6c373cc9
PP
549 input_port_iter_can_seek_beginning = False
550 can_seek_beginning = None
551 graph.run_once()
7f0c21bb 552 self.assertIs(can_seek_beginning, False)
f00b8d40 553
0a6d7302
SM
554 def test_no_can_seek_beginning_with_seek_beginning(self):
555 # Test an iterator without a _user_can_seek_beginning method, but with
556 # a _user_seek_beginning method.
557 class MySink(bt2._UserSinkComponent):
59225a3e 558 def __init__(self, config, params, obj):
0a6d7302
SM
559 self._add_input_port('in')
560
561 def _user_graph_is_configured(self):
9a2c8b8e 562 self._msg_iter = self._create_message_iterator(self._input_ports['in'])
0a6d7302
SM
563
564 def _user_consume(self):
565 nonlocal can_seek_beginning
14cfc8ce 566 can_seek_beginning = self._msg_iter.can_seek_beginning()
0a6d7302
SM
567
568 def _user_seek_beginning(self):
569 pass
f00b8d40 570
0a6d7302 571 graph = _setup_seek_test(MySink, user_seek_beginning=_user_seek_beginning)
6c373cc9
PP
572 can_seek_beginning = None
573 graph.run_once()
7f0c21bb 574 self.assertIs(can_seek_beginning, True)
f00b8d40 575
0a6d7302
SM
576 def test_no_can_seek_beginning(self):
577 # Test an iterator without a _user_can_seek_beginning method, without
578 # a _user_seek_beginning method.
579 class MySink(bt2._UserSinkComponent):
59225a3e 580 def __init__(self, config, params, obj):
0a6d7302
SM
581 self._add_input_port('in')
582
583 def _user_graph_is_configured(self):
9a2c8b8e 584 self._msg_iter = self._create_message_iterator(self._input_ports['in'])
0a6d7302
SM
585
586 def _user_consume(self):
587 nonlocal can_seek_beginning
14cfc8ce 588 can_seek_beginning = self._msg_iter.can_seek_beginning()
0a6d7302
SM
589
590 graph = _setup_seek_test(MySink)
6c373cc9
PP
591 can_seek_beginning = None
592 graph.run_once()
7f0c21bb 593 self.assertIs(can_seek_beginning, False)
f00b8d40 594
f2fb1b32
SM
595 def test_can_seek_beginning_user_error(self):
596 class MySink(bt2._UserSinkComponent):
59225a3e 597 def __init__(self, config, params, obj):
f2fb1b32
SM
598 self._add_input_port('in')
599
600 def _user_graph_is_configured(self):
9a2c8b8e 601 self._msg_iter = self._create_message_iterator(self._input_ports['in'])
f2fb1b32
SM
602
603 def _user_consume(self):
604 # This is expected to raise.
14cfc8ce 605 self._msg_iter.can_seek_beginning()
f2fb1b32
SM
606
607 def _user_can_seek_beginning(self):
608 raise ValueError('moustiquaire')
609
610 graph = _setup_seek_test(
2e1b5615
SM
611 MySink,
612 user_can_seek_beginning=_user_can_seek_beginning,
613 user_seek_beginning=lambda: None,
f2fb1b32
SM
614 )
615
616 with self.assertRaises(bt2._Error) as ctx:
617 graph.run_once()
618
619 cause = ctx.exception[0]
620 self.assertIn('ValueError: moustiquaire', cause.message)
621
622 def test_can_seek_beginning_wrong_return_value(self):
623 class MySink(bt2._UserSinkComponent):
59225a3e 624 def __init__(self, config, params, obj):
f2fb1b32
SM
625 self._add_input_port('in')
626
627 def _user_graph_is_configured(self):
9a2c8b8e 628 self._msg_iter = self._create_message_iterator(self._input_ports['in'])
f2fb1b32
SM
629
630 def _user_consume(self):
631 # This is expected to raise.
14cfc8ce 632 self._msg_iter.can_seek_beginning()
f2fb1b32
SM
633
634 def _user_can_seek_beginning(self):
635 return 'Amqui'
636
637 graph = _setup_seek_test(
2e1b5615
SM
638 MySink,
639 user_can_seek_beginning=_user_can_seek_beginning,
640 user_seek_beginning=lambda: None,
f2fb1b32
SM
641 )
642
643 with self.assertRaises(bt2._Error) as ctx:
644 graph.run_once()
645
646 cause = ctx.exception[0]
647 self.assertIn("TypeError: 'str' is not a 'bool' object", cause.message)
648
f00b8d40 649 def test_seek_beginning(self):
6c373cc9 650 class MySink(bt2._UserSinkComponent):
59225a3e 651 def __init__(self, config, params, obj):
6c373cc9 652 self._add_input_port('in')
f00b8d40 653
6c373cc9 654 def _user_graph_is_configured(self):
9a2c8b8e 655 self._msg_iter = self._create_message_iterator(self._input_ports['in'])
6c373cc9
PP
656
657 def _user_consume(self):
658 nonlocal do_seek_beginning
659 nonlocal msg
660
661 if do_seek_beginning:
662 self._msg_iter.seek_beginning()
663 return
664
665 msg = next(self._msg_iter)
666
0a6d7302
SM
667 def _user_seek_beginning(self):
668 self._at = 0
669
6c373cc9 670 msg = None
0a6d7302
SM
671 graph = _setup_seek_test(MySink, user_seek_beginning=_user_seek_beginning)
672
673 # Consume message.
674 do_seek_beginning = False
6c373cc9 675 graph.run_once()
f0a42b33 676 self.assertIs(type(msg), bt2._StreamBeginningMessageConst)
0a6d7302
SM
677
678 # Consume message.
6c373cc9 679 graph.run_once()
f0a42b33 680 self.assertIs(type(msg), bt2._PacketBeginningMessageConst)
0a6d7302
SM
681
682 # Seek beginning.
6c373cc9
PP
683 do_seek_beginning = True
684 graph.run_once()
0a6d7302
SM
685
686 # Consume message.
6c373cc9
PP
687 do_seek_beginning = False
688 graph.run_once()
f0a42b33 689 self.assertIs(type(msg), bt2._StreamBeginningMessageConst)
f00b8d40 690
6c373cc9
PP
691 def test_seek_beginning_user_error(self):
692 class MySink(bt2._UserSinkComponent):
59225a3e 693 def __init__(self, config, params, obj):
6c373cc9 694 self._add_input_port('in')
f00b8d40 695
6c373cc9 696 def _user_graph_is_configured(self):
9a2c8b8e 697 self._msg_iter = self._create_message_iterator(self._input_ports['in'])
f00b8d40 698
6c373cc9
PP
699 def _user_consume(self):
700 self._msg_iter.seek_beginning()
f00b8d40 701
0a6d7302 702 def _user_seek_beginning(self):
cfbd7cf3 703 raise ValueError('ouch')
f00b8d40 704
0a6d7302 705 graph = _setup_seek_test(MySink, user_seek_beginning=_user_seek_beginning)
f00b8d40 706
694c792b 707 with self.assertRaises(bt2._Error):
6c373cc9 708 graph.run_once()
f00b8d40
SM
709
710
c182d7dd 711class UserMessageIteratorSeekNsFromOriginTestCase(unittest.TestCase):
2e1b5615
SM
712 def test_can_seek_ns_from_origin_without_seek_ns_from_origin(self):
713 # Test the case where:
714 #
715 # - can_seek_ns_from_origin: Returns True (don't really care, as long
716 # as it's provided)
717 # - seek_ns_from_origin provided: No
718 # - can the iterator seek beginning: Don't care
719 # - can the iterator seek forward: Don't care
720 for can_seek_ns_from_origin in (False, True):
721 for iter_can_seek_beginning in (False, True):
722 for iter_can_seek_forward in (False, True):
723 with self.assertRaisesRegex(
724 bt2._IncompleteUserClass,
725 "cannot create component class 'MySource': message iterator class implements _user_can_seek_ns_from_origin but not _user_seek_ns_from_origin",
726 ):
727 self._can_seek_ns_from_origin_test(
728 None,
729 user_can_seek_ns_from_origin_ret_val=True,
730 user_seek_ns_from_origin_provided=False,
731 iter_can_seek_beginning=iter_can_seek_beginning,
732 iter_can_seek_forward=iter_can_seek_forward,
733 )
734
c0e46a7c
SM
735 def test_can_seek_ns_from_origin_returns_true(self):
736 # Test the case where:
737 #
738 # - can_seek_ns_from_origin: returns True
2e1b5615 739 # - seek_ns_from_origin provided: Yes
c0e46a7c
SM
740 # - can the iterator seek beginning: Don't care
741 # - can the iterator seek forward: Don't care
742 #
743 # We expect iter.can_seek_ns_from_origin to return True.
2e1b5615
SM
744 for iter_can_seek_beginning in (False, True):
745 for iter_can_seek_forward in (False, True):
746 self._can_seek_ns_from_origin_test(
747 expected_outcome=True,
748 user_can_seek_ns_from_origin_ret_val=True,
749 user_seek_ns_from_origin_provided=True,
750 iter_can_seek_beginning=iter_can_seek_beginning,
751 iter_can_seek_forward=iter_can_seek_forward,
752 )
c0e46a7c
SM
753
754 def test_can_seek_ns_from_origin_returns_false_can_seek_beginning_forward_seekable(
75882e97 755 self,
c0e46a7c
SM
756 ):
757 # Test the case where:
758 #
759 # - can_seek_ns_from_origin: returns False
2e1b5615 760 # - seek_ns_from_origin provided: Yes
c0e46a7c
SM
761 # - can the iterator seek beginning: Yes
762 # - can the iterator seek forward: Yes
763 #
764 # We expect iter.can_seek_ns_from_origin to return True.
2e1b5615
SM
765 self._can_seek_ns_from_origin_test(
766 expected_outcome=True,
767 user_can_seek_ns_from_origin_ret_val=False,
768 user_seek_ns_from_origin_provided=True,
769 iter_can_seek_beginning=True,
770 iter_can_seek_forward=True,
771 )
c182d7dd 772
c0e46a7c 773 def test_can_seek_ns_from_origin_returns_false_can_seek_beginning_not_forward_seekable(
75882e97 774 self,
c0e46a7c
SM
775 ):
776 # Test the case where:
777 #
778 # - can_seek_ns_from_origin: returns False
2e1b5615 779 # - seek_ns_from_origin provided: Yes
c0e46a7c
SM
780 # - can the iterator seek beginning: Yes
781 # - can the iterator seek forward: No
782 #
783 # We expect iter.can_seek_ns_from_origin to return False.
2e1b5615
SM
784 self._can_seek_ns_from_origin_test(
785 expected_outcome=False,
786 user_can_seek_ns_from_origin_ret_val=False,
787 user_seek_ns_from_origin_provided=True,
788 iter_can_seek_beginning=True,
789 iter_can_seek_forward=False,
790 )
c182d7dd 791
c0e46a7c 792 def test_can_seek_ns_from_origin_returns_false_cant_seek_beginning_forward_seekable(
75882e97 793 self,
c0e46a7c
SM
794 ):
795 # Test the case where:
796 #
797 # - can_seek_ns_from_origin: returns False
2e1b5615 798 # - seek_ns_from_origin provided: Yes
c0e46a7c
SM
799 # - can the iterator seek beginning: No
800 # - can the iterator seek forward: Yes
801 #
802 # We expect iter.can_seek_ns_from_origin to return False.
c0e46a7c
SM
803 self._can_seek_ns_from_origin_test(
804 expected_outcome=False,
805 user_can_seek_ns_from_origin_ret_val=False,
2e1b5615 806 user_seek_ns_from_origin_provided=True,
c0e46a7c
SM
807 iter_can_seek_beginning=False,
808 iter_can_seek_forward=True,
809 )
810
811 def test_can_seek_ns_from_origin_returns_false_cant_seek_beginning_not_forward_seekable(
75882e97 812 self,
c0e46a7c
SM
813 ):
814 # Test the case where:
815 #
816 # - can_seek_ns_from_origin: returns False
2e1b5615 817 # - seek_ns_from_origin provided: Yes
c0e46a7c
SM
818 # - can the iterator seek beginning: No
819 # - can the iterator seek forward: No
820 #
821 # We expect iter.can_seek_ns_from_origin to return False.
2e1b5615
SM
822 self._can_seek_ns_from_origin_test(
823 expected_outcome=False,
824 user_can_seek_ns_from_origin_ret_val=False,
825 user_seek_ns_from_origin_provided=True,
826 iter_can_seek_beginning=False,
827 iter_can_seek_forward=False,
828 )
c0e46a7c
SM
829
830 def test_no_can_seek_ns_from_origin_seek_ns_from_origin(self):
831 # Test the case where:
832 #
833 # - can_seek_ns_from_origin: Not provided
834 # - seek_ns_from_origin provided: Yes
835 # - can the iterator seek beginning: Don't care
836 # - can the iterator seek forward: Don't care
837 #
838 # We expect iter.can_seek_ns_from_origin to return True.
839 for iter_can_seek_beginning in (False, True):
840 for iter_can_seek_forward in (False, True):
841 self._can_seek_ns_from_origin_test(
842 expected_outcome=True,
843 user_can_seek_ns_from_origin_ret_val=None,
844 user_seek_ns_from_origin_provided=True,
845 iter_can_seek_beginning=iter_can_seek_beginning,
846 iter_can_seek_forward=iter_can_seek_forward,
c182d7dd
SM
847 )
848
c0e46a7c 849 def test_no_can_seek_ns_from_origin_no_seek_ns_from_origin_can_seek_beginning_forward_seekable(
75882e97 850 self,
c0e46a7c
SM
851 ):
852 # Test the case where:
853 #
854 # - can_seek_ns_from_origin: Not provided
855 # - seek_ns_from_origin provided: Not provided
856 # - can the iterator seek beginning: Yes
857 # - can the iterator seek forward: Yes
858 #
859 # We expect iter.can_seek_ns_from_origin to return True.
860 self._can_seek_ns_from_origin_test(
861 expected_outcome=True,
862 user_can_seek_ns_from_origin_ret_val=None,
863 user_seek_ns_from_origin_provided=False,
864 iter_can_seek_beginning=True,
865 iter_can_seek_forward=True,
866 )
c182d7dd 867
c0e46a7c 868 def test_no_can_seek_ns_from_origin_no_seek_ns_from_origin_can_seek_beginning_not_forward_seekable(
75882e97 869 self,
c0e46a7c
SM
870 ):
871 # Test the case where:
872 #
873 # - can_seek_ns_from_origin: Not provided
874 # - seek_ns_from_origin provided: Not provided
875 # - can the iterator seek beginning: Yes
876 # - can the iterator seek forward: No
877 #
878 # We expect iter.can_seek_ns_from_origin to return False.
879 self._can_seek_ns_from_origin_test(
880 expected_outcome=False,
881 user_can_seek_ns_from_origin_ret_val=None,
882 user_seek_ns_from_origin_provided=False,
883 iter_can_seek_beginning=True,
884 iter_can_seek_forward=False,
c182d7dd
SM
885 )
886
c0e46a7c 887 def test_no_can_seek_ns_from_origin_no_seek_ns_from_origin_cant_seek_beginning_forward_seekable(
75882e97 888 self,
c0e46a7c
SM
889 ):
890 # Test the case where:
891 #
892 # - can_seek_ns_from_origin: Not provided
893 # - seek_ns_from_origin provided: Not provided
894 # - can the iterator seek beginning: No
895 # - can the iterator seek forward: Yes
896 #
897 # We expect iter.can_seek_ns_from_origin to return False.
898 self._can_seek_ns_from_origin_test(
899 expected_outcome=False,
900 user_can_seek_ns_from_origin_ret_val=None,
901 user_seek_ns_from_origin_provided=False,
902 iter_can_seek_beginning=False,
903 iter_can_seek_forward=True,
904 )
c182d7dd 905
c0e46a7c 906 def test_no_can_seek_ns_from_origin_no_seek_ns_from_origin_cant_seek_beginning_not_forward_seekable(
75882e97 907 self,
c0e46a7c
SM
908 ):
909 # Test the case where:
910 #
911 # - can_seek_ns_from_origin: Not provided
912 # - seek_ns_from_origin provided: Not provided
913 # - can the iterator seek beginning: No
914 # - can the iterator seek forward: No
915 #
916 # We expect iter.can_seek_ns_from_origin to return False.
917 self._can_seek_ns_from_origin_test(
918 expected_outcome=False,
919 user_can_seek_ns_from_origin_ret_val=None,
920 user_seek_ns_from_origin_provided=False,
921 iter_can_seek_beginning=False,
922 iter_can_seek_forward=False,
923 )
c182d7dd 924
c0e46a7c
SM
925 def _can_seek_ns_from_origin_test(
926 self,
927 expected_outcome,
928 user_can_seek_ns_from_origin_ret_val,
929 user_seek_ns_from_origin_provided,
930 iter_can_seek_beginning,
931 iter_can_seek_forward,
932 ):
c182d7dd 933 class MySink(bt2._UserSinkComponent):
59225a3e 934 def __init__(self, config, params, obj):
c182d7dd
SM
935 self._add_input_port('in')
936
937 def _user_graph_is_configured(self):
9a2c8b8e 938 self._msg_iter = self._create_message_iterator(self._input_ports['in'])
c182d7dd
SM
939
940 def _user_consume(self):
941 nonlocal can_seek_ns_from_origin
c182d7dd 942 can_seek_ns_from_origin = self._msg_iter.can_seek_ns_from_origin(
c0e46a7c 943 passed_ns_from_origin
c182d7dd
SM
944 )
945
c0e46a7c 946 if user_can_seek_ns_from_origin_ret_val is not None:
c182d7dd 947
c0e46a7c
SM
948 def user_can_seek_ns_from_origin(self, ns_from_origin):
949 nonlocal received_ns_from_origin
950 received_ns_from_origin = ns_from_origin
951 return user_can_seek_ns_from_origin_ret_val
c182d7dd 952
c0e46a7c
SM
953 else:
954 user_can_seek_ns_from_origin = None
c182d7dd 955
c0e46a7c 956 if user_seek_ns_from_origin_provided:
c182d7dd 957
c0e46a7c
SM
958 def user_seek_ns_from_origin(self, ns_from_origin):
959 pass
c182d7dd 960
c0e46a7c
SM
961 else:
962 user_seek_ns_from_origin = None
c182d7dd 963
c0e46a7c 964 if iter_can_seek_beginning:
c182d7dd 965
c0e46a7c
SM
966 def user_seek_beginning(self):
967 pass
c182d7dd 968
c0e46a7c
SM
969 else:
970 user_seek_beginning = None
c182d7dd 971
c0e46a7c
SM
972 graph = _setup_seek_test(
973 MySink,
974 user_can_seek_ns_from_origin=user_can_seek_ns_from_origin,
975 user_seek_ns_from_origin=user_seek_ns_from_origin,
976 user_seek_beginning=user_seek_beginning,
977 can_seek_forward=iter_can_seek_forward,
978 )
c182d7dd 979
c0e46a7c
SM
980 passed_ns_from_origin = 77
981 received_ns_from_origin = None
c182d7dd 982 can_seek_ns_from_origin = None
c182d7dd 983 graph.run_once()
c0e46a7c
SM
984 self.assertIs(can_seek_ns_from_origin, expected_outcome)
985
986 if user_can_seek_ns_from_origin_ret_val is not None:
987 self.assertEqual(received_ns_from_origin, passed_ns_from_origin)
c182d7dd
SM
988
989 def test_can_seek_ns_from_origin_user_error(self):
990 class MySink(bt2._UserSinkComponent):
59225a3e 991 def __init__(self, config, params, obj):
c182d7dd
SM
992 self._add_input_port('in')
993
994 def _user_graph_is_configured(self):
9a2c8b8e 995 self._msg_iter = self._create_message_iterator(self._input_ports['in'])
c182d7dd
SM
996
997 def _user_consume(self):
998 # This is expected to raise.
999 self._msg_iter.can_seek_ns_from_origin(2)
1000
1001 def _user_can_seek_ns_from_origin(self, ns_from_origin):
1002 raise ValueError('Joutel')
1003
1004 graph = _setup_seek_test(
2e1b5615
SM
1005 MySink,
1006 user_can_seek_ns_from_origin=_user_can_seek_ns_from_origin,
1007 user_seek_ns_from_origin=lambda: None,
c182d7dd
SM
1008 )
1009
1010 with self.assertRaises(bt2._Error) as ctx:
1011 graph.run_once()
1012
1013 cause = ctx.exception[0]
1014 self.assertIn('ValueError: Joutel', cause.message)
1015
1016 def test_can_seek_ns_from_origin_wrong_return_value(self):
1017 class MySink(bt2._UserSinkComponent):
59225a3e 1018 def __init__(self, config, params, obj):
c182d7dd
SM
1019 self._add_input_port('in')
1020
1021 def _user_graph_is_configured(self):
9a2c8b8e 1022 self._msg_iter = self._create_message_iterator(self._input_ports['in'])
c182d7dd
SM
1023
1024 def _user_consume(self):
1025 # This is expected to raise.
1026 self._msg_iter.can_seek_ns_from_origin(2)
1027
1028 def _user_can_seek_ns_from_origin(self, ns_from_origin):
1029 return 'Nitchequon'
1030
1031 graph = _setup_seek_test(
2e1b5615
SM
1032 MySink,
1033 user_can_seek_ns_from_origin=_user_can_seek_ns_from_origin,
1034 user_seek_ns_from_origin=lambda: None,
c182d7dd
SM
1035 )
1036
1037 with self.assertRaises(bt2._Error) as ctx:
1038 graph.run_once()
1039
1040 cause = ctx.exception[0]
1041 self.assertIn("TypeError: 'str' is not a 'bool' object", cause.message)
1042
1043 def test_seek_ns_from_origin(self):
1044 class MySink(bt2._UserSinkComponent):
59225a3e 1045 def __init__(self, config, params, obj):
c182d7dd
SM
1046 self._add_input_port('in')
1047
1048 def _user_graph_is_configured(self):
9a2c8b8e 1049 self._msg_iter = self._create_message_iterator(self._input_ports['in'])
c182d7dd
SM
1050
1051 def _user_consume(self):
1052 self._msg_iter.seek_ns_from_origin(17)
1053
1054 def _user_seek_ns_from_origin(self, ns_from_origin):
1055 nonlocal actual_ns_from_origin
1056 actual_ns_from_origin = ns_from_origin
1057
c182d7dd
SM
1058 graph = _setup_seek_test(
1059 MySink, user_seek_ns_from_origin=_user_seek_ns_from_origin
1060 )
1061
1062 actual_ns_from_origin = None
1063 graph.run_once()
1064 self.assertEqual(actual_ns_from_origin, 17)
1065
1066
f00b8d40
SM
1067if __name__ == '__main__':
1068 unittest.main()
This page took 0.119421 seconds and 4 git commands to generate.