tests: Add C versions of gen-ust-events-constructor
[lttng-tools.git] / tests / regression / ust / ust-constructor / test_ust_constructor.py
CommitLineData
da1e97c9
MD
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
09a872ef 8import copy
da1e97c9
MD
9import pathlib
10import sys
11import os
b8e79f3f 12import subprocess
da1e97c9
MD
13from typing import Any, Callable, Type
14
15"""
16Test instrumentation coverage of C/C++ constructors and destructors by LTTng-UST
17tracepoints.
18
19This test successively sets up a session, traces a test application, and then
20reads the resulting trace to determine if all the expected events are present.
21"""
22
23# Import in-tree test utils
24test_utils_import_path = pathlib.Path(__file__).absolute().parents[3] / "utils"
25sys.path.append(str(test_utils_import_path))
26
27import lttngtest
28import bt2
29
b8e79f3f
KS
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#
35compound_literal_on_heap = False
36process = 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)
46process.wait()
47if process.returncode == 0:
48 compound_literal_on_heap = True
49
21b65d7f 50expected_events_common_cpp = [
da1e97c9
MD
51 {
52 "name": "tp:constructor_cplusplus",
53 "msg": "global - across units before define",
54 "count": 0,
b8e79f3f
KS
55 "may_fail": compound_literal_on_heap,
56 },
da1e97c9
MD
57 {
58 "name": "tp:constructor_cplusplus",
59 "msg": "global - same unit before define",
60 "count": 0,
b8e79f3f 61 "may_fail": compound_literal_on_heap,
da1e97c9
MD
62 },
63 {
64 "name": "tp:constructor_cplusplus",
65 "msg": "global - same unit after define",
66 "count": 0,
b8e79f3f
KS
67 "may_fail": compound_literal_on_heap,
68 },
da1e97c9
MD
69 {
70 "name": "tp:constructor_cplusplus",
71 "msg": "global - across units after define",
72 "count": 0,
b8e79f3f
KS
73 "may_fail": compound_literal_on_heap,
74 },
da1e97c9
MD
75 {
76 "name": "tp:constructor_cplusplus",
77 "msg": "global - same unit before provider",
78 "count": 0,
b8e79f3f 79 "may_fail": compound_literal_on_heap,
da1e97c9
MD
80 },
81 {
82 "name": "tp:constructor_cplusplus",
83 "msg": "global - same unit after provider",
84 "count": 0,
85 },
da1e97c9
MD
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},
da1e97c9
MD
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,
b8e79f3f 107 "may_fail": compound_literal_on_heap,
da1e97c9
MD
108 },
109 {
110 "name": "tp:destructor_cplusplus",
111 "msg": "global - across units after define",
112 "count": 0,
b8e79f3f 113 "may_fail": compound_literal_on_heap,
da1e97c9
MD
114 },
115 {
116 "name": "tp:destructor_cplusplus",
117 "msg": "global - same unit after define",
118 "count": 0,
b8e79f3f 119 "may_fail": compound_literal_on_heap,
da1e97c9
MD
120 },
121 {
122 "name": "tp:destructor_cplusplus",
123 "msg": "global - same unit before define",
124 "count": 0,
b8e79f3f 125 "may_fail": compound_literal_on_heap,
da1e97c9
MD
126 },
127 {
128 "name": "tp:destructor_cplusplus",
129 "msg": "global - across units before define",
130 "count": 0,
b8e79f3f 131 "may_fail": compound_literal_on_heap,
da1e97c9 132 },
21b65d7f
KS
133]
134
135expected_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},
b8e79f3f
KS
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 },
09a872ef 216]
21b65d7f
KS
217
218expected_events_tp_so_cpp = [
b8e79f3f 219 {
09a872ef
KS
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",
b8e79f3f 237 "count": 0,
b8e79f3f 238 },
21b65d7f
KS
239]
240
241expected_events_tp_so = [
242 {"name": "tp_so_c:constructor_c_provider_shared_library", "msg": None, "count": 0},
ed1b6b66 243 {"name": "tp_so_c:destructor_c_provider_shared_library", "msg": None, "count": 0},
da1e97c9 244]
21b65d7f
KS
245
246expected_events_tp_a_cpp = [
09a872ef
KS
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 },
21b65d7f
KS
269]
270
271expected_events_tp_a = [
272 {"name": "tp_a_c:constructor_c_provider_static_archive", "msg": None, "count": 0},
09a872ef
KS
273 {"name": "tp_a_c:destructor_c_provider_static_archive", "msg": None, "count": 0},
274]
d096be91 275
da1e97c9 276
09a872ef 277def capture_trace(tap, test_env, application, description):
d2455527 278 # type: (lttngtest.TapGenerator, lttngtest._Environment) -> lttngtest.LocalSessionOutputLocation
09a872ef 279 tap.diagnostic(description)
da1e97c9
MD
280
281 session_output_location = lttngtest.LocalSessionOutputLocation(
282 test_env.create_temporary_directory("trace")
283 )
284
aae4cdd1 285 client = lttngtest.LTTngClient(test_env, log=tap.diagnostic)
da1e97c9
MD
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
d096be91
MJ
300 with tap.case(
301 "Start session `{session_name}`".format(session_name=session.name)
302 ) as test_case:
303 session.start()
304
09a872ef
KS
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:
d096be91
MJ
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
da1e97c9
MD
321 return session_output_location
322
323
09a872ef 324def validate_trace(trace_location, tap, expected_events):
d096be91 325 # type: (pathlib.Path, lttngtest.TapGenerator)
da1e97c9
MD
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
d096be91 346
da1e97c9
MD
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:
b8e79f3f
KS
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 ),
d096be91 366 ),
b8e79f3f
KS
367 else:
368 tap.skip("Event '{}' may or may not be recorded".format(event["name"]))
d096be91
MJ
369
370 tap.test(unknown_event_count == 0, "Found no unexpected events")
da1e97c9
MD
371
372
09a872ef
KS
373success = True
374tests = [
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",
21b65d7f
KS
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 ),
09a872ef
KS
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",
21b65d7f
KS
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",
09a872ef
KS
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
417success = True
418for 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
da1e97c9 436
da1e97c9 437
09a872ef 438sys.exit(0 if success else 1)
This page took 0.046228 seconds and 4 git commands to generate.