#
# SPDX-License-Identifier: GPL-2.0-only
-from cgi import test
+import copy
import pathlib
import sys
import os
+import subprocess
from typing import Any, Callable, Type
"""
import lttngtest
import bt2
-num_tests = 3
+# Determine if LTTNG_UST_ALLOCATE_COMPOUND_LITERAL_ON_HEAP is set. This will
+# affect if certain events may or may not be expected when compiling with
+# C++.
+# @see https://github.com/lttng/lttng-ust/blob/47fa3e4ed7ab43e034dc61fc1480f919f4ee51d0/include/lttng/ust-compiler.h#L51
+#
+compound_literal_on_heap = False
+process = subprocess.Popen(
+ [
+ os.path.join(
+ str(test_utils_import_path),
+ "testapp",
+ "gen-ust-events-constructor",
+ "uses_heap",
+ )
+ ]
+)
+process.wait()
+if process.returncode == 0:
+ compound_literal_on_heap = True
-expected_events = [
- {"name": "tp_so:constructor_c_provider_shared_library", "msg": None, "count": 0},
- {"name": "tp_a:constructor_c_provider_static_archive", "msg": None, "count": 0},
+expected_events_common = [
{
- "name": "tp_so:constructor_cplusplus_provider_shared_library",
- "msg": "global - shared library define and provider",
+ "name": "tp:constructor_c_across_units_before_define",
+ "msg": None,
"count": 0,
+ "may_fail": compound_literal_on_heap,
},
{
- "name": "tp_a:constructor_cplusplus_provider_static_archive",
- "msg": "global - static archive define and provider",
+ "name": "tp:constructor_cplusplus",
+ "msg": "global - across units before define",
"count": 0,
+ "may_fail": compound_literal_on_heap,
},
- {"name": "tp:constructor_c_across_units_before_define", "msg": None, "count": 0},
{
- "name": "tp:constructor_cplusplus",
- "msg": "global - across units before define",
+ "name": "tp:constructor_c_same_unit_before_define",
+ "msg": None,
"count": 0,
+ "may_fail": compound_literal_on_heap,
},
- {"name": "tp:constructor_c_same_unit_before_define", "msg": None, "count": 0},
- {"name": "tp:constructor_c_same_unit_after_define", "msg": None, "count": 0},
{
- "name": "tp:constructor_cplusplus",
- "msg": "global - same unit before define",
+ "name": "tp:constructor_c_same_unit_after_define",
+ "msg": None,
"count": 0,
+ "may_fail": compound_literal_on_heap,
},
{
"name": "tp:constructor_cplusplus",
- "msg": "global - same unit after define",
+ "msg": "global - same unit before define",
"count": 0,
+ "may_fail": compound_literal_on_heap,
},
- {"name": "tp:constructor_c_across_units_after_define", "msg": None, "count": 0},
{
"name": "tp:constructor_cplusplus",
- "msg": "global - across units after define",
+ "msg": "global - same unit after define",
"count": 0,
+ "may_fail": compound_literal_on_heap,
},
- {"name": "tp:constructor_c_same_unit_before_provider", "msg": None, "count": 0},
- {"name": "tp:constructor_c_same_unit_after_provider", "msg": None, "count": 0},
{
- "name": "tp:constructor_cplusplus",
- "msg": "global - same unit before provider",
+ "name": "tp:constructor_c_across_units_after_define",
+ "msg": None,
"count": 0,
+ "may_fail": compound_literal_on_heap,
},
{
"name": "tp:constructor_cplusplus",
- "msg": "global - same unit after provider",
+ "msg": "global - across units after define",
"count": 0,
+ "may_fail": compound_literal_on_heap,
},
- {"name": "tp:constructor_c_across_units_after_provider", "msg": None, "count": 0},
{
- "name": "tp:constructor_cplusplus",
- "msg": "global - across units after provider",
+ "name": "tp:constructor_c_same_unit_before_provider",
+ "msg": None,
"count": 0,
+ "may_fail": compound_literal_on_heap,
},
- {"name": "tp:constructor_cplusplus", "msg": "main() local", "count": 0},
{
- "name": "tp_so:constructor_cplusplus_provider_shared_library",
- "msg": "main() local - shared library define and provider",
+ "name": "tp:constructor_c_same_unit_after_provider",
+ "msg": None,
"count": 0,
+ "may_fail": compound_literal_on_heap,
},
{
- "name": "tp_a:constructor_cplusplus_provider_static_archive",
- "msg": "main() local - static archive define and provider",
+ "name": "tp:constructor_cplusplus",
+ "msg": "global - same unit before provider",
"count": 0,
+ "may_fail": compound_literal_on_heap,
},
- {"name": "tp:main", "msg": None, "count": 0},
{
- "name": "tp_a:destructor_cplusplus_provider_static_archive",
- "msg": "main() local - static archive define and provider",
+ "name": "tp:constructor_cplusplus",
+ "msg": "global - same unit after provider",
"count": 0,
},
+ {"name": "tp:constructor_c_across_units_after_provider", "msg": None, "count": 0},
{
- "name": "tp_so:destructor_cplusplus_provider_shared_library",
- "msg": "main() local - shared library define and provider",
+ "name": "tp:constructor_cplusplus",
+ "msg": "global - across units after provider",
"count": 0,
},
+ {"name": "tp:constructor_cplusplus", "msg": "main() local", "count": 0},
{"name": "tp:destructor_cplusplus", "msg": "main() local", "count": 0},
+ {"name": "tp:main", "msg": None, "count": 0},
{
"name": "tp:destructor_cplusplus",
"msg": "global - across units after provider",
"name": "tp:destructor_cplusplus",
"msg": "global - same unit before provider",
"count": 0,
+ "may_fail": compound_literal_on_heap,
},
{
"name": "tp:destructor_cplusplus",
"msg": "global - across units after define",
"count": 0,
+ "may_fail": compound_literal_on_heap,
},
{
"name": "tp:destructor_cplusplus",
"msg": "global - same unit after define",
"count": 0,
+ "may_fail": compound_literal_on_heap,
},
{
"name": "tp:destructor_cplusplus",
"msg": "global - same unit before define",
"count": 0,
+ "may_fail": compound_literal_on_heap,
},
{
"name": "tp:destructor_cplusplus",
"msg": "global - across units before define",
"count": 0,
+ "may_fail": compound_literal_on_heap,
},
{
- "name": "tp_a:destructor_cplusplus_provider_static_archive",
- "msg": "global - static archive define and provider",
+ "name": "tp:destructor_c_across_units_after_provider",
+ "msg": None,
+ "count": 0,
+ "may_fail": compound_literal_on_heap,
+ },
+ {
+ "name": "tp:destructor_c_same_unit_after_provider",
+ "msg": None,
+ "count": 0,
+ "may_fail": compound_literal_on_heap,
+ },
+ {
+ "name": "tp:destructor_c_same_unit_before_provider",
+ "msg": None,
+ "count": 0,
+ "may_fail": compound_literal_on_heap,
+ },
+ {
+ "name": "tp:destructor_c_across_units_after_define",
+ "msg": None,
+ "count": 0,
+ "may_fail": compound_literal_on_heap,
+ },
+ {
+ "name": "tp:destructor_c_same_unit_after_define",
+ "msg": None,
+ "count": 0,
+ "may_fail": compound_literal_on_heap,
+ },
+ {
+ "name": "tp:destructor_c_same_unit_before_define",
+ "msg": None,
+ "count": 0,
+ "may_fail": compound_literal_on_heap,
+ },
+ {
+ "name": "tp:destructor_c_across_units_before_define",
+ "msg": None,
+ "count": 0,
+ "may_fail": compound_literal_on_heap,
+ },
+]
+expected_events_tp_so = [
+ {"name": "tp_so_c:constructor_c_provider_shared_library", "msg": None, "count": 0},
+ {
+ "name": "tp_so:constructor_cplusplus_provider_shared_library",
+ "msg": "global - shared library define and provider",
+ "count": 0,
+ },
+ {
+ "name": "tp_so:constructor_cplusplus_provider_shared_library",
+ "msg": "main() local - shared library define and provider",
+ "count": 0,
+ },
+ {
+ "name": "tp_so:destructor_cplusplus_provider_shared_library",
+ "msg": "main() local - shared library define and provider",
"count": 0,
},
{
"msg": "global - shared library define and provider",
"count": 0,
},
- {"name": "tp:destructor_c_across_units_after_provider", "msg": None, "count": 0},
- {"name": "tp:destructor_c_same_unit_after_provider", "msg": None, "count": 0},
- {"name": "tp:destructor_c_same_unit_before_provider", "msg": None, "count": 0},
- {"name": "tp:destructor_c_across_units_after_define", "msg": None, "count": 0},
- {"name": "tp:destructor_c_same_unit_after_define", "msg": None, "count": 0},
- {"name": "tp:destructor_c_same_unit_before_define", "msg": None, "count": 0},
- {"name": "tp:destructor_c_across_units_before_define", "msg": None, "count": 0},
- {"name": "tp_a:destructor_c_provider_static_archive", "msg": None, "count": 0},
- {"name": "tp_so:destructor_c_provider_shared_library", "msg": None, "count": 0},
+ {"name": "tp_so_c:destructor_c_provider_shared_library", "msg": None, "count": 0},
+]
+expected_events_tp_a = [
+ {"name": "tp_a_c:constructor_c_provider_static_archive", "msg": None, "count": 0},
+ {
+ "name": "tp_a:constructor_cplusplus_provider_static_archive",
+ "msg": "global - static archive define and provider",
+ "count": 0,
+ "may_fail": compound_literal_on_heap,
+ },
+ {
+ "name": "tp_a:constructor_cplusplus_provider_static_archive",
+ "msg": "main() local - static archive define and provider",
+ "count": 0,
+ },
+ {
+ "name": "tp_a:destructor_cplusplus_provider_static_archive",
+ "msg": "main() local - static archive define and provider",
+ "count": 0,
+ },
+ {
+ "name": "tp_a:destructor_cplusplus_provider_static_archive",
+ "msg": "global - static archive define and provider",
+ "count": 0,
+ "may_fail": compound_literal_on_heap,
+ },
+ {"name": "tp_a_c:destructor_c_provider_static_archive", "msg": None, "count": 0},
]
-def capture_trace(
- tap: lttngtest.TapGenerator, test_env: lttngtest._Environment
-) -> lttngtest.LocalSessionOutputLocation:
- tap.diagnostic(
- "Capture trace from application with instrumented C/C++ constructors/destructors"
- )
+def capture_trace(tap, test_env, application, description):
+ # type: (lttngtest.TapGenerator, lttngtest._Environment) -> lttngtest.LocalSessionOutputLocation
+ tap.diagnostic(description)
session_output_location = lttngtest.LocalSessionOutputLocation(
test_env.create_temporary_directory("trace")
)
- client: lttngtest.Controller = lttngtest.LTTngClient(test_env, log=tap.diagnostic)
+ client = lttngtest.LTTngClient(test_env, log=tap.diagnostic)
with tap.case("Create a session") as test_case:
session = client.create_session(output=session_output_location)
# Enable all user space events, the default for a user tracepoint event rule.
channel.add_recording_rule(lttngtest.UserTracepointEventRule("tp*"))
- session.start()
- test_app = test_env.launch_trace_test_constructor_application()
- test_app.wait_for_exit()
- session.stop()
- session.destroy()
+ with tap.case(
+ "Start session `{session_name}`".format(session_name=session.name)
+ ) as test_case:
+ session.start()
+
+ test_app = test_env.launch_test_application(application)
+ with tap.case(
+ "Run test app '{}'".format(application, session_name=session.name)
+ ) as test_case:
+ test_app.wait_for_exit()
+
+ with tap.case(
+ "Stop session `{session_name}`".format(session_name=session.name)
+ ) as test_case:
+ session.stop()
+
+ with tap.case(
+ "Destroy session `{session_name}`".format(session_name=session.name)
+ ) as test_case:
+ session.destroy()
+
return session_output_location
-def validate_trace(trace_location: pathlib.Path, tap: lttngtest.TapGenerator) -> bool:
- success = True
+def validate_trace(trace_location, tap, expected_events):
+ # type: (pathlib.Path, lttngtest.TapGenerator)
unknown_event_count = 0
for msg in bt2.TraceCollectionMessageIterator(str(trace_location)):
found = True
event["count"] = event["count"] + 1
break
+
if found == False:
unknown_event_count = unknown_event_count + 1
printmsg = None
)
for event in expected_events:
- if event["count"] != 1:
- success = False
- tap.diagnostic("Expected event {} not found".format(event["name"]))
- if unknown_event_count != 0:
- success = False
- return success
-
-
-tap = lttngtest.TapGenerator(num_tests)
-tap.diagnostic("Test user space constructor/destructor instrumentation coverage")
-
-with lttngtest.test_environment(with_sessiond=True, log=tap.diagnostic) as test_env:
- outputlocation = capture_trace(tap, test_env)
- tap.test(
- validate_trace(outputlocation.path, tap),
- "Validate that trace constains expected events",
- )
+ may_fail = "may_fail" in event.keys() and event["may_fail"]
+ if not may_fail:
+ tap.test(
+ event["count"] == 1,
+ 'Found expected event name="{}" msg="{}"'.format(
+ event["name"], str(event["msg"])
+ ),
+ ),
+ else:
+ tap.skip("Event '{}' may or may not be recorded".format(event["name"]))
+
+ tap.test(unknown_event_count == 0, "Found no unexpected events")
+
+
+success = True
+tests = [
+ {
+ "description": "Test user space constructor/destructor instrumentation coverage (C++ w/ static archive)",
+ "application": "gen-ust-events-constructor/gen-ust-events-constructor-a",
+ "expected_events": copy.deepcopy(expected_events_common + expected_events_tp_a),
+ "skip_if_application_not_present": False,
+ },
+ {
+ "description": "Test user space constructor/destructor instrumentation coverage (C++ w/ dynamic object",
+ "application": "gen-ust-events-constructor/gen-ust-events-constructor-so",
+ "expected_events": copy.deepcopy(
+ expected_events_common + expected_events_tp_so
+ ),
+ # This application is not be built when `NO_SHARED` is set in the
+ # configuration options.
+ "skip_if_application_not_present": True,
+ },
+]
+
+success = True
+for test in tests:
+ tap = lttngtest.TapGenerator(7 + len(test["expected_events"]))
+ with lttngtest.test_environment(with_sessiond=True, log=tap.diagnostic) as test_env:
+ try:
+ outputlocation = capture_trace(
+ tap, test_env, test["application"], test["description"]
+ )
+ except FileNotFoundError as fne:
+ tap.diagnostic(fne)
+ if test["skip_if_application_not_present"]:
+ tap.skip(
+ "Test application '{}' not found".format(test["application"]),
+ tap.remaining_test_cases,
+ )
+ break
+ # Warning: validate_trace mutates test['expected_events']
+ validate_trace(outputlocation.path, tap, test["expected_events"])
+ success = success and tap.is_successful
+
-sys.exit(0 if tap.is_successful else 1)
+sys.exit(0 if success else 1)