tests: Add diagnostic info for kernel bug, warning, and oops
[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_cpp = [
51 {
52 "name": "tp:constructor_cplusplus",
53 "msg": "global - across units before define",
54 "count": 0,
55 "may_fail": compound_literal_on_heap,
56 },
57 {
58 "name": "tp:constructor_cplusplus",
59 "msg": "global - same unit before define",
60 "count": 0,
61 "may_fail": compound_literal_on_heap,
62 },
63 {
64 "name": "tp:constructor_cplusplus",
65 "msg": "global - same unit after define",
66 "count": 0,
67 "may_fail": compound_literal_on_heap,
68 },
69 {
70 "name": "tp:constructor_cplusplus",
71 "msg": "global - across units after define",
72 "count": 0,
73 "may_fail": compound_literal_on_heap,
74 },
75 {
76 "name": "tp:constructor_cplusplus",
77 "msg": "global - same unit before provider",
78 "count": 0,
79 "may_fail": compound_literal_on_heap,
80 },
81 {
82 "name": "tp:constructor_cplusplus",
83 "msg": "global - same unit after provider",
84 "count": 0,
85 },
86 {
87 "name": "tp:constructor_cplusplus",
88 "msg": "global - across units after provider",
89 "count": 0,
90 },
91 {"name": "tp:constructor_cplusplus", "msg": "main() local", "count": 0},
92 {"name": "tp:destructor_cplusplus", "msg": "main() local", "count": 0},
93 {
94 "name": "tp:destructor_cplusplus",
95 "msg": "global - across units after provider",
96 "count": 0,
97 },
98 {
99 "name": "tp:destructor_cplusplus",
100 "msg": "global - same unit after provider",
101 "count": 0,
102 },
103 {
104 "name": "tp:destructor_cplusplus",
105 "msg": "global - same unit before provider",
106 "count": 0,
107 "may_fail": compound_literal_on_heap,
108 },
109 {
110 "name": "tp:destructor_cplusplus",
111 "msg": "global - across units after define",
112 "count": 0,
113 "may_fail": compound_literal_on_heap,
114 },
115 {
116 "name": "tp:destructor_cplusplus",
117 "msg": "global - same unit after define",
118 "count": 0,
119 "may_fail": compound_literal_on_heap,
120 },
121 {
122 "name": "tp:destructor_cplusplus",
123 "msg": "global - same unit before define",
124 "count": 0,
125 "may_fail": compound_literal_on_heap,
126 },
127 {
128 "name": "tp:destructor_cplusplus",
129 "msg": "global - across units before define",
130 "count": 0,
131 "may_fail": compound_literal_on_heap,
132 },
133 ]
134
135 expected_events_common = [
136 {
137 "name": "tp:constructor_c_across_units_before_define",
138 "msg": None,
139 "count": 0,
140 "may_fail": compound_literal_on_heap,
141 },
142 {
143 "name": "tp:constructor_c_same_unit_before_define",
144 "msg": None,
145 "count": 0,
146 "may_fail": compound_literal_on_heap,
147 },
148 {
149 "name": "tp:constructor_c_same_unit_after_define",
150 "msg": None,
151 "count": 0,
152 "may_fail": compound_literal_on_heap,
153 },
154 {
155 "name": "tp:constructor_c_across_units_after_define",
156 "msg": None,
157 "count": 0,
158 "may_fail": compound_literal_on_heap,
159 },
160 {
161 "name": "tp:constructor_c_same_unit_before_provider",
162 "msg": None,
163 "count": 0,
164 "may_fail": compound_literal_on_heap,
165 },
166 {
167 "name": "tp:constructor_c_same_unit_after_provider",
168 "msg": None,
169 "count": 0,
170 "may_fail": compound_literal_on_heap,
171 },
172 {"name": "tp:constructor_c_across_units_after_provider", "msg": None, "count": 0},
173 {"name": "tp:main", "msg": None, "count": 0},
174 {
175 "name": "tp:destructor_c_across_units_after_provider",
176 "msg": None,
177 "count": 0,
178 "may_fail": compound_literal_on_heap,
179 },
180 {
181 "name": "tp:destructor_c_same_unit_after_provider",
182 "msg": None,
183 "count": 0,
184 "may_fail": compound_literal_on_heap,
185 },
186 {
187 "name": "tp:destructor_c_same_unit_before_provider",
188 "msg": None,
189 "count": 0,
190 "may_fail": compound_literal_on_heap,
191 },
192 {
193 "name": "tp:destructor_c_across_units_after_define",
194 "msg": None,
195 "count": 0,
196 "may_fail": compound_literal_on_heap,
197 },
198 {
199 "name": "tp:destructor_c_same_unit_after_define",
200 "msg": None,
201 "count": 0,
202 "may_fail": compound_literal_on_heap,
203 },
204 {
205 "name": "tp:destructor_c_same_unit_before_define",
206 "msg": None,
207 "count": 0,
208 "may_fail": compound_literal_on_heap,
209 },
210 {
211 "name": "tp:destructor_c_across_units_before_define",
212 "msg": None,
213 "count": 0,
214 "may_fail": compound_literal_on_heap,
215 },
216 ]
217
218 expected_events_tp_so_cpp = [
219 {
220 "name": "tp_so:constructor_cplusplus_provider_shared_library",
221 "msg": "global - shared library define and provider",
222 "count": 0,
223 },
224 {
225 "name": "tp_so:constructor_cplusplus_provider_shared_library",
226 "msg": "main() local - shared library define and provider",
227 "count": 0,
228 },
229 {
230 "name": "tp_so:destructor_cplusplus_provider_shared_library",
231 "msg": "main() local - shared library define and provider",
232 "count": 0,
233 },
234 {
235 "name": "tp_so:destructor_cplusplus_provider_shared_library",
236 "msg": "global - shared library define and provider",
237 "count": 0,
238 },
239 ]
240
241 expected_events_tp_so = [
242 {"name": "tp_so_c:constructor_c_provider_shared_library", "msg": None, "count": 0},
243 {"name": "tp_so_c:destructor_c_provider_shared_library", "msg": None, "count": 0},
244 ]
245
246 expected_events_tp_a_cpp = [
247 {
248 "name": "tp_a:constructor_cplusplus_provider_static_archive",
249 "msg": "global - static archive define and provider",
250 "count": 0,
251 "may_fail": compound_literal_on_heap,
252 },
253 {
254 "name": "tp_a:constructor_cplusplus_provider_static_archive",
255 "msg": "main() local - static archive define and provider",
256 "count": 0,
257 },
258 {
259 "name": "tp_a:destructor_cplusplus_provider_static_archive",
260 "msg": "main() local - static archive define and provider",
261 "count": 0,
262 },
263 {
264 "name": "tp_a:destructor_cplusplus_provider_static_archive",
265 "msg": "global - static archive define and provider",
266 "count": 0,
267 "may_fail": compound_literal_on_heap,
268 },
269 ]
270
271 expected_events_tp_a = [
272 {"name": "tp_a_c:constructor_c_provider_static_archive", "msg": None, "count": 0},
273 {"name": "tp_a_c:destructor_c_provider_static_archive", "msg": None, "count": 0},
274 ]
275
276
277 def capture_trace(tap, test_env, application, description):
278 # type: (lttngtest.TapGenerator, lttngtest._Environment) -> lttngtest.LocalSessionOutputLocation
279 tap.diagnostic(description)
280
281 session_output_location = lttngtest.LocalSessionOutputLocation(
282 test_env.create_temporary_directory("trace")
283 )
284
285 client = lttngtest.LTTngClient(test_env, log=tap.diagnostic)
286
287 with tap.case("Create a session") as test_case:
288 session = client.create_session(output=session_output_location)
289 tap.diagnostic("Created session `{session_name}`".format(session_name=session.name))
290
291 with tap.case(
292 "Add a channel to session `{session_name}`".format(session_name=session.name)
293 ) as test_case:
294 channel = session.add_channel(lttngtest.TracingDomain.User)
295 tap.diagnostic("Created channel `{channel_name}`".format(channel_name=channel.name))
296
297 # Enable all user space events, the default for a user tracepoint event rule.
298 channel.add_recording_rule(lttngtest.UserTracepointEventRule("tp*"))
299
300 with tap.case(
301 "Start session `{session_name}`".format(session_name=session.name)
302 ) as test_case:
303 session.start()
304
305 test_app = test_env.launch_test_application(application)
306 with tap.case(
307 "Run test app '{}'".format(application, session_name=session.name)
308 ) as test_case:
309 test_app.wait_for_exit()
310
311 with tap.case(
312 "Stop session `{session_name}`".format(session_name=session.name)
313 ) as test_case:
314 session.stop()
315
316 with tap.case(
317 "Destroy session `{session_name}`".format(session_name=session.name)
318 ) as test_case:
319 session.destroy()
320
321 return session_output_location
322
323
324 def validate_trace(trace_location, tap, expected_events):
325 # type: (pathlib.Path, lttngtest.TapGenerator)
326 unknown_event_count = 0
327
328 for msg in bt2.TraceCollectionMessageIterator(str(trace_location)):
329 if type(msg) is not bt2._EventMessageConst:
330 continue
331
332 found = False
333 for event in expected_events:
334 if event["name"] == msg.event.name and event["msg"] is None:
335 found = True
336 event["count"] = event["count"] + 1
337 break
338 elif (
339 event["name"] == msg.event.name
340 and event["msg"] is not None
341 and event["msg"] == msg.event["msg"]
342 ):
343 found = True
344 event["count"] = event["count"] + 1
345 break
346
347 if found == False:
348 unknown_event_count = unknown_event_count + 1
349 printmsg = None
350 if "msg" in msg.event:
351 printmsg = msg.event["msg"]
352 tap.diagnostic(
353 'Unexpected event name="{}" msg="{}" encountered'.format(
354 msg.event.name, str(printmsg)
355 )
356 )
357
358 for event in expected_events:
359 may_fail = "may_fail" in event.keys() and event["may_fail"]
360 if not may_fail:
361 tap.test(
362 event["count"] == 1,
363 'Found expected event name="{}" msg="{}"'.format(
364 event["name"], str(event["msg"])
365 ),
366 ),
367 else:
368 tap.skip("Event '{}' may or may not be recorded".format(event["name"]))
369
370 tap.test(unknown_event_count == 0, "Found no unexpected events")
371
372
373 success = True
374 tests = [
375 {
376 "description": "Test user space constructor/destructor instrumentation coverage (C++ w/ static archive)",
377 "application": "gen-ust-events-constructor/gen-ust-events-constructor-a",
378 "expected_events": copy.deepcopy(
379 expected_events_common
380 + expected_events_common_cpp
381 + expected_events_tp_a
382 + expected_events_tp_a_cpp
383 ),
384 "skip_if_application_not_present": False,
385 },
386 {
387 "description": "Test user space constructor/destructor instrumentation coverage (C++ w/ dynamic object",
388 "application": "gen-ust-events-constructor/gen-ust-events-constructor-so",
389 "expected_events": copy.deepcopy(
390 expected_events_common
391 + expected_events_common_cpp
392 + expected_events_tp_so
393 + expected_events_tp_so_cpp
394 ),
395 # This application is not be built when `NO_SHARED` is set in the
396 # configuration options.
397 "skip_if_application_not_present": True,
398 },
399 {
400 "description": "Test user space constructor/destructor instrumentation coverage (C w/ static archive)",
401 "application": "gen-ust-events-constructor/gen-ust-events-c-constructor-a",
402 "expected_events": copy.deepcopy(expected_events_common + expected_events_tp_a),
403 "skip_if_application_not_present": False,
404 },
405 {
406 "description": "Test user space constructor/destructor instrumentation coverage (C w/ dynamic object",
407 "application": "gen-ust-events-constructor/gen-ust-events-c-constructor-so",
408 "expected_events": copy.deepcopy(
409 expected_events_common + expected_events_tp_so
410 ),
411 # This application is not be built when `NO_SHARED` is set in the
412 # configuration options.
413 "skip_if_application_not_present": True,
414 },
415 ]
416
417 success = True
418 for test in tests:
419 tap = lttngtest.TapGenerator(7 + len(test["expected_events"]))
420 with lttngtest.test_environment(with_sessiond=True, log=tap.diagnostic) as test_env:
421 try:
422 outputlocation = capture_trace(
423 tap, test_env, test["application"], test["description"]
424 )
425 except FileNotFoundError as fne:
426 tap.diagnostic(fne)
427 if test["skip_if_application_not_present"]:
428 tap.skip(
429 "Test application '{}' not found".format(test["application"]),
430 tap.remaining_test_cases,
431 )
432 break
433 # Warning: validate_trace mutates test['expected_events']
434 validate_trace(outputlocation.path, tap, test["expected_events"])
435 success = success and tap.is_successful
436
437
438 sys.exit(0 if success else 1)
This page took 0.038734 seconds and 4 git commands to generate.