tests: test_ust_constructor: Split test_ust_constructor binary
[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
09a872ef 50expected_events_common = [
b8e79f3f
KS
51 {
52 "name": "tp:constructor_c_across_units_before_define",
53 "msg": None,
54 "count": 0,
55 "may_fail": compound_literal_on_heap,
da1e97c9 56 },
da1e97c9
MD
57 {
58 "name": "tp:constructor_cplusplus",
59 "msg": "global - across units before define",
60 "count": 0,
b8e79f3f
KS
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,
da1e97c9 74 },
da1e97c9
MD
75 {
76 "name": "tp:constructor_cplusplus",
77 "msg": "global - same unit before define",
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 define",
84 "count": 0,
b8e79f3f
KS
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,
da1e97c9 92 },
da1e97c9
MD
93 {
94 "name": "tp:constructor_cplusplus",
95 "msg": "global - across units after define",
96 "count": 0,
b8e79f3f
KS
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,
da1e97c9 110 },
da1e97c9
MD
111 {
112 "name": "tp:constructor_cplusplus",
113 "msg": "global - same unit before provider",
114 "count": 0,
b8e79f3f 115 "may_fail": compound_literal_on_heap,
da1e97c9
MD
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},
da1e97c9 129 {"name": "tp:destructor_cplusplus", "msg": "main() local", "count": 0},
09a872ef 130 {"name": "tp:main", "msg": None, "count": 0},
da1e97c9
MD
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,
b8e79f3f 145 "may_fail": compound_literal_on_heap,
da1e97c9
MD
146 },
147 {
148 "name": "tp:destructor_cplusplus",
149 "msg": "global - across units after define",
150 "count": 0,
b8e79f3f 151 "may_fail": compound_literal_on_heap,
da1e97c9
MD
152 },
153 {
154 "name": "tp:destructor_cplusplus",
155 "msg": "global - same unit after define",
156 "count": 0,
b8e79f3f 157 "may_fail": compound_literal_on_heap,
da1e97c9
MD
158 },
159 {
160 "name": "tp:destructor_cplusplus",
161 "msg": "global - same unit before define",
162 "count": 0,
b8e79f3f 163 "may_fail": compound_literal_on_heap,
da1e97c9
MD
164 },
165 {
166 "name": "tp:destructor_cplusplus",
167 "msg": "global - across units before define",
168 "count": 0,
b8e79f3f 169 "may_fail": compound_literal_on_heap,
da1e97c9 170 },
b8e79f3f
KS
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 },
09a872ef
KS
213]
214expected_events_tp_so = [
215 {"name": "tp_so_c:constructor_c_provider_shared_library", "msg": None, "count": 0},
b8e79f3f 216 {
09a872ef
KS
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",
b8e79f3f 234 "count": 0,
b8e79f3f 235 },
ed1b6b66 236 {"name": "tp_so_c:destructor_c_provider_shared_library", "msg": None, "count": 0},
da1e97c9 237]
09a872ef
KS
238expected_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]
d096be91 264
da1e97c9 265
09a872ef 266def capture_trace(tap, test_env, application, description):
d2455527 267 # type: (lttngtest.TapGenerator, lttngtest._Environment) -> lttngtest.LocalSessionOutputLocation
09a872ef 268 tap.diagnostic(description)
da1e97c9
MD
269
270 session_output_location = lttngtest.LocalSessionOutputLocation(
271 test_env.create_temporary_directory("trace")
272 )
273
aae4cdd1 274 client = lttngtest.LTTngClient(test_env, log=tap.diagnostic)
da1e97c9
MD
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
d096be91
MJ
289 with tap.case(
290 "Start session `{session_name}`".format(session_name=session.name)
291 ) as test_case:
292 session.start()
293
09a872ef
KS
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:
d096be91
MJ
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
da1e97c9
MD
310 return session_output_location
311
312
09a872ef 313def validate_trace(trace_location, tap, expected_events):
d096be91 314 # type: (pathlib.Path, lttngtest.TapGenerator)
da1e97c9
MD
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
d096be91 335
da1e97c9
MD
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:
b8e79f3f
KS
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 ),
d096be91 355 ),
b8e79f3f
KS
356 else:
357 tap.skip("Event '{}' may or may not be recorded".format(event["name"]))
d096be91
MJ
358
359 tap.test(unknown_event_count == 0, "Found no unexpected events")
da1e97c9
MD
360
361
09a872ef
KS
362success = True
363tests = [
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
382success = True
383for 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
da1e97c9 401
da1e97c9 402
09a872ef 403sys.exit(0 if success else 1)
This page took 0.045581 seconds and 4 git commands to generate.