2 # Copyright (C) 2019 EfficiOS Inc.
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; only version 2
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 class UserMessageIteratorTestCase(unittest
.TestCase
):
28 def _create_graph(src_comp_cls
, flt_comp_cls
=None):
29 class MySink(bt2
._UserSinkComponent
):
30 def __init__(self
, params
, obj
):
31 self
._add
_input
_port
('in')
33 def _user_consume(self
):
36 def _user_graph_is_configured(self
):
37 self
._msg
_iter
= self
._create
_input
_port
_message
_iterator
(
38 self
._input
_ports
['in']
42 src_comp
= graph
.add_component(src_comp_cls
, 'src')
44 if flt_comp_cls
is not None:
45 flt_comp
= graph
.add_component(flt_comp_cls
, 'flt')
47 sink_comp
= graph
.add_component(MySink
, 'sink')
49 if flt_comp_cls
is not None:
50 assert flt_comp
is not None
52 src_comp
.output_ports
['out'], flt_comp
.input_ports
['in']
54 out_port
= flt_comp
.output_ports
['out']
56 out_port
= src_comp
.output_ports
['out']
58 graph
.connect_ports(out_port
, sink_comp
.input_ports
['in'])
62 the_output_port_from_source
= None
63 the_output_port_from_iter
= None
65 class MyIter(bt2
._UserMessageIterator
):
66 def __init__(self
, self_port_output
):
68 nonlocal the_output_port_from_iter
70 the_output_port_from_iter
= self_port_output
72 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
73 def __init__(self
, params
, obj
):
74 nonlocal the_output_port_from_source
75 the_output_port_from_source
= self
._add
_output
_port
('out', 'user data')
78 graph
= self
._create
_graph
(MySource
)
80 self
.assertTrue(initialized
)
82 the_output_port_from_source
.addr
, the_output_port_from_iter
.addr
84 self
.assertEqual(the_output_port_from_iter
.user_data
, 'user data')
86 def test_create_from_message_iterator(self
):
87 class MySourceIter(bt2
._UserMessageIterator
):
88 def __init__(self
, self_port_output
):
89 nonlocal src_iter_initialized
90 src_iter_initialized
= True
92 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MySourceIter
):
93 def __init__(self
, params
, obj
):
94 self
._add
_output
_port
('out')
96 class MyFilterIter(bt2
._UserMessageIterator
):
97 def __init__(self
, self_port_output
):
98 nonlocal flt_iter_initialized
99 flt_iter_initialized
= True
100 self
._up
_iter
= self
._create
_input
_port
_message
_iterator
(
101 self
._component
._input
_ports
['in']
105 return next(self
._up
_iter
)
107 class MyFilter(bt2
._UserFilterComponent
, message_iterator_class
=MyFilterIter
):
108 def __init__(self
, params
, obj
):
109 self
._add
_input
_port
('in')
110 self
._add
_output
_port
('out')
112 src_iter_initialized
= False
113 flt_iter_initialized
= False
114 graph
= self
._create
_graph
(MySource
, MyFilter
)
116 self
.assertTrue(src_iter_initialized
)
117 self
.assertTrue(flt_iter_initialized
)
119 def test_finalize(self
):
120 class MyIter(bt2
._UserMessageIterator
):
121 def _user_finalize(self
):
125 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
126 def __init__(self
, params
, obj
):
127 self
._add
_output
_port
('out')
130 graph
= self
._create
_graph
(MySource
)
133 self
.assertTrue(finalized
)
135 def test_component(self
):
136 class MyIter(bt2
._UserMessageIterator
):
137 def __init__(self
, self_port_output
):
139 salut
= self
._component
._salut
141 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
142 def __init__(self
, params
, obj
):
143 self
._add
_output
_port
('out')
147 graph
= self
._create
_graph
(MySource
)
149 self
.assertEqual(salut
, 23)
152 class MyIter(bt2
._UserMessageIterator
):
153 def __init__(self
, self_port_output
):
157 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
158 def __init__(self
, params
, obj
):
159 self
._add
_output
_port
('out')
162 graph
= self
._create
_graph
(MySource
)
164 self
.assertIsNotNone(addr
)
165 self
.assertNotEqual(addr
, 0)
167 # Test that messages returned by _UserMessageIterator.__next__ remain valid
168 # and can be re-used.
169 def test_reuse_message(self
):
170 class MyIter(bt2
._UserMessageIterator
):
171 def __init__(self
, port
):
172 tc
, sc
, ec
= port
.user_data
174 stream
= trace
.create_stream(sc
)
175 packet
= stream
.create_packet()
177 # This message will be returned twice by __next__.
178 event_message
= self
._create
_event
_message
(ec
, packet
)
181 self
._create
_stream
_beginning
_message
(stream
),
182 self
._create
_packet
_beginning
_message
(packet
),
188 return self
._msgs
.pop(0)
190 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
191 def __init__(self
, params
, obj
):
192 tc
= self
._create
_trace
_class
()
193 sc
= tc
.create_stream_class(supports_packets
=True)
194 ec
= sc
.create_event_class()
195 self
._add
_output
_port
('out', (tc
, sc
, ec
))
198 src
= graph
.add_component(MySource
, 'src')
199 it
= graph
.create_output_port_message_iterator(src
.output_ports
['out'])
201 # Skip beginning messages.
203 self
.assertIsInstance(msg
, bt2
._StreamBeginningMessage
)
205 self
.assertIsInstance(msg
, bt2
._PacketBeginningMessage
)
210 self
.assertIsInstance(msg_ev1
, bt2
._EventMessage
)
211 self
.assertIsInstance(msg_ev2
, bt2
._EventMessage
)
212 self
.assertEqual(msg_ev1
.addr
, msg_ev2
.addr
)
215 def _setup_seek_beginning_test():
216 # Use a source, a filter and an output port iterator. This allows us
217 # to test calling `seek_beginning` on both a _OutputPortMessageIterator
218 # and a _UserComponentInputPortMessageIterator, on top of checking that
219 # _UserMessageIterator._seek_beginning is properly called.
221 class MySourceIter(bt2
._UserMessageIterator
):
222 def __init__(self
, port
):
223 tc
, sc
, ec
= port
.user_data
225 stream
= trace
.create_stream(sc
)
226 packet
= stream
.create_packet()
229 self
._create
_stream
_beginning
_message
(stream
),
230 self
._create
_packet
_beginning
_message
(packet
),
231 self
._create
_event
_message
(ec
, packet
),
232 self
._create
_event
_message
(ec
, packet
),
233 self
._create
_packet
_end
_message
(packet
),
234 self
._create
_stream
_end
_message
(stream
),
238 def _user_seek_beginning(self
):
242 if self
._at
< len(self
._msgs
):
243 msg
= self
._msgs
[self
._at
]
249 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MySourceIter
):
250 def __init__(self
, params
, obj
):
251 tc
= self
._create
_trace
_class
()
252 sc
= tc
.create_stream_class(supports_packets
=True)
253 ec
= sc
.create_event_class()
255 self
._add
_output
_port
('out', (tc
, sc
, ec
))
257 class MyFilterIter(bt2
._UserMessageIterator
):
258 def __init__(self
, port
):
259 input_port
= port
.user_data
260 self
._upstream
_iter
= self
._create
_input
_port
_message
_iterator
(
265 return next(self
._upstream
_iter
)
267 def _user_seek_beginning(self
):
268 self
._upstream
_iter
.seek_beginning()
271 def _user_can_seek_beginning(self
):
272 return self
._upstream
_iter
.can_seek_beginning
274 class MyFilter(bt2
._UserFilterComponent
, message_iterator_class
=MyFilterIter
):
275 def __init__(self
, params
, obj
):
276 input_port
= self
._add
_input
_port
('in')
277 self
._add
_output
_port
('out', input_port
)
280 src
= graph
.add_component(MySource
, 'src')
281 flt
= graph
.add_component(MyFilter
, 'flt')
282 graph
.connect_ports(src
.output_ports
['out'], flt
.input_ports
['in'])
283 it
= graph
.create_output_port_message_iterator(flt
.output_ports
['out'])
285 return it
, MySourceIter
287 def test_can_seek_beginning(self
):
288 it
, MySourceIter
= self
._setup
_seek
_beginning
_test
()
290 def _user_can_seek_beginning(self
):
291 nonlocal can_seek_beginning
292 return can_seek_beginning
294 MySourceIter
._user
_can
_seek
_beginning
= property(_user_can_seek_beginning
)
296 can_seek_beginning
= True
297 self
.assertTrue(it
.can_seek_beginning
)
299 can_seek_beginning
= False
300 self
.assertFalse(it
.can_seek_beginning
)
302 # Once can_seek_beginning returns an error, verify that it raises when
303 # _can_seek_beginning has/returns the wrong type.
305 # Remove the _can_seek_beginning method, we now rely on the presence of
306 # a _seek_beginning method to know whether the iterator can seek to
308 del MySourceIter
._user
_can
_seek
_beginning
309 self
.assertTrue(it
.can_seek_beginning
)
311 del MySourceIter
._user
_seek
_beginning
312 self
.assertFalse(it
.can_seek_beginning
)
314 def test_seek_beginning(self
):
315 it
, MySourceIter
= self
._setup
_seek
_beginning
_test
()
318 self
.assertIsInstance(msg
, bt2
._StreamBeginningMessage
)
320 self
.assertIsInstance(msg
, bt2
._PacketBeginningMessage
)
325 self
.assertIsInstance(msg
, bt2
._StreamBeginningMessage
)
327 # Verify that we can seek beginning after having reached the end.
329 # It currently does not work to seek an output port message iterator
330 # once it's ended, but we should eventually make it work and uncomment
331 # the following snippet.
339 # it.seek_beginning()
341 # self.assertIsInstance(msg, bt2._StreamBeginningMessage)
343 def test_seek_beginning_user_error(self
):
344 it
, MySourceIter
= self
._setup
_seek
_beginning
_test
()
346 def _user_seek_beginning_error(self
):
347 raise ValueError('ouch')
349 MySourceIter
._user
_seek
_beginning
= _user_seek_beginning_error
351 with self
.assertRaises(bt2
._Error
):
354 # Try consuming many times from an iterator that always returns TryAgain.
355 # This verifies that we are not missing an incref of Py_None, making the
356 # refcount of Py_None reach 0.
357 def test_try_again_many_times(self
):
358 class MyIter(bt2
._UserMessageIterator
):
362 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
363 def __init__(self
, params
, obj
):
364 self
._add
_output
_port
('out')
367 src
= graph
.add_component(MySource
, 'src')
368 it
= graph
.create_output_port_message_iterator(src
.output_ports
['out'])
370 # The initial refcount of Py_None was in the 7000, so 100000 iterations
371 # should be enough to catch the bug even if there are small differences
372 # between configurations.
373 for i
in range(100000):
374 with self
.assertRaises(bt2
.TryAgain
):
378 class OutputPortMessageIteratorTestCase(unittest
.TestCase
):
379 def test_component(self
):
380 class MyIter(bt2
._UserMessageIterator
):
381 def __init__(self
, self_port_output
):
389 msg
= self
._create
_stream
_beginning
_message
(test_obj
._stream
)
391 msg
= self
._create
_packet
_beginning
_message
(test_obj
._packet
)
393 msg
= self
._create
_packet
_end
_message
(test_obj
._packet
)
395 msg
= self
._create
_stream
_end
_message
(test_obj
._stream
)
397 msg
= self
._create
_event
_message
(
398 test_obj
._event
_class
, test_obj
._packet
400 msg
.event
.payload_field
['my_int'] = self
._at
* 3
405 class MySource(bt2
._UserSourceComponent
, message_iterator_class
=MyIter
):
406 def __init__(self
, params
, obj
):
407 self
._add
_output
_port
('out')
409 trace_class
= self
._create
_trace
_class
()
410 stream_class
= trace_class
.create_stream_class(supports_packets
=True)
412 # Create payload field class
413 my_int_ft
= trace_class
.create_signed_integer_field_class(32)
414 payload_ft
= trace_class
.create_structure_field_class()
415 payload_ft
+= [('my_int', my_int_ft
)]
417 event_class
= stream_class
.create_event_class(
418 name
='salut', payload_field_class
=payload_ft
421 trace
= trace_class()
422 stream
= trace
.create_stream(stream_class
)
423 packet
= stream
.create_packet()
425 test_obj
._event
_class
= event_class
426 test_obj
._stream
= stream
427 test_obj
._packet
= packet
431 src
= graph
.add_component(MySource
, 'src')
432 msg_iter
= graph
.create_output_port_message_iterator(src
.output_ports
['out'])
434 for at
, msg
in enumerate(msg_iter
):
436 self
.assertIsInstance(msg
, bt2
._StreamBeginningMessage
)
438 self
.assertIsInstance(msg
, bt2
._PacketBeginningMessage
)
440 self
.assertIsInstance(msg
, bt2
._PacketEndMessage
)
442 self
.assertIsInstance(msg
, bt2
._StreamEndMessage
)
444 self
.assertIsInstance(msg
, bt2
._EventMessage
)
445 self
.assertEqual(msg
.event
.cls
.name
, 'salut')
446 field
= msg
.event
.payload_field
['my_int']
447 self
.assertEqual(field
, at
* 3)
450 if __name__
== '__main__':