bt2: fix some whitespace issues
[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
c4239792 19from bt2 import value
548bb510 20import collections
811644b8
PP
21import unittest
22import copy
23import bt2
24
25
5602ef81 26class UserMessageIteratorTestCase(unittest.TestCase):
811644b8
PP
27 @staticmethod
28 def _create_graph(src_comp_cls):
29 class MySink(bt2._UserSinkComponent):
30 def __init__(self, params):
31 self._add_input_port('in')
32
33 def _consume(self):
5602ef81 34 next(self._msg_iter)
811644b8 35
c5f330cd
SM
36 def _graph_is_configured(self):
37 self._msg_iter = self._input_ports['in'].create_message_iterator()
811644b8
PP
38
39 graph = bt2.Graph()
40 src_comp = graph.add_component(src_comp_cls, 'src')
41 sink_comp = graph.add_component(MySink, 'sink')
cfbd7cf3 42 graph.connect_ports(src_comp.output_ports['out'], sink_comp.input_ports['in'])
811644b8
PP
43 return graph
44
45 def test_init(self):
c5f330cd
SM
46 the_output_port_from_source = None
47 the_output_port_from_iter = None
48
5602ef81 49 class MyIter(bt2._UserMessageIterator):
c5f330cd 50 def __init__(self, self_port_output):
811644b8 51 nonlocal initialized
c5f330cd 52 nonlocal the_output_port_from_iter
811644b8 53 initialized = True
c5f330cd 54 the_output_port_from_iter = self_port_output
811644b8 55
cfbd7cf3 56 class MySource(bt2._UserSourceComponent, message_iterator_class=MyIter):
811644b8 57 def __init__(self, params):
c5f330cd 58 nonlocal the_output_port_from_source
2e00bc76 59 the_output_port_from_source = self._add_output_port('out', 'user data')
811644b8
PP
60
61 initialized = False
62 graph = self._create_graph(MySource)
c5f330cd 63 graph.run()
811644b8 64 self.assertTrue(initialized)
cfbd7cf3
FD
65 self.assertEqual(
66 the_output_port_from_source.addr, the_output_port_from_iter.addr
67 )
2e00bc76 68 self.assertEqual(the_output_port_from_iter.user_data, 'user data')
811644b8
PP
69
70 def test_finalize(self):
5602ef81 71 class MyIter(bt2._UserMessageIterator):
811644b8
PP
72 def _finalize(self):
73 nonlocal finalized
74 finalized = True
75
cfbd7cf3 76 class MySource(bt2._UserSourceComponent, message_iterator_class=MyIter):
811644b8
PP
77 def __init__(self, params):
78 self._add_output_port('out')
79
80 finalized = False
81 graph = self._create_graph(MySource)
c5f330cd 82 graph.run()
811644b8
PP
83 del graph
84 self.assertTrue(finalized)
85
86 def test_component(self):
5602ef81 87 class MyIter(bt2._UserMessageIterator):
c5f330cd 88 def __init__(self, self_port_output):
811644b8
PP
89 nonlocal salut
90 salut = self._component._salut
91
cfbd7cf3 92 class MySource(bt2._UserSourceComponent, message_iterator_class=MyIter):
811644b8
PP
93 def __init__(self, params):
94 self._add_output_port('out')
95 self._salut = 23
96
97 salut = None
98 graph = self._create_graph(MySource)
c5f330cd 99 graph.run()
811644b8
PP
100 self.assertEqual(salut, 23)
101
102 def test_addr(self):
5602ef81 103 class MyIter(bt2._UserMessageIterator):
c5f330cd 104 def __init__(self, self_port_output):
811644b8
PP
105 nonlocal addr
106 addr = self.addr
107
cfbd7cf3 108 class MySource(bt2._UserSourceComponent, message_iterator_class=MyIter):
811644b8
PP
109 def __init__(self, params):
110 self._add_output_port('out')
111
112 addr = None
113 graph = self._create_graph(MySource)
c5f330cd 114 graph.run()
811644b8
PP
115 self.assertIsNotNone(addr)
116 self.assertNotEqual(addr, 0)
117
d79a8353
SM
118 # Test that messages returned by _UserMessageIterator.__next__ remain valid
119 # and can be re-used.
120 def test_reuse_message(self):
121 class MyIter(bt2._UserMessageIterator):
122 def __init__(self, port):
123 tc, sc, ec = port.user_data
124 trace = tc()
125 stream = trace.create_stream(sc)
126 packet = stream.create_packet()
127
128 # This message will be returned twice by __next__.
129 event_message = self._create_event_message(ec, packet)
130
131 self._msgs = [
132 self._create_stream_beginning_message(stream),
d79a8353
SM
133 self._create_packet_beginning_message(packet),
134 event_message,
135 event_message,
136 ]
137
138 def __next__(self):
139 return self._msgs.pop(0)
140
141 class MySource(bt2._UserSourceComponent, message_iterator_class=MyIter):
142 def __init__(self, params):
143 tc = self._create_trace_class()
26fc5aed 144 sc = tc.create_stream_class(supports_packets=True)
d79a8353
SM
145 ec = sc.create_event_class()
146 self._add_output_port('out', (tc, sc, ec))
147
148 graph = bt2.Graph()
149 src = graph.add_component(MySource, 'src')
150 it = graph.create_output_port_message_iterator(src.output_ports['out'])
151
152 # Skip beginning messages.
188edac1
SM
153 msg = next(it)
154 self.assertIsInstance(msg, bt2.message._StreamBeginningMessage)
155 msg = next(it)
156 self.assertIsInstance(msg, bt2.message._PacketBeginningMessage)
d79a8353
SM
157
158 msg_ev1 = next(it)
159 msg_ev2 = next(it)
160
161 self.assertIsInstance(msg_ev1, bt2.message._EventMessage)
162 self.assertIsInstance(msg_ev2, bt2.message._EventMessage)
163 self.assertEqual(msg_ev1.addr, msg_ev2.addr)
164
f00b8d40
SM
165 @staticmethod
166 def _setup_seek_beginning_test():
167 # Use a source, a filter and an output port iterator. This allows us
168 # to test calling `seek_beginning` on both a _OutputPortMessageIterator
169 # and a _UserComponentInputPortMessageIterator, on top of checking that
170 # _UserMessageIterator._seek_beginning is properly called.
171
172 class MySourceIter(bt2._UserMessageIterator):
173 def __init__(self, port):
174 tc, sc, ec = port.user_data
175 trace = tc()
176 stream = trace.create_stream(sc)
177 packet = stream.create_packet()
178
179 self._msgs = [
180 self._create_stream_beginning_message(stream),
f00b8d40
SM
181 self._create_packet_beginning_message(packet),
182 self._create_event_message(ec, packet),
183 self._create_event_message(ec, packet),
184 self._create_packet_end_message(packet),
f00b8d40
SM
185 self._create_stream_end_message(stream),
186 ]
187 self._at = 0
188
189 def _seek_beginning(self):
190 self._at = 0
191
192 def __next__(self):
193 if self._at < len(self._msgs):
194 msg = self._msgs[self._at]
195 self._at += 1
196 return msg
197 else:
198 raise StopIteration
199
cfbd7cf3 200 class MySource(bt2._UserSourceComponent, message_iterator_class=MySourceIter):
f00b8d40
SM
201 def __init__(self, params):
202 tc = self._create_trace_class()
26fc5aed 203 sc = tc.create_stream_class(supports_packets=True)
f00b8d40
SM
204 ec = sc.create_event_class()
205
206 self._add_output_port('out', (tc, sc, ec))
207
208 class MyFilterIter(bt2._UserMessageIterator):
209 def __init__(self, port):
210 input_port = port.user_data
211 self._upstream_iter = input_port.create_message_iterator()
212
213 def __next__(self):
214 return next(self._upstream_iter)
215
216 def _seek_beginning(self):
217 self._upstream_iter.seek_beginning()
218
219 @property
220 def _can_seek_beginning(self):
221 return self._upstream_iter.can_seek_beginning
222
223 class MyFilter(bt2._UserFilterComponent, message_iterator_class=MyFilterIter):
224 def __init__(self, params):
225 input_port = self._add_input_port('in')
226 self._add_output_port('out', input_port)
227
f00b8d40
SM
228 graph = bt2.Graph()
229 src = graph.add_component(MySource, 'src')
230 flt = graph.add_component(MyFilter, 'flt')
231 graph.connect_ports(src.output_ports['out'], flt.input_ports['in'])
232 it = graph.create_output_port_message_iterator(flt.output_ports['out'])
233
234 return it, MySourceIter
235
236 def test_can_seek_beginning(self):
237 it, MySourceIter = self._setup_seek_beginning_test()
238
239 def _can_seek_beginning(self):
240 nonlocal can_seek_beginning
241 return can_seek_beginning
242
243 MySourceIter._can_seek_beginning = property(_can_seek_beginning)
244
245 can_seek_beginning = True
246 self.assertTrue(it.can_seek_beginning)
247
248 can_seek_beginning = False
249 self.assertFalse(it.can_seek_beginning)
250
251 # Once can_seek_beginning returns an error, verify that it raises when
252 # _can_seek_beginning has/returns the wrong type.
253
254 # Remove the _can_seek_beginning method, we now rely on the presence of
255 # a _seek_beginning method to know whether the iterator can seek to
256 # beginning or not.
257 del MySourceIter._can_seek_beginning
258 self.assertTrue(it.can_seek_beginning)
259
260 del MySourceIter._seek_beginning
261 self.assertFalse(it.can_seek_beginning)
262
263 def test_seek_beginning(self):
264 it, MySourceIter = self._setup_seek_beginning_test()
265
266 msg = next(it)
267 self.assertIsInstance(msg, bt2.message._StreamBeginningMessage)
268 msg = next(it)
188edac1 269 self.assertIsInstance(msg, bt2.message._PacketBeginningMessage)
f00b8d40
SM
270
271 it.seek_beginning()
272
273 msg = next(it)
274 self.assertIsInstance(msg, bt2.message._StreamBeginningMessage)
275
276 # Verify that we can seek beginning after having reached the end.
277 #
278 # It currently does not work to seek an output port message iterator
279 # once it's ended, but we should eventually make it work and uncomment
280 # the following snippet.
281 #
282 # try:
283 # while True:
284 # next(it)
285 # except bt2.Stop:
286 # pass
287 #
288 # it.seek_beginning()
289 # msg = next(it)
290 # self.assertIsInstance(msg, bt2.message._StreamBeginningMessage)
291
292 def test_seek_beginning_user_error(self):
293 it, MySourceIter = self._setup_seek_beginning_test()
294
295 def _seek_beginning_error(self):
cfbd7cf3 296 raise ValueError('ouch')
f00b8d40
SM
297
298 MySourceIter._seek_beginning = _seek_beginning_error
299
694c792b 300 with self.assertRaises(bt2._Error):
f00b8d40
SM
301 it.seek_beginning()
302
0361868a
SM
303 # Try consuming many times from an iterator that always returns TryAgain.
304 # This verifies that we are not missing an incref of Py_None, making the
305 # refcount of Py_None reach 0.
306 def test_try_again_many_times(self):
307 class MyIter(bt2._UserMessageIterator):
308 def __next__(self):
309 raise bt2.TryAgain
310
311 class MySource(bt2._UserSourceComponent, message_iterator_class=MyIter):
312 def __init__(self, params):
313 self._add_output_port('out')
314
315 graph = bt2.Graph()
316 src = graph.add_component(MySource, 'src')
317 it = graph.create_output_port_message_iterator(src.output_ports['out'])
318
319 # The initial refcount of Py_None was in the 7000, so 100000 iterations
320 # should be enough to catch the bug even if there are small differences
321 # between configurations.
322 for i in range(100000):
323 with self.assertRaises(bt2.TryAgain):
324 next(it)
325
f00b8d40 326
5602ef81 327class OutputPortMessageIteratorTestCase(unittest.TestCase):
548bb510 328 def test_component(self):
5602ef81 329 class MyIter(bt2._UserMessageIterator):
c5f330cd 330 def __init__(self, self_port_output):
548bb510
PP
331 self._at = 0
332
548bb510 333 def __next__(self):
c5f330cd 334 if self._at == 7:
548bb510
PP
335 raise bt2.Stop
336
c5f330cd
SM
337 if self._at == 0:
338 msg = self._create_stream_beginning_message(test_obj._stream)
339 elif self._at == 1:
340 msg = self._create_packet_beginning_message(test_obj._packet)
341 elif self._at == 5:
342 msg = self._create_packet_end_message(test_obj._packet)
343 elif self._at == 6:
344 msg = self._create_stream_end_message(test_obj._stream)
345 else:
cfbd7cf3
FD
346 msg = self._create_event_message(
347 test_obj._event_class, test_obj._packet
348 )
c5f330cd
SM
349 msg.event.payload_field['my_int'] = self._at * 3
350
548bb510 351 self._at += 1
5602ef81 352 return msg
548bb510 353
cfbd7cf3 354 class MySource(bt2._UserSourceComponent, message_iterator_class=MyIter):
548bb510
PP
355 def __init__(self, params):
356 self._add_output_port('out')
357
c5f330cd 358 trace_class = self._create_trace_class()
26fc5aed 359 stream_class = trace_class.create_stream_class(supports_packets=True)
c5f330cd
SM
360
361 # Create payload field class
362 my_int_ft = trace_class.create_signed_integer_field_class(32)
363 payload_ft = trace_class.create_structure_field_class()
cfbd7cf3 364 payload_ft += [('my_int', my_int_ft)]
c5f330cd 365
cfbd7cf3
FD
366 event_class = stream_class.create_event_class(
367 name='salut', payload_field_class=payload_ft
368 )
c5f330cd
SM
369
370 trace = trace_class()
371 stream = trace.create_stream(stream_class)
372 packet = stream.create_packet()
373
374 test_obj._event_class = event_class
375 test_obj._stream = stream
376 test_obj._packet = packet
377
378 test_obj = self
548bb510
PP
379 graph = bt2.Graph()
380 src = graph.add_component(MySource, 'src')
c5f330cd 381 msg_iter = graph.create_output_port_message_iterator(src.output_ports['out'])
548bb510 382
5602ef81 383 for at, msg in enumerate(msg_iter):
c5f330cd
SM
384 if at == 0:
385 self.assertIsInstance(msg, bt2.message._StreamBeginningMessage)
386 elif at == 1:
387 self.assertIsInstance(msg, bt2.message._PacketBeginningMessage)
388 elif at == 5:
389 self.assertIsInstance(msg, bt2.message._PacketEndMessage)
390 elif at == 6:
391 self.assertIsInstance(msg, bt2.message._StreamEndMessage)
392 else:
393 self.assertIsInstance(msg, bt2.message._EventMessage)
e8ac1aae 394 self.assertEqual(msg.event.cls.name, 'salut')
c5f330cd
SM
395 field = msg.event.payload_field['my_int']
396 self.assertEqual(field, at * 3)
f00b8d40 397
cfbd7cf3 398
f00b8d40
SM
399if __name__ == '__main__':
400 unittest.main()
This page took 0.05215 seconds and 4 git commands to generate.