bt2: Add remaining trace-ir `*Const` classes and adapt tests
[babeltrace.git] / tests / bindings / python / bt2 / utils.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
fbbe9302 19import bt2
6c373cc9 20import collections.abc
fbbe9302 21
2287be69 22
fbbe9302
SM
23# Run callable `func` in the context of a component's __init__ method. The
24# callable is passed the Component being instantiated.
25#
26# The value returned by the callable is returned by run_in_component_init.
fbbe9302
SM
27def run_in_component_init(func):
28 class MySink(bt2._UserSinkComponent):
66964f3f 29 def __init__(self, params, obj):
fbbe9302
SM
30 nonlocal res_bound
31 res_bound = func(self)
32
6a91742b 33 def _user_consume(self):
a01b452b
SM
34 pass
35
fbbe9302
SM
36 g = bt2.Graph()
37 res_bound = None
38 g.add_component(MySink, 'comp')
39
40 # We deliberately use a different variable for returning the result than
41 # the variable bound to the MySink.__init__ context and delete res_bound.
42 # The MySink.__init__ context stays alive until the end of the program, so
43 # if res_bound were to still point to our result, it would contribute an
44 # unexpected reference to the refcount of the result, from the point of view
45 # of the user of this function. It would then affect destruction tests,
46 # for example, which want to test what happens when the refcount of a Python
47 # object reaches 0.
48
49 res = res_bound
50 del res_bound
51 return res
52
cfbd7cf3 53
fbbe9302 54# Create an empty trace class with default values.
fbbe9302
SM
55def get_default_trace_class():
56 def f(comp_self):
57 return comp_self._create_trace_class()
58
59 return run_in_component_init(f)
6c373cc9
PP
60
61
f0a42b33
FD
62# Create a pair of list, one containing non-const messages and the other
63# containing const messages
64def _get_all_message_types(with_packet=True):
65 _msgs = None
66
67 class MyIter(bt2._UserMessageIterator):
68 def __init__(self, self_output_port):
69
70 nonlocal _msgs
71 self._at = 0
72 self._msgs = [
73 self._create_stream_beginning_message(
74 self_output_port.user_data['stream']
75 )
76 ]
77
78 if with_packet:
79 assert self_output_port.user_data['packet']
80 self._msgs.append(
81 self._create_packet_beginning_message(
82 self_output_port.user_data['packet']
83 )
84 )
85
86 default_clock_snapshot = 789
87
88 if with_packet:
89 assert self_output_port.user_data['packet']
90 ev_parent = self_output_port.user_data['packet']
91 else:
92 assert self_output_port.user_data['stream']
93 ev_parent = self_output_port.user_data['stream']
94
95 msg = self._create_event_message(
96 self_output_port.user_data['event_class'],
97 ev_parent,
98 default_clock_snapshot,
99 )
100
101 msg.event.payload_field['giraffe'] = 1
102 msg.event.specific_context_field['ant'] = -1
103 msg.event.common_context_field['cpu_id'] = 1
104 self._msgs.append(msg)
105
106 if with_packet:
107 self._msgs.append(
108 self._create_packet_end_message(
109 self_output_port.user_data['packet']
110 )
111 )
112
113 self._msgs.append(
114 self._create_stream_end_message(self_output_port.user_data['stream'])
115 )
116
117 _msgs = self._msgs
118
119 def __next__(self):
120 if self._at == len(self._msgs):
121 raise bt2.Stop
122
123 msg = self._msgs[self._at]
124 self._at += 1
125 return msg
126
127 class MySrc(bt2._UserSourceComponent, message_iterator_class=MyIter):
128 def __init__(self, params, obj):
129 tc = self._create_trace_class()
130 clock_class = self._create_clock_class(frequency=1000)
131
132 # event common context (stream-class-defined)
133 cc = tc.create_structure_field_class()
134 cc += [('cpu_id', tc.create_signed_integer_field_class(8))]
135
136 # packet context (stream-class-defined)
137 pc = None
138
139 if with_packet:
140 pc = tc.create_structure_field_class()
141 pc += [('something', tc.create_unsigned_integer_field_class(8))]
142
143 stream_class = tc.create_stream_class(
144 default_clock_class=clock_class,
145 event_common_context_field_class=cc,
146 packet_context_field_class=pc,
147 supports_packets=with_packet,
148 )
149
150 # specific context (event-class-defined)
151 sc = tc.create_structure_field_class()
152 sc += [('ant', tc.create_signed_integer_field_class(16))]
153
154 # event payload
155 ep = tc.create_structure_field_class()
156 ep += [('giraffe', tc.create_signed_integer_field_class(32))]
157
158 event_class = stream_class.create_event_class(
159 name='garou', specific_context_field_class=sc, payload_field_class=ep
160 )
161
162 trace = tc(environment={'patate': 12})
163 stream = trace.create_stream(stream_class, user_attributes={'salut': 23})
164
165 if with_packet:
166 packet = stream.create_packet()
167 packet.context_field['something'] = 154
168 else:
169 packet = None
170
171 self._add_output_port(
172 'out',
173 {
174 'tc': tc,
175 'stream': stream,
176 'event_class': event_class,
177 'trace': trace,
178 'packet': packet,
179 },
180 )
181
182 _graph = bt2.Graph()
183 _src_comp = _graph.add_component(MySrc, 'my_source')
184 _msg_iter = TestOutputPortMessageIterator(_graph, _src_comp.output_ports['out'])
185
186 const_msgs = list(_msg_iter)
187
188 return _msgs, const_msgs
189
190
191def get_stream_beginning_message():
192 msgs, _ = _get_all_message_types()
193 for m in msgs:
194 if type(m) is bt2._StreamBeginningMessage:
195 return m
196
197
198def get_const_stream_beginning_message():
199 _, const_msgs = _get_all_message_types()
200 for m in const_msgs:
201 if type(m) is bt2._StreamBeginningMessageConst:
202 return m
203
204
205def get_stream_end_message():
206 msgs, _ = _get_all_message_types()
207 for m in msgs:
208 if type(m) is bt2._StreamEndMessage:
209 return m
210
211
212def get_packet_beginning_message():
213 msgs, _ = _get_all_message_types(with_packet=True)
214 for m in msgs:
215 if type(m) is bt2._PacketBeginningMessage:
216 return m
217
218
219def get_const_packet_beginning_message():
220 _, const_msgs = _get_all_message_types(with_packet=True)
221 for m in const_msgs:
222 if type(m) is bt2._PacketBeginningMessageConst:
223 return m
224
225
226def get_packet_end_message():
227 msgs, _ = _get_all_message_types(with_packet=True)
228 for m in msgs:
229 if type(m) is bt2._PacketEndMessage:
230 return m
231
232
233def get_event_message():
234 msgs, _ = _get_all_message_types()
235 for m in msgs:
236 if type(m) is bt2._EventMessage:
237 return m
238
239
240def get_const_event_message():
241 _, const_msgs = _get_all_message_types()
242 for m in const_msgs:
243 if type(m) is bt2._EventMessageConst:
244 return m
245
246
6c373cc9
PP
247# Proxy sink component class.
248#
249# This sink accepts a list of a single item as its initialization
250# object. This sink creates a single input port `in`. When it consumes
251# from this port, it puts the returned message in the initialization
252# list as the first item.
253class TestProxySink(bt2._UserSinkComponent):
254 def __init__(self, params, msg_list):
255 assert msg_list is not None
256 self._msg_list = msg_list
257 self._add_input_port('in')
258
259 def _user_graph_is_configured(self):
260 self._msg_iter = self._create_input_port_message_iterator(
261 self._input_ports['in']
262 )
263
264 def _user_consume(self):
265 assert self._msg_list[0] is None
266 self._msg_list[0] = next(self._msg_iter)
267
268
269# This is a helper message iterator for tests.
270#
271# The constructor accepts a graph and an output port.
272#
273# Internally, it adds a proxy sink to the graph and connects the
274# received output port to the proxy sink's input port. Its __next__()
275# method then uses the proxy sink to transfer the consumed message to
276# the output port message iterator's user.
277#
278# This message iterator cannot seek.
279class TestOutputPortMessageIterator(collections.abc.Iterator):
280 def __init__(self, graph, output_port):
281 self._graph = graph
282 self._msg_list = [None]
283 sink = graph.add_component(TestProxySink, 'test-proxy-sink', obj=self._msg_list)
284 graph.connect_ports(output_port, sink.input_ports['in'])
285
286 def __next__(self):
287 assert self._msg_list[0] is None
288 self._graph.run_once()
289 msg = self._msg_list[0]
290 assert msg is not None
291 self._msg_list[0] = None
292 return msg
This page took 0.041626 seconds and 4 git commands to generate.