3 # Copyright (C) 2022 Jérémie Galarneau <jeremie.galarneau@efficios.com>
4 # Copyright (C) 2023 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
6 # SPDX-License-Identifier: GPL-2.0-only
13 from typing
import Any
, Callable
, Type
16 Test instrumentation coverage of C/C++ constructors and destructors by LTTng-UST
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.
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
))
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
33 # @see https://github.com/lttng/lttng-ust/blob/47fa3e4ed7ab43e034dc61fc1480f919f4ee51d0/include/lttng/ust-compiler.h#L51
35 compound_literal_on_heap
= False
36 process
= subprocess
.Popen(
39 str(test_utils_import_path
),
41 "gen-ust-events-constructor",
47 if process
.returncode
== 0:
48 compound_literal_on_heap
= True
50 expected_events_common_cpp
= [
52 "name": "tp:constructor_cplusplus",
53 "msg": "global - across units before define",
55 "may_fail": compound_literal_on_heap
,
58 "name": "tp:constructor_cplusplus",
59 "msg": "global - same unit before define",
61 "may_fail": compound_literal_on_heap
,
64 "name": "tp:constructor_cplusplus",
65 "msg": "global - same unit after define",
67 "may_fail": compound_literal_on_heap
,
70 "name": "tp:constructor_cplusplus",
71 "msg": "global - across units after define",
73 "may_fail": compound_literal_on_heap
,
76 "name": "tp:constructor_cplusplus",
77 "msg": "global - same unit before provider",
79 "may_fail": compound_literal_on_heap
,
82 "name": "tp:constructor_cplusplus",
83 "msg": "global - same unit after provider",
87 "name": "tp:constructor_cplusplus",
88 "msg": "global - across units after provider",
91 {"name": "tp:constructor_cplusplus", "msg": "main() local", "count": 0},
92 {"name": "tp:destructor_cplusplus", "msg": "main() local", "count": 0},
94 "name": "tp:destructor_cplusplus",
95 "msg": "global - across units after provider",
99 "name": "tp:destructor_cplusplus",
100 "msg": "global - same unit after provider",
104 "name": "tp:destructor_cplusplus",
105 "msg": "global - same unit before provider",
107 "may_fail": compound_literal_on_heap
,
110 "name": "tp:destructor_cplusplus",
111 "msg": "global - across units after define",
113 "may_fail": compound_literal_on_heap
,
116 "name": "tp:destructor_cplusplus",
117 "msg": "global - same unit after define",
119 "may_fail": compound_literal_on_heap
,
122 "name": "tp:destructor_cplusplus",
123 "msg": "global - same unit before define",
125 "may_fail": compound_literal_on_heap
,
128 "name": "tp:destructor_cplusplus",
129 "msg": "global - across units before define",
131 "may_fail": compound_literal_on_heap
,
135 expected_events_common
= [
137 "name": "tp:constructor_c_across_units_before_define",
140 "may_fail": compound_literal_on_heap
,
143 "name": "tp:constructor_c_same_unit_before_define",
146 "may_fail": compound_literal_on_heap
,
149 "name": "tp:constructor_c_same_unit_after_define",
152 "may_fail": compound_literal_on_heap
,
155 "name": "tp:constructor_c_across_units_after_define",
158 "may_fail": compound_literal_on_heap
,
161 "name": "tp:constructor_c_same_unit_before_provider",
164 "may_fail": compound_literal_on_heap
,
167 "name": "tp:constructor_c_same_unit_after_provider",
170 "may_fail": compound_literal_on_heap
,
172 {"name": "tp:constructor_c_across_units_after_provider", "msg": None, "count": 0},
173 {"name": "tp:main", "msg": None, "count": 0},
175 "name": "tp:destructor_c_across_units_after_provider",
178 "may_fail": compound_literal_on_heap
,
181 "name": "tp:destructor_c_same_unit_after_provider",
184 "may_fail": compound_literal_on_heap
,
187 "name": "tp:destructor_c_same_unit_before_provider",
190 "may_fail": compound_literal_on_heap
,
193 "name": "tp:destructor_c_across_units_after_define",
196 "may_fail": compound_literal_on_heap
,
199 "name": "tp:destructor_c_same_unit_after_define",
202 "may_fail": compound_literal_on_heap
,
205 "name": "tp:destructor_c_same_unit_before_define",
208 "may_fail": compound_literal_on_heap
,
211 "name": "tp:destructor_c_across_units_before_define",
214 "may_fail": compound_literal_on_heap
,
218 expected_events_tp_so_cpp
= [
220 "name": "tp_so:constructor_cplusplus_provider_shared_library",
221 "msg": "global - shared library define and provider",
225 "name": "tp_so:constructor_cplusplus_provider_shared_library",
226 "msg": "main() local - shared library define and provider",
230 "name": "tp_so:destructor_cplusplus_provider_shared_library",
231 "msg": "main() local - shared library define and provider",
235 "name": "tp_so:destructor_cplusplus_provider_shared_library",
236 "msg": "global - shared library define and provider",
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},
246 expected_events_tp_a_cpp
= [
248 "name": "tp_a:constructor_cplusplus_provider_static_archive",
249 "msg": "global - static archive define and provider",
251 "may_fail": compound_literal_on_heap
,
254 "name": "tp_a:constructor_cplusplus_provider_static_archive",
255 "msg": "main() local - static archive define and provider",
259 "name": "tp_a:destructor_cplusplus_provider_static_archive",
260 "msg": "main() local - static archive define and provider",
264 "name": "tp_a:destructor_cplusplus_provider_static_archive",
265 "msg": "global - static archive define and provider",
267 "may_fail": compound_literal_on_heap
,
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},
277 def capture_trace(tap
, test_env
, application
, description
):
278 # type: (lttngtest.TapGenerator, lttngtest._Environment) -> lttngtest.LocalSessionOutputLocation
279 tap
.diagnostic(description
)
281 session_output_location
= lttngtest
.LocalSessionOutputLocation(
282 test_env
.create_temporary_directory("trace")
285 client
= lttngtest
.LTTngClient(test_env
, log
=tap
.diagnostic
)
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
))
292 "Add a channel to session `{session_name}`".format(session_name
=session
.name
)
294 channel
= session
.add_channel(lttngtest
.TracingDomain
.User
)
295 tap
.diagnostic("Created channel `{channel_name}`".format(channel_name
=channel
.name
))
297 # Enable all user space events, the default for a user tracepoint event rule.
298 channel
.add_recording_rule(lttngtest
.UserTracepointEventRule("tp*"))
301 "Start session `{session_name}`".format(session_name
=session
.name
)
305 test_app
= test_env
.launch_test_application(application
)
307 "Run test app '{}'".format(application
, session_name
=session
.name
)
309 test_app
.wait_for_exit()
312 "Stop session `{session_name}`".format(session_name
=session
.name
)
317 "Destroy session `{session_name}`".format(session_name
=session
.name
)
321 return session_output_location
324 def validate_trace(trace_location
, tap
, expected_events
):
325 # type: (pathlib.Path, lttngtest.TapGenerator)
326 unknown_event_count
= 0
328 for msg
in bt2
.TraceCollectionMessageIterator(str(trace_location
)):
329 if type(msg
) is not bt2
._EventMessageConst
:
333 for event
in expected_events
:
334 if event
["name"] == msg
.event
.name
and event
["msg"] is None:
336 event
["count"] = event
["count"] + 1
339 event
["name"] == msg
.event
.name
340 and event
["msg"] is not None
341 and event
["msg"] == msg
.event
["msg"]
344 event
["count"] = event
["count"] + 1
348 unknown_event_count
= unknown_event_count
+ 1
350 if "msg" in msg
.event
:
351 printmsg
= msg
.event
["msg"]
353 'Unexpected event name="{}" msg="{}" encountered'.format(
354 msg
.event
.name
, str(printmsg
)
358 for event
in expected_events
:
359 may_fail
= "may_fail" in event
.keys() and event
["may_fail"]
363 'Found expected event name="{}" msg="{}"'.format(
364 event
["name"], str(event
["msg"])
368 tap
.skip("Event '{}' may or may not be recorded".format(event
["name"]))
370 tap
.test(unknown_event_count
== 0, "Found no unexpected events")
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
384 "skip_if_application_not_present": False,
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
395 # This application is not be built when `NO_SHARED` is set in the
396 # configuration options.
397 "skip_if_application_not_present": True,
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,
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
411 # This application is not be built when `NO_SHARED` is set in the
412 # configuration options.
413 "skip_if_application_not_present": True,
419 tap
= lttngtest
.TapGenerator(7 + len(test
["expected_events"]))
420 with lttngtest
.test_environment(with_sessiond
=True, log
=tap
.diagnostic
) as test_env
:
422 outputlocation
= capture_trace(
423 tap
, test_env
, test
["application"], test
["description"]
425 except FileNotFoundError
as fne
:
427 if test
["skip_if_application_not_present"]:
429 "Test application '{}' not found".format(test
["application"]),
430 tap
.remaining_test_cases
,
433 # Warning: validate_trace mutates test['expected_events']
434 validate_trace(outputlocation
.path
, tap
, test
["expected_events"])
435 success
= success
and tap
.is_successful
438 sys
.exit(0 if success
else 1)