Commit | Line | Data |
---|---|---|
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 | 19 | import unittest |
811644b8 | 20 | import bt2 |
8e97c333 | 21 | import sys |
6c373cc9 | 22 | from utils import TestOutputPortMessageIterator |
14503fb1 | 23 | from bt2 import port as bt2_port |
8d8b141d | 24 | from bt2 import message_iterator as bt2_message_iterator |
811644b8 PP |
25 | |
26 | ||
0a6d7302 SM |
27 | class 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 SM |
37 | def _user_graph_is_configured(self): |
38 | self._msg_iter = self._create_input_port_message_iterator( | |
39 | self._input_ports['in'] | |
40 | ) | |
ca02df0a | 41 | |
ca02df0a | 42 | |
0a6d7302 SM |
43 | def _create_graph(src_comp_cls, sink_comp_cls, flt_comp_cls=None): |
44 | graph = bt2.Graph() | |
ca02df0a | 45 | |
0a6d7302 SM |
46 | src_comp = graph.add_component(src_comp_cls, 'src') |
47 | sink_comp = graph.add_component(sink_comp_cls, 'sink') | |
ca02df0a | 48 | |
0a6d7302 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']) | |
811644b8 | 55 | |
0a6d7302 SM |
56 | return graph |
57 | ||
58 | ||
59 | class UserMessageIteratorTestCase(unittest.TestCase): | |
811644b8 | 60 | def test_init(self): |
c5f330cd SM |
61 | the_output_port_from_source = None |
62 | the_output_port_from_iter = None | |
63 | ||
5602ef81 | 64 | class MyIter(bt2._UserMessageIterator): |
8d8b141d | 65 | def __init__(self, config, self_port_output): |
811644b8 | 66 | nonlocal initialized |
c5f330cd | 67 | nonlocal the_output_port_from_iter |
811644b8 | 68 | initialized = True |
c5f330cd | 69 | the_output_port_from_iter = self_port_output |
811644b8 | 70 | |
cfbd7cf3 | 71 | class MySource(bt2._UserSourceComponent, message_iterator_class=MyIter): |
59225a3e | 72 | def __init__(self, config, params, obj): |
c5f330cd | 73 | nonlocal the_output_port_from_source |
2e00bc76 | 74 | the_output_port_from_source = self._add_output_port('out', 'user data') |
811644b8 PP |
75 | |
76 | initialized = False | |
0a6d7302 | 77 | graph = _create_graph(MySource, SimpleSink) |
c5f330cd | 78 | graph.run() |
811644b8 | 79 | self.assertTrue(initialized) |
cfbd7cf3 FD |
80 | self.assertEqual( |
81 | the_output_port_from_source.addr, the_output_port_from_iter.addr | |
82 | ) | |
2e00bc76 | 83 | self.assertEqual(the_output_port_from_iter.user_data, 'user data') |
811644b8 | 84 | |
ca02df0a PP |
85 | def test_create_from_message_iterator(self): |
86 | class MySourceIter(bt2._UserMessageIterator): | |
8d8b141d | 87 | def __init__(self, config, self_port_output): |
ca02df0a PP |
88 | nonlocal src_iter_initialized |
89 | src_iter_initialized = True | |
90 | ||
91 | class MySource(bt2._UserSourceComponent, message_iterator_class=MySourceIter): | |
59225a3e | 92 | def __init__(self, config, params, obj): |
ca02df0a PP |
93 | self._add_output_port('out') |
94 | ||
95 | class MyFilterIter(bt2._UserMessageIterator): | |
8d8b141d | 96 | def __init__(self, config, self_port_output): |
ca02df0a 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): | |
59225a3e | 107 | def __init__(self, config, params, obj): |
ca02df0a PP |
108 | self._add_input_port('in') |
109 | self._add_output_port('out') | |
110 | ||
111 | src_iter_initialized = False | |
112 | flt_iter_initialized = False | |
0a6d7302 | 113 | graph = _create_graph(MySource, SimpleSink, MyFilter) |
ca02df0a PP |
114 | graph.run() |
115 | self.assertTrue(src_iter_initialized) | |
116 | self.assertTrue(flt_iter_initialized) | |
117 | ||
e803df70 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): | |
8d8b141d | 124 | def __init__(self, config, self_port_output): |
e803df70 SM |
125 | raise ValueError('Very bad error') |
126 | ||
127 | class MySource(bt2._UserSourceComponent, message_iterator_class=MySourceIter): | |
59225a3e | 128 | def __init__(self, config, params, obj): |
e803df70 SM |
129 | self._add_output_port('out') |
130 | ||
131 | class MyFilterIter(bt2._UserMessageIterator): | |
8d8b141d | 132 | def __init__(self, config, self_port_output): |
e803df70 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): | |
59225a3e | 140 | def __init__(self, config, params, obj): |
e803df70 SM |
141 | self._add_input_port('in') |
142 | self._add_output_port('out') | |
143 | ||
0a6d7302 | 144 | graph = _create_graph(MySource, SimpleSink, MyFilter) |
e803df70 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 | ||
811644b8 | 157 | def test_finalize(self): |
5602ef81 | 158 | class MyIter(bt2._UserMessageIterator): |
6a91742b | 159 | def _user_finalize(self): |
811644b8 PP |
160 | nonlocal finalized |
161 | finalized = True | |
162 | ||
cfbd7cf3 | 163 | class MySource(bt2._UserSourceComponent, message_iterator_class=MyIter): |
59225a3e | 164 | def __init__(self, config, params, obj): |
811644b8 PP |
165 | self._add_output_port('out') |
166 | ||
167 | finalized = False | |
0a6d7302 | 168 | graph = _create_graph(MySource, SimpleSink) |
c5f330cd | 169 | graph.run() |
811644b8 PP |
170 | del graph |
171 | self.assertTrue(finalized) | |
172 | ||
8d8b141d 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 | ||
811644b8 | 238 | def test_component(self): |
5602ef81 | 239 | class MyIter(bt2._UserMessageIterator): |
8d8b141d | 240 | def __init__(self, config, self_port_output): |
811644b8 PP |
241 | nonlocal salut |
242 | salut = self._component._salut | |
243 | ||
cfbd7cf3 | 244 | class MySource(bt2._UserSourceComponent, message_iterator_class=MyIter): |
59225a3e | 245 | def __init__(self, config, params, obj): |
811644b8 PP |
246 | self._add_output_port('out') |
247 | self._salut = 23 | |
248 | ||
249 | salut = None | |
0a6d7302 | 250 | graph = _create_graph(MySource, SimpleSink) |
c5f330cd | 251 | graph.run() |
811644b8 PP |
252 | self.assertEqual(salut, 23) |
253 | ||
14503fb1 SM |
254 | def test_port(self): |
255 | class MyIter(bt2._UserMessageIterator): | |
8d8b141d | 256 | def __init__(self_iter, config, self_port_output): |
14503fb1 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): | |
59225a3e | 265 | def __init__(self, config, params, obj): |
14503fb1 SM |
266 | self._add_output_port('out') |
267 | ||
268 | called = False | |
0a6d7302 | 269 | graph = _create_graph(MySource, SimpleSink) |
14503fb1 SM |
270 | graph.run() |
271 | self.assertTrue(called) | |
272 | ||
811644b8 | 273 | def test_addr(self): |
5602ef81 | 274 | class MyIter(bt2._UserMessageIterator): |
8d8b141d | 275 | def __init__(self, config, self_port_output): |
811644b8 PP |
276 | nonlocal addr |
277 | addr = self.addr | |
278 | ||
cfbd7cf3 | 279 | class MySource(bt2._UserSourceComponent, message_iterator_class=MyIter): |
59225a3e | 280 | def __init__(self, config, params, obj): |
811644b8 PP |
281 | self._add_output_port('out') |
282 | ||
283 | addr = None | |
0a6d7302 | 284 | graph = _create_graph(MySource, SimpleSink) |
c5f330cd | 285 | graph.run() |
811644b8 PP |
286 | self.assertIsNotNone(addr) |
287 | self.assertNotEqual(addr, 0) | |
288 | ||
d79a8353 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): | |
8d8b141d | 293 | def __init__(self, config, port): |
d79a8353 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), | |
d79a8353 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): | |
59225a3e | 313 | def __init__(self, config, params, obj): |
d79a8353 | 314 | tc = self._create_trace_class() |
26fc5aed | 315 | sc = tc.create_stream_class(supports_packets=True) |
d79a8353 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') | |
6c373cc9 | 321 | it = TestOutputPortMessageIterator(graph, src.output_ports['out']) |
d79a8353 SM |
322 | |
323 | # Skip beginning messages. | |
188edac1 | 324 | msg = next(it) |
f0a42b33 | 325 | self.assertIs(type(msg), bt2._StreamBeginningMessageConst) |
188edac1 | 326 | msg = next(it) |
f0a42b33 | 327 | self.assertIs(type(msg), bt2._PacketBeginningMessageConst) |
d79a8353 SM |
328 | |
329 | msg_ev1 = next(it) | |
330 | msg_ev2 = next(it) | |
331 | ||
f0a42b33 FD |
332 | self.assertIs(type(msg_ev1), bt2._EventMessageConst) |
333 | self.assertIs(type(msg_ev2), bt2._EventMessageConst) | |
d79a8353 SM |
334 | self.assertEqual(msg_ev1.addr, msg_ev2.addr) |
335 | ||
0a6d7302 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): | |
f00b8d40 | 341 | def __next__(self): |
0a6d7302 | 342 | raise bt2.TryAgain |
f00b8d40 | 343 | |
0a6d7302 | 344 | class MySource(bt2._UserSourceComponent, message_iterator_class=MyIter): |
59225a3e | 345 | def __init__(self, config, params, obj): |
0a6d7302 | 346 | self._add_output_port('out') |
f00b8d40 SM |
347 | |
348 | class MyFilterIter(bt2._UserMessageIterator): | |
349 | def __init__(self, port): | |
350 | input_port = port.user_data | |
ca02df0a PP |
351 | self._upstream_iter = self._create_input_port_message_iterator( |
352 | input_port | |
353 | ) | |
f00b8d40 SM |
354 | |
355 | def __next__(self): | |
356 | return next(self._upstream_iter) | |
357 | ||
6a91742b | 358 | def _user_seek_beginning(self): |
f00b8d40 SM |
359 | self._upstream_iter.seek_beginning() |
360 | ||
6a91742b | 361 | def _user_can_seek_beginning(self): |
14cfc8ce | 362 | return self._upstream_iter.can_seek_beginning() |
f00b8d40 SM |
363 | |
364 | class MyFilter(bt2._UserFilterComponent, message_iterator_class=MyFilterIter): | |
59225a3e | 365 | def __init__(self, config, params, obj): |
f00b8d40 SM |
366 | input_port = self._add_input_port('in') |
367 | self._add_output_port('out', input_port) | |
368 | ||
f00b8d40 SM |
369 | graph = bt2.Graph() |
370 | src = graph.add_component(MySource, 'src') | |
0a6d7302 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 | ||
382 | ||
c182d7dd SM |
383 | def _setup_seek_test( |
384 | sink_cls, | |
385 | user_seek_beginning=None, | |
386 | user_can_seek_beginning=None, | |
387 | user_seek_ns_from_origin=None, | |
388 | user_can_seek_ns_from_origin=None, | |
389 | ): | |
0a6d7302 | 390 | class MySourceIter(bt2._UserMessageIterator): |
8d8b141d | 391 | def __init__(self, config, port): |
0a6d7302 SM |
392 | tc, sc, ec = port.user_data |
393 | trace = tc() | |
394 | stream = trace.create_stream(sc) | |
395 | packet = stream.create_packet() | |
396 | ||
397 | self._msgs = [ | |
398 | self._create_stream_beginning_message(stream), | |
399 | self._create_packet_beginning_message(packet), | |
400 | self._create_event_message(ec, packet), | |
401 | self._create_event_message(ec, packet), | |
402 | self._create_packet_end_message(packet), | |
403 | self._create_stream_end_message(stream), | |
404 | ] | |
405 | self._at = 0 | |
406 | ||
407 | def __next__(self): | |
408 | if self._at < len(self._msgs): | |
409 | msg = self._msgs[self._at] | |
410 | self._at += 1 | |
411 | return msg | |
412 | else: | |
413 | raise StopIteration | |
414 | ||
415 | if user_seek_beginning is not None: | |
416 | MySourceIter._user_seek_beginning = user_seek_beginning | |
417 | ||
418 | if user_can_seek_beginning is not None: | |
14cfc8ce | 419 | MySourceIter._user_can_seek_beginning = user_can_seek_beginning |
0a6d7302 | 420 | |
c182d7dd SM |
421 | if user_seek_ns_from_origin is not None: |
422 | MySourceIter._user_seek_ns_from_origin = user_seek_ns_from_origin | |
423 | ||
424 | if user_can_seek_ns_from_origin is not None: | |
425 | MySourceIter._user_can_seek_ns_from_origin = user_can_seek_ns_from_origin | |
426 | ||
0a6d7302 | 427 | class MySource(bt2._UserSourceComponent, message_iterator_class=MySourceIter): |
59225a3e | 428 | def __init__(self, config, params, obj): |
0a6d7302 SM |
429 | tc = self._create_trace_class() |
430 | sc = tc.create_stream_class(supports_packets=True) | |
431 | ec = sc.create_event_class() | |
432 | ||
433 | self._add_output_port('out', (tc, sc, ec)) | |
434 | ||
435 | class MyFilterIter(bt2._UserMessageIterator): | |
8d8b141d | 436 | def __init__(self, config, port): |
0a6d7302 SM |
437 | self._upstream_iter = self._create_input_port_message_iterator( |
438 | self._component._input_ports['in'] | |
439 | ) | |
440 | ||
441 | def __next__(self): | |
442 | return next(self._upstream_iter) | |
443 | ||
0a6d7302 | 444 | def _user_can_seek_beginning(self): |
14cfc8ce | 445 | return self._upstream_iter.can_seek_beginning() |
0a6d7302 SM |
446 | |
447 | def _user_seek_beginning(self): | |
448 | self._upstream_iter.seek_beginning() | |
449 | ||
c182d7dd SM |
450 | def _user_can_seek_ns_from_origin(self, ns_from_origin): |
451 | return self._upstream_iter.can_seek_ns_from_origin(ns_from_origin) | |
452 | ||
453 | def _user_seek_ns_from_origin(self, ns_from_origin): | |
454 | self._upstream_iter.seek_ns_from_origin(ns_from_origin) | |
455 | ||
0a6d7302 | 456 | class MyFilter(bt2._UserFilterComponent, message_iterator_class=MyFilterIter): |
59225a3e | 457 | def __init__(self, config, params, obj): |
0a6d7302 SM |
458 | self._add_input_port('in') |
459 | self._add_output_port('out') | |
460 | ||
461 | return _create_graph(MySource, sink_cls, flt_comp_cls=MyFilter) | |
f00b8d40 | 462 | |
0a6d7302 SM |
463 | |
464 | class UserMessageIteratorSeekBeginningTestCase(unittest.TestCase): | |
f00b8d40 | 465 | def test_can_seek_beginning(self): |
6c373cc9 | 466 | class MySink(bt2._UserSinkComponent): |
59225a3e | 467 | def __init__(self, config, params, obj): |
6c373cc9 PP |
468 | self._add_input_port('in') |
469 | ||
470 | def _user_graph_is_configured(self): | |
471 | self._msg_iter = self._create_input_port_message_iterator( | |
472 | self._input_ports['in'] | |
473 | ) | |
474 | ||
475 | def _user_consume(self): | |
476 | nonlocal can_seek_beginning | |
14cfc8ce | 477 | can_seek_beginning = self._msg_iter.can_seek_beginning() |
6c373cc9 | 478 | |
6a91742b | 479 | def _user_can_seek_beginning(self): |
6c373cc9 PP |
480 | nonlocal input_port_iter_can_seek_beginning |
481 | return input_port_iter_can_seek_beginning | |
f00b8d40 | 482 | |
0a6d7302 SM |
483 | graph = _setup_seek_test( |
484 | MySink, user_can_seek_beginning=_user_can_seek_beginning | |
485 | ) | |
f00b8d40 | 486 | |
6c373cc9 PP |
487 | input_port_iter_can_seek_beginning = True |
488 | can_seek_beginning = None | |
489 | graph.run_once() | |
7f0c21bb | 490 | self.assertIs(can_seek_beginning, True) |
f00b8d40 | 491 | |
6c373cc9 PP |
492 | input_port_iter_can_seek_beginning = False |
493 | can_seek_beginning = None | |
494 | graph.run_once() | |
7f0c21bb | 495 | self.assertIs(can_seek_beginning, False) |
f00b8d40 | 496 | |
0a6d7302 SM |
497 | def test_no_can_seek_beginning_with_seek_beginning(self): |
498 | # Test an iterator without a _user_can_seek_beginning method, but with | |
499 | # a _user_seek_beginning method. | |
500 | class MySink(bt2._UserSinkComponent): | |
59225a3e | 501 | def __init__(self, config, params, obj): |
0a6d7302 SM |
502 | self._add_input_port('in') |
503 | ||
504 | def _user_graph_is_configured(self): | |
505 | self._msg_iter = self._create_input_port_message_iterator( | |
506 | self._input_ports['in'] | |
507 | ) | |
508 | ||
509 | def _user_consume(self): | |
510 | nonlocal can_seek_beginning | |
14cfc8ce | 511 | can_seek_beginning = self._msg_iter.can_seek_beginning() |
0a6d7302 SM |
512 | |
513 | def _user_seek_beginning(self): | |
514 | pass | |
f00b8d40 | 515 | |
0a6d7302 | 516 | graph = _setup_seek_test(MySink, user_seek_beginning=_user_seek_beginning) |
6c373cc9 PP |
517 | can_seek_beginning = None |
518 | graph.run_once() | |
7f0c21bb | 519 | self.assertIs(can_seek_beginning, True) |
f00b8d40 | 520 | |
0a6d7302 SM |
521 | def test_no_can_seek_beginning(self): |
522 | # Test an iterator without a _user_can_seek_beginning method, without | |
523 | # a _user_seek_beginning method. | |
524 | class MySink(bt2._UserSinkComponent): | |
59225a3e | 525 | def __init__(self, config, params, obj): |
0a6d7302 SM |
526 | self._add_input_port('in') |
527 | ||
528 | def _user_graph_is_configured(self): | |
529 | self._msg_iter = self._create_input_port_message_iterator( | |
530 | self._input_ports['in'] | |
531 | ) | |
532 | ||
533 | def _user_consume(self): | |
534 | nonlocal can_seek_beginning | |
14cfc8ce | 535 | can_seek_beginning = self._msg_iter.can_seek_beginning() |
0a6d7302 SM |
536 | |
537 | graph = _setup_seek_test(MySink) | |
6c373cc9 PP |
538 | can_seek_beginning = None |
539 | graph.run_once() | |
7f0c21bb | 540 | self.assertIs(can_seek_beginning, False) |
f00b8d40 | 541 | |
f2fb1b32 SM |
542 | def test_can_seek_beginning_user_error(self): |
543 | class MySink(bt2._UserSinkComponent): | |
59225a3e | 544 | def __init__(self, config, params, obj): |
f2fb1b32 SM |
545 | self._add_input_port('in') |
546 | ||
547 | def _user_graph_is_configured(self): | |
548 | self._msg_iter = self._create_input_port_message_iterator( | |
549 | self._input_ports['in'] | |
550 | ) | |
551 | ||
552 | def _user_consume(self): | |
553 | # This is expected to raise. | |
14cfc8ce | 554 | self._msg_iter.can_seek_beginning() |
f2fb1b32 SM |
555 | |
556 | def _user_can_seek_beginning(self): | |
557 | raise ValueError('moustiquaire') | |
558 | ||
559 | graph = _setup_seek_test( | |
560 | MySink, user_can_seek_beginning=_user_can_seek_beginning | |
561 | ) | |
562 | ||
563 | with self.assertRaises(bt2._Error) as ctx: | |
564 | graph.run_once() | |
565 | ||
566 | cause = ctx.exception[0] | |
567 | self.assertIn('ValueError: moustiquaire', cause.message) | |
568 | ||
569 | def test_can_seek_beginning_wrong_return_value(self): | |
570 | class MySink(bt2._UserSinkComponent): | |
59225a3e | 571 | def __init__(self, config, params, obj): |
f2fb1b32 SM |
572 | self._add_input_port('in') |
573 | ||
574 | def _user_graph_is_configured(self): | |
575 | self._msg_iter = self._create_input_port_message_iterator( | |
576 | self._input_ports['in'] | |
577 | ) | |
578 | ||
579 | def _user_consume(self): | |
580 | # This is expected to raise. | |
14cfc8ce | 581 | self._msg_iter.can_seek_beginning() |
f2fb1b32 SM |
582 | |
583 | def _user_can_seek_beginning(self): | |
584 | return 'Amqui' | |
585 | ||
586 | graph = _setup_seek_test( | |
587 | MySink, user_can_seek_beginning=_user_can_seek_beginning | |
588 | ) | |
589 | ||
590 | with self.assertRaises(bt2._Error) as ctx: | |
591 | graph.run_once() | |
592 | ||
593 | cause = ctx.exception[0] | |
594 | self.assertIn("TypeError: 'str' is not a 'bool' object", cause.message) | |
595 | ||
f00b8d40 | 596 | def test_seek_beginning(self): |
6c373cc9 | 597 | class MySink(bt2._UserSinkComponent): |
59225a3e | 598 | def __init__(self, config, params, obj): |
6c373cc9 | 599 | self._add_input_port('in') |
f00b8d40 | 600 | |
6c373cc9 PP |
601 | def _user_graph_is_configured(self): |
602 | self._msg_iter = self._create_input_port_message_iterator( | |
603 | self._input_ports['in'] | |
604 | ) | |
605 | ||
606 | def _user_consume(self): | |
607 | nonlocal do_seek_beginning | |
608 | nonlocal msg | |
609 | ||
610 | if do_seek_beginning: | |
611 | self._msg_iter.seek_beginning() | |
612 | return | |
613 | ||
614 | msg = next(self._msg_iter) | |
615 | ||
0a6d7302 SM |
616 | def _user_seek_beginning(self): |
617 | self._at = 0 | |
618 | ||
6c373cc9 | 619 | msg = None |
0a6d7302 SM |
620 | graph = _setup_seek_test(MySink, user_seek_beginning=_user_seek_beginning) |
621 | ||
622 | # Consume message. | |
623 | do_seek_beginning = False | |
6c373cc9 | 624 | graph.run_once() |
f0a42b33 | 625 | self.assertIs(type(msg), bt2._StreamBeginningMessageConst) |
0a6d7302 SM |
626 | |
627 | # Consume message. | |
6c373cc9 | 628 | graph.run_once() |
f0a42b33 | 629 | self.assertIs(type(msg), bt2._PacketBeginningMessageConst) |
0a6d7302 SM |
630 | |
631 | # Seek beginning. | |
6c373cc9 PP |
632 | do_seek_beginning = True |
633 | graph.run_once() | |
0a6d7302 SM |
634 | |
635 | # Consume message. | |
6c373cc9 PP |
636 | do_seek_beginning = False |
637 | graph.run_once() | |
f0a42b33 | 638 | self.assertIs(type(msg), bt2._StreamBeginningMessageConst) |
f00b8d40 | 639 | |
6c373cc9 PP |
640 | def test_seek_beginning_user_error(self): |
641 | class MySink(bt2._UserSinkComponent): | |
59225a3e | 642 | def __init__(self, config, params, obj): |
6c373cc9 | 643 | self._add_input_port('in') |
f00b8d40 | 644 | |
6c373cc9 PP |
645 | def _user_graph_is_configured(self): |
646 | self._msg_iter = self._create_input_port_message_iterator( | |
647 | self._input_ports['in'] | |
648 | ) | |
f00b8d40 | 649 | |
6c373cc9 PP |
650 | def _user_consume(self): |
651 | self._msg_iter.seek_beginning() | |
f00b8d40 | 652 | |
0a6d7302 | 653 | def _user_seek_beginning(self): |
cfbd7cf3 | 654 | raise ValueError('ouch') |
f00b8d40 | 655 | |
0a6d7302 | 656 | graph = _setup_seek_test(MySink, user_seek_beginning=_user_seek_beginning) |
f00b8d40 | 657 | |
694c792b | 658 | with self.assertRaises(bt2._Error): |
6c373cc9 | 659 | graph.run_once() |
f00b8d40 SM |
660 | |
661 | ||
c182d7dd SM |
662 | class UserMessageIteratorSeekNsFromOriginTestCase(unittest.TestCase): |
663 | def test_can_seek_ns_from_origin(self): | |
664 | class MySink(bt2._UserSinkComponent): | |
59225a3e | 665 | def __init__(self, config, params, obj): |
c182d7dd SM |
666 | self._add_input_port('in') |
667 | ||
668 | def _user_graph_is_configured(self): | |
669 | self._msg_iter = self._create_input_port_message_iterator( | |
670 | self._input_ports['in'] | |
671 | ) | |
672 | ||
673 | def _user_consume(self): | |
674 | nonlocal can_seek_ns_from_origin | |
675 | nonlocal test_ns_from_origin | |
676 | can_seek_ns_from_origin = self._msg_iter.can_seek_ns_from_origin( | |
677 | test_ns_from_origin | |
678 | ) | |
679 | ||
680 | def _user_can_seek_ns_from_origin(iter_self, ns_from_origin): | |
681 | nonlocal input_port_iter_can_seek_ns_from_origin | |
682 | nonlocal test_ns_from_origin | |
683 | self.assertEqual(ns_from_origin, test_ns_from_origin) | |
684 | return input_port_iter_can_seek_ns_from_origin | |
685 | ||
686 | graph = _setup_seek_test( | |
687 | MySink, user_can_seek_ns_from_origin=_user_can_seek_ns_from_origin | |
688 | ) | |
689 | ||
690 | input_port_iter_can_seek_ns_from_origin = True | |
691 | can_seek_ns_from_origin = None | |
692 | test_ns_from_origin = 1 | |
693 | graph.run_once() | |
694 | self.assertIs(can_seek_ns_from_origin, True) | |
695 | ||
696 | input_port_iter_can_seek_ns_from_origin = False | |
697 | can_seek_ns_from_origin = None | |
698 | test_ns_from_origin = 2 | |
699 | graph.run_once() | |
700 | self.assertIs(can_seek_ns_from_origin, False) | |
701 | ||
702 | def test_no_can_seek_ns_from_origin_with_seek_ns_from_origin(self): | |
703 | # Test an iterator without a _user_can_seek_ns_from_origin method, but | |
704 | # with a _user_seek_ns_from_origin method. | |
705 | class MySink(bt2._UserSinkComponent): | |
59225a3e | 706 | def __init__(self, config, params, obj): |
c182d7dd SM |
707 | self._add_input_port('in') |
708 | ||
709 | def _user_graph_is_configured(self): | |
710 | self._msg_iter = self._create_input_port_message_iterator( | |
711 | self._input_ports['in'] | |
712 | ) | |
713 | ||
714 | def _user_consume(self): | |
715 | nonlocal can_seek_ns_from_origin | |
716 | nonlocal test_ns_from_origin | |
717 | can_seek_ns_from_origin = self._msg_iter.can_seek_ns_from_origin( | |
718 | test_ns_from_origin | |
719 | ) | |
720 | ||
721 | def _user_seek_ns_from_origin(self): | |
722 | pass | |
723 | ||
724 | graph = _setup_seek_test( | |
725 | MySink, user_seek_ns_from_origin=_user_seek_ns_from_origin | |
726 | ) | |
727 | can_seek_ns_from_origin = None | |
728 | test_ns_from_origin = 2 | |
729 | graph.run_once() | |
730 | self.assertIs(can_seek_ns_from_origin, True) | |
731 | ||
732 | def test_no_can_seek_ns_from_origin_with_seek_beginning(self): | |
733 | # Test an iterator without a _user_can_seek_ns_from_origin method, but | |
734 | # with a _user_seek_beginning method. | |
735 | class MySink(bt2._UserSinkComponent): | |
59225a3e | 736 | def __init__(self, config, params, obj): |
c182d7dd SM |
737 | self._add_input_port('in') |
738 | ||
739 | def _user_graph_is_configured(self): | |
740 | self._msg_iter = self._create_input_port_message_iterator( | |
741 | self._input_ports['in'] | |
742 | ) | |
743 | ||
744 | def _user_consume(self): | |
745 | nonlocal can_seek_ns_from_origin | |
746 | nonlocal test_ns_from_origin | |
747 | can_seek_ns_from_origin = self._msg_iter.can_seek_ns_from_origin( | |
748 | test_ns_from_origin | |
749 | ) | |
750 | ||
751 | def _user_seek_beginning(self): | |
752 | pass | |
753 | ||
754 | graph = _setup_seek_test(MySink, user_seek_beginning=_user_seek_beginning) | |
755 | can_seek_ns_from_origin = None | |
756 | test_ns_from_origin = 2 | |
757 | graph.run_once() | |
758 | self.assertIs(can_seek_ns_from_origin, True) | |
759 | ||
760 | def test_no_can_seek_ns_from_origin(self): | |
761 | # Test an iterator without a _user_can_seek_ns_from_origin method | |
762 | # and no other related method. | |
763 | class MySink(bt2._UserSinkComponent): | |
59225a3e | 764 | def __init__(self, config, params, obj): |
c182d7dd SM |
765 | self._add_input_port('in') |
766 | ||
767 | def _user_graph_is_configured(self): | |
768 | self._msg_iter = self._create_input_port_message_iterator( | |
769 | self._input_ports['in'] | |
770 | ) | |
771 | ||
772 | def _user_consume(self): | |
773 | nonlocal can_seek_ns_from_origin | |
774 | nonlocal test_ns_from_origin | |
775 | can_seek_ns_from_origin = self._msg_iter.can_seek_ns_from_origin( | |
776 | test_ns_from_origin | |
777 | ) | |
778 | ||
779 | graph = _setup_seek_test(MySink) | |
780 | can_seek_ns_from_origin = None | |
781 | test_ns_from_origin = 2 | |
782 | graph.run_once() | |
783 | self.assertIs(can_seek_ns_from_origin, False) | |
784 | ||
785 | def test_can_seek_ns_from_origin_user_error(self): | |
786 | class MySink(bt2._UserSinkComponent): | |
59225a3e | 787 | def __init__(self, config, params, obj): |
c182d7dd SM |
788 | self._add_input_port('in') |
789 | ||
790 | def _user_graph_is_configured(self): | |
791 | self._msg_iter = self._create_input_port_message_iterator( | |
792 | self._input_ports['in'] | |
793 | ) | |
794 | ||
795 | def _user_consume(self): | |
796 | # This is expected to raise. | |
797 | self._msg_iter.can_seek_ns_from_origin(2) | |
798 | ||
799 | def _user_can_seek_ns_from_origin(self, ns_from_origin): | |
800 | raise ValueError('Joutel') | |
801 | ||
802 | graph = _setup_seek_test( | |
803 | MySink, user_can_seek_ns_from_origin=_user_can_seek_ns_from_origin | |
804 | ) | |
805 | ||
806 | with self.assertRaises(bt2._Error) as ctx: | |
807 | graph.run_once() | |
808 | ||
809 | cause = ctx.exception[0] | |
810 | self.assertIn('ValueError: Joutel', cause.message) | |
811 | ||
812 | def test_can_seek_ns_from_origin_wrong_return_value(self): | |
813 | class MySink(bt2._UserSinkComponent): | |
59225a3e | 814 | def __init__(self, config, params, obj): |
c182d7dd SM |
815 | self._add_input_port('in') |
816 | ||
817 | def _user_graph_is_configured(self): | |
818 | self._msg_iter = self._create_input_port_message_iterator( | |
819 | self._input_ports['in'] | |
820 | ) | |
821 | ||
822 | def _user_consume(self): | |
823 | # This is expected to raise. | |
824 | self._msg_iter.can_seek_ns_from_origin(2) | |
825 | ||
826 | def _user_can_seek_ns_from_origin(self, ns_from_origin): | |
827 | return 'Nitchequon' | |
828 | ||
829 | graph = _setup_seek_test( | |
830 | MySink, user_can_seek_ns_from_origin=_user_can_seek_ns_from_origin | |
831 | ) | |
832 | ||
833 | with self.assertRaises(bt2._Error) as ctx: | |
834 | graph.run_once() | |
835 | ||
836 | cause = ctx.exception[0] | |
837 | self.assertIn("TypeError: 'str' is not a 'bool' object", cause.message) | |
838 | ||
839 | def test_seek_ns_from_origin(self): | |
840 | class MySink(bt2._UserSinkComponent): | |
59225a3e | 841 | def __init__(self, config, params, obj): |
c182d7dd SM |
842 | self._add_input_port('in') |
843 | ||
844 | def _user_graph_is_configured(self): | |
845 | self._msg_iter = self._create_input_port_message_iterator( | |
846 | self._input_ports['in'] | |
847 | ) | |
848 | ||
849 | def _user_consume(self): | |
850 | self._msg_iter.seek_ns_from_origin(17) | |
851 | ||
852 | def _user_seek_ns_from_origin(self, ns_from_origin): | |
853 | nonlocal actual_ns_from_origin | |
854 | actual_ns_from_origin = ns_from_origin | |
855 | ||
856 | msg = None | |
857 | graph = _setup_seek_test( | |
858 | MySink, user_seek_ns_from_origin=_user_seek_ns_from_origin | |
859 | ) | |
860 | ||
861 | actual_ns_from_origin = None | |
862 | graph.run_once() | |
863 | self.assertEqual(actual_ns_from_origin, 17) | |
864 | ||
865 | ||
f00b8d40 SM |
866 | if __name__ == '__main__': |
867 | unittest.main() |