summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/test/test_dtrace.py82
1 files changed, 82 insertions, 0 deletions
diff --git a/Lib/test/test_dtrace.py b/Lib/test/test_dtrace.py
index 4b971de..e1adf8e 100644
--- a/Lib/test/test_dtrace.py
+++ b/Lib/test/test_dtrace.py
@@ -3,6 +3,7 @@ import os.path
import re
import subprocess
import sys
+import sysconfig
import types
import unittest
@@ -173,6 +174,87 @@ class SystemTapOptimizedTests(TraceTests, unittest.TestCase):
backend = SystemTapBackend()
optimize_python = 2
+class CheckDtraceProbes(unittest.TestCase):
+ @classmethod
+ def setUpClass(cls):
+ if sysconfig.get_config_var('WITH_DTRACE'):
+ readelf_major_version, readelf_minor_version = cls.get_readelf_version()
+ if support.verbose:
+ print(f"readelf version: {readelf_major_version}.{readelf_minor_version}")
+ else:
+ raise unittest.SkipTest("CPython must be configured with the --with-dtrace option.")
+
+
+ @staticmethod
+ def get_readelf_version():
+ try:
+ cmd = ["readelf", "--version"]
+ proc = subprocess.Popen(
+ cmd,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ universal_newlines=True,
+ )
+ with proc:
+ version, stderr = proc.communicate()
+
+ if proc.returncode:
+ raise Exception(
+ f"Command {' '.join(cmd)!r} failed "
+ f"with exit code {proc.returncode}: "
+ f"stdout={version!r} stderr={stderr!r}"
+ )
+ except OSError:
+ raise unittest.SkipTest("Couldn't find readelf on the path")
+
+ # Regex to parse:
+ # 'GNU readelf (GNU Binutils) 2.40.0\n' -> 2.40
+ match = re.search(r"^(?:GNU) readelf.*?\b(\d+)\.(\d+)", version)
+ if match is None:
+ raise unittest.SkipTest(f"Unable to parse readelf version: {version}")
+
+ return int(match.group(1)), int(match.group(2))
+
+ def get_readelf_output(self):
+ command = ["readelf", "-n", sys.executable]
+ stdout, _ = subprocess.Popen(
+ command,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ universal_newlines=True,
+ ).communicate()
+ return stdout
+
+ def test_check_probes(self):
+ readelf_output = self.get_readelf_output()
+
+ available_probe_names = [
+ "Name: import__find__load__done",
+ "Name: import__find__load__start",
+ "Name: audit",
+ "Name: gc__start",
+ "Name: gc__done",
+ ]
+
+ for probe_name in available_probe_names:
+ with self.subTest(probe_name=probe_name):
+ self.assertIn(probe_name, readelf_output)
+
+ @unittest.expectedFailure
+ def test_missing_probes(self):
+ readelf_output = self.get_readelf_output()
+
+ # Missing probes will be added in the future.
+ missing_probe_names = [
+ "Name: function__entry",
+ "Name: function__return",
+ "Name: line",
+ ]
+
+ for probe_name in missing_probe_names:
+ with self.subTest(probe_name=probe_name):
+ self.assertIn(probe_name, readelf_output)
+
if __name__ == '__main__':
unittest.main()