tests: test_ust_constructor: Split test_ust_constructor binary
[lttng-tools.git] / tests / regression / ust / ust-constructor / test_ust_constructor.py
1 #!/usr/bin/env python3
2 #
3 # Copyright (C) 2022 Jérémie Galarneau <jeremie.galarneau@efficios.com>
4 # Copyright (C) 2023 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
5 #
6 # SPDX-License-Identifier: GPL-2.0-only
7
8 import copy
9 import pathlib
10 import sys
11 import os
12 import subprocess
13 from typing import Any, Callable, Type
14
15 """
16 Test instrumentation coverage of C/C++ constructors and destructors by LTTng-UST
17 tracepoints.
18
19 This test successively sets up a session, traces a test application, and then
20 reads the resulting trace to determine if all the expected events are present.
21 """
22
23 # Import in-tree test utils
24 test_utils_import_path = pathlib.Path(__file__).absolute().parents[3] / "utils"
25 sys.path.append(str(test_utils_import_path))
26
27 import lttngtest
28 import bt2
29
30 # Determine if LTTNG_UST_ALLOCATE_COMPOUND_LITERAL_ON_HEAP is set. This will
31 # affect if certain events may or may not be expected when compiling with
32 # C++.
33 # @see https://github.com/lttng/lttng-ust/blob/47fa3e4ed7ab43e034dc61fc1480f919f4ee51d0/include/lttng/ust-compiler.h#L51
34 #
35 compound_literal_on_heap = False
36 process = subprocess.Popen(
37 [
38 os.path.join(
39 str(test_utils_import_path),
40 "testapp",
41 "gen-ust-events-constructor",
42 "uses_heap",
43 )
44 ]
45 )
46 process.wait()
47 if process.returncode == 0:
48 compound_literal_on_heap = True
49
50 expected_events_common = [
51 {
52 "name": "tp:constructor_c_across_units_before_define",
53 "msg": None,
54 "count": 0,
55 "may_fail": compound_literal_on_heap,
56 },
57 {
58 "name": "tp:constructor_cplusplus",
59 "msg": "global - across units before define",
60 "count": 0,
61 "may_fail": compound_literal_on_heap,
62 },
63 {
64 "name": "tp:constructor_c_same_unit_before_define",
65 "msg": None,
66 "count": 0,
67 "may_fail": compound_literal_on_heap,
68 },
69 {
70 "name": "tp:constructor_c_same_unit_after_define",
71 "msg": None,
72 "count": 0,
73 "may_fail": compound_literal_on_heap,
74 },
75 {
76 "name": "tp:constructor_cplusplus",
77 "msg": "global - same unit before define",
78 "count": 0,
79 "may_fail": compound_literal_on_heap,
80 },
81 {
82 "name": "tp:constructor_cplusplus",
83 "msg": "global - same unit after define",
84 "count": 0,
85 "may_fail": compound_literal_on_heap,
86 },
87 {
88 "name": "tp:constructor_c_across_units_after_define",
89 "msg": None,
90 "count": 0,
91 "may_fail": compound_literal_on_heap,
92 },
93 {
94 "name": "tp:constructor_cplusplus",
95 "msg": "global - across units after define",
96 "count": 0,
97 "may_fail": compound_literal_on_heap,
98 },
99 {
100 "name": "tp:constructor_c_same_unit_before_provider",
101 "msg": None,
102 "count": 0,
103 "may_fail": compound_literal_on_heap,
104 },
105 {
106 "name": "tp:constructor_c_same_unit_after_provider",
107 "msg": None,
108 "count": 0,
109 "may_fail": compound_literal_on_heap,
110 },
111 {
112 "name": "tp:constructor_cplusplus",
113 "msg": "global - same unit before provider",
114 "count": 0,
115 "may_fail": compound_literal_on_heap,
116 },
117 {
118 "name": "tp:constructor_cplusplus",
119 "msg": "global - same unit after provider",
120 "count": 0,
121 },
122 {"name": "tp:constructor_c_across_units_after_provider", "msg": None, "count": 0},
123 {
124 "name": "tp:constructor_cplusplus",
125 "msg": "global - across units after provider",
126 "count": 0,
127 },
128 {"name": "tp:constructor_cplusplus", "msg": "main() local", "count": 0},
129 {"name": "tp:destructor_cplusplus", "msg": "main() local", "count": 0},
130 {"name": "tp:main", "msg": None, "count": 0},
131 {
132 "name": "tp:destructor_cplusplus",
133 "msg": "global - across units after provider",
134 "count": 0,
135 },
136 {
137 "name": "tp:destructor_cplusplus",
138 "msg": "global - same unit after provider",
139 "count": 0,
140 },
141 {
142 "name": "tp:destructor_cplusplus",
143 "msg": "global - same unit before provider",
144 "count": 0,
145 "may_fail": compound_literal_on_heap,
146 },
147 {
148 "name": "tp:destructor_cplusplus",
149 "msg": "global - across units after define",
150 "count": 0,
151 "may_fail": compound_literal_on_heap,
152 },
153 {
154 "name": "tp:destructor_cplusplus",
155 "msg": "global - same unit after define",
156 "count": 0,
157 "may_fail": compound_literal_on_heap,
158 },
159 {
160 "name": "tp:destructor_cplusplus",
161 "msg": "global - same unit before define",
162 "count": 0,
163 "may_fail": compound_literal_on_heap,
164 },
165 {
166 "name": "tp:destructor_cplusplus",
167 "msg": "global - across units before define",
168 "count": 0,
169 "may_fail": compound_literal_on_heap,
170 },
171 {
172 "name": "tp:destructor_c_across_units_after_provider",
173 "msg": None,
174 "count": 0,
175 "may_fail": compound_literal_on_heap,
176 },
177 {
178 "name": "tp:destructor_c_same_unit_after_provider",
179 "msg": None,
180 "count": 0,
181 "may_fail": compound_literal_on_heap,
182 },
183 {
184 "name": "tp:destructor_c_same_unit_before_provider",
185 "msg": None,
186 "count": 0,
187 "may_fail": compound_literal_on_heap,
188 },
189 {
190 "name": "tp:destructor_c_across_units_after_define",
191 "msg": None,
192 "count": 0,
193 "may_fail": compound_literal_on_heap,
194 },
195 {
196 "name": "tp:destructor_c_same_unit_after_define",
197 "msg": None,
198 "count": 0,
199 "may_fail": compound_literal_on_heap,
200 },
201 {
202 "name": "tp:destructor_c_same_unit_before_define",
203 "msg": None,
204 "count": 0,
205 "may_fail": compound_literal_on_heap,
206 },
207 {
208 "name": "tp:destructor_c_across_units_before_define",
209 "msg": None,
210 "count": 0,
211 "may_fail": compound_literal_on_heap,
212 },
213 ]
214 expected_events_tp_so = [
215 {"name": "tp_so_c:constructor_c_provider_shared_library", "msg": None, "count": 0},
216 {
217 "name": "tp_so:constructor_cplusplus_provider_shared_library",
218 "msg": "global - shared library define and provider",
219 "count": 0,
220 },
221 {
222 "name": "tp_so:constructor_cplusplus_provider_shared_library",
223 "msg": "main() local - shared library define and provider",
224 "count": 0,
225 },
226 {
227 "name": "tp_so:destructor_cplusplus_provider_shared_library",
228 "msg": "main() local - shared library define and provider",
229 "count": 0,
230 },
231 {
232 "name": "tp_so:destructor_cplusplus_provider_shared_library",
233 "msg": "global - shared library define and provider",
234 "count": 0,
235 },
236 {"name": "tp_so_c:destructor_c_provider_shared_library", "msg": None, "count": 0},
237 ]
238 expected_events_tp_a = [
239 {"name": "tp_a_c:constructor_c_provider_static_archive", "msg": None, "count": 0},
240 {
241 "name": "tp_a:constructor_cplusplus_provider_static_archive",
242 "msg": "global - static archive define and provider",
243 "count": 0,
244 "may_fail": compound_literal_on_heap,
245 },
246 {
247 "name": "tp_a:constructor_cplusplus_provider_static_archive",
248 "msg": "main() local - static archive define and provider",
249 "count": 0,
250 },
251 {
252 "name": "tp_a:destructor_cplusplus_provider_static_archive",
253 "msg": "main() local - static archive define and provider",
254 "count": 0,
255 },
256 {
257 "name": "tp_a:destructor_cplusplus_provider_static_archive",
258 "msg": "global - static archive define and provider",
259 "count": 0,
260 "may_fail": compound_literal_on_heap,
261 },
262 {"name": "tp_a_c:destructor_c_provider_static_archive", "msg": None, "count": 0},
263 ]
264
265
266 def capture_trace(tap, test_env, application, description):
267 # type: (lttngtest.TapGenerator, lttngtest._Environment) -> lttngtest.LocalSessionOutputLocation
268 tap.diagnostic(description)
269
270 session_output_location = lttngtest.LocalSessionOutputLocation(
271 test_env.create_temporary_directory("trace")
272 )
273
274 client = lttngtest.LTTngClient(test_env, log=tap.diagnostic)
275
276 with tap.case("Create a session") as test_case:
277 session = client.create_session(output=session_output_location)
278 tap.diagnostic("Created session `{session_name}`".format(session_name=session.name))
279
280 with tap.case(
281 "Add a channel to session `{session_name}`".format(session_name=session.name)
282 ) as test_case:
283 channel = session.add_channel(lttngtest.TracingDomain.User)
284 tap.diagnostic("Created channel `{channel_name}`".format(channel_name=channel.name))
285
286 # Enable all user space events, the default for a user tracepoint event rule.
287 channel.add_recording_rule(lttngtest.UserTracepointEventRule("tp*"))
288
289 with tap.case(
290 "Start session `{session_name}`".format(session_name=session.name)
291 ) as test_case:
292 session.start()
293
294 test_app = test_env.launch_test_application(application)
295 with tap.case(
296 "Run test app '{}'".format(application, session_name=session.name)
297 ) as test_case:
298 test_app.wait_for_exit()
299
300 with tap.case(
301 "Stop session `{session_name}`".format(session_name=session.name)
302 ) as test_case:
303 session.stop()
304
305 with tap.case(
306 "Destroy session `{session_name}`".format(session_name=session.name)
307 ) as test_case:
308 session.destroy()
309
310 return session_output_location
311
312
313 def validate_trace(trace_location, tap, expected_events):
314 # type: (pathlib.Path, lttngtest.TapGenerator)
315 unknown_event_count = 0
316
317 for msg in bt2.TraceCollectionMessageIterator(str(trace_location)):
318 if type(msg) is not bt2._EventMessageConst:
319 continue
320
321 found = False
322 for event in expected_events:
323 if event["name"] == msg.event.name and event["msg"] is None:
324 found = True
325 event["count"] = event["count"] + 1
326 break
327 elif (
328 event["name"] == msg.event.name
329 and event["msg"] is not None
330 and event["msg"] == msg.event["msg"]
331 ):
332 found = True
333 event["count"] = event["count"] + 1
334 break
335
336 if found == False:
337 unknown_event_count = unknown_event_count + 1
338 printmsg = None
339 if "msg" in msg.event:
340 printmsg = msg.event["msg"]
341 tap.diagnostic(
342 'Unexpected event name="{}" msg="{}" encountered'.format(
343 msg.event.name, str(printmsg)
344 )
345 )
346
347 for event in expected_events:
348 may_fail = "may_fail" in event.keys() and event["may_fail"]
349 if not may_fail:
350 tap.test(
351 event["count"] == 1,
352 'Found expected event name="{}" msg="{}"'.format(
353 event["name"], str(event["msg"])
354 ),
355 ),
356 else:
357 tap.skip("Event '{}' may or may not be recorded".format(event["name"]))
358
359 tap.test(unknown_event_count == 0, "Found no unexpected events")
360
361
362 success = True
363 tests = [
364 {
365 "description": "Test user space constructor/destructor instrumentation coverage (C++ w/ static archive)",
366 "application": "gen-ust-events-constructor/gen-ust-events-constructor-a",
367 "expected_events": copy.deepcopy(expected_events_common + expected_events_tp_a),
368 "skip_if_application_not_present": False,
369 },
370 {
371 "description": "Test user space constructor/destructor instrumentation coverage (C++ w/ dynamic object",
372 "application": "gen-ust-events-constructor/gen-ust-events-constructor-so",
373 "expected_events": copy.deepcopy(
374 expected_events_common + expected_events_tp_so
375 ),
376 # This application is not be built when `NO_SHARED` is set in the
377 # configuration options.
378 "skip_if_application_not_present": True,
379 },
380 ]
381
382 success = True
383 for test in tests:
384 tap = lttngtest.TapGenerator(7 + len(test["expected_events"]))
385 with lttngtest.test_environment(with_sessiond=True, log=tap.diagnostic) as test_env:
386 try:
387 outputlocation = capture_trace(
388 tap, test_env, test["application"], test["description"]
389 )
390 except FileNotFoundError as fne:
391 tap.diagnostic(fne)
392 if test["skip_if_application_not_present"]:
393 tap.skip(
394 "Test application '{}' not found".format(test["application"]),
395 tap.remaining_test_cases,
396 )
397 break
398 # Warning: validate_trace mutates test['expected_events']
399 validate_trace(outputlocation.path, tap, test["expected_events"])
400 success = success and tap.is_successful
401
402
403 sys.exit(0 if success else 1)
This page took 0.046214 seconds and 4 git commands to generate.