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