lib: pass config objects to component init methods
[babeltrace.git] / tests / bindings / python / bt2 / utils.py
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
19 import bt2
20 import collections.abc
21
22
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.
27 def run_in_component_init(func):
28 class MySink(bt2._UserSinkComponent):
29 def __init__(self, config, params, obj):
30 nonlocal res_bound
31 res_bound = func(self)
32
33 def _user_consume(self):
34 pass
35
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
53
54 # Create an empty trace class with default values.
55 def get_default_trace_class():
56 def f(comp_self):
57 return comp_self._create_trace_class()
58
59 return run_in_component_init(f)
60
61
62 # Create a pair of list, one containing non-const messages and the other
63 # containing const messages
64 def _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, config, 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
191 def 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
198 def 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
205 def 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
212 def 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
219 def 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
226 def 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
233 def 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
240 def 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
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.
253 class TestProxySink(bt2._UserSinkComponent):
254 def __init__(self, config, 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.
279 class 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.035494 seconds and 4 git commands to generate.