[PATCH 3/3] test/unittest: Add basic python bindings tests
Alan Maguire <[email protected]> Fri, 15 May 2026 14:44:15 +0100
| Newsgroups | dev.linux.lists.dtrace |
|---|---|
| Message-ID | <[email protected]> |
Add tests to read an aggregation from a python-invoked DTrace session, grab a process and trace it, and create a process and trace it. Signed-off-by: Alan Maguire <[email protected]> --- test/unittest/python/tst.aggr.sh | 59 ++++++++++++++++++ test/unittest/python/tst.proc-create.sh | 56 +++++++++++++++++ test/unittest/python/tst.proc-grab.sh | 81 +++++++++++++++++++++++++ 3 files changed, 196 insertions(+) create mode 100755 test/unittest/python/tst.aggr.sh create mode 100755 test/unittest/python/tst.proc-create.sh create mode 100755 test/unittest/python/tst.proc-grab.sh diff --git a/test/unittest/python/tst.aggr.sh b/test/unittest/python/tst.aggr.sh new file mode 100755 index 00000000..9c2daa67 --- /dev/null +++ b/test/unittest/python/tst.aggr.sh @@ -0,0 +1,59 @@ +#!/bin/bash +# +# Oracle Linux DTrace. +# Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. +# Licensed under the Universal Permissive License v 1.0 as shown at +# http://oss.oracle.com/licenses/upl. +# +# Ensure aggregation can be retrieved from simple D script. + +if [ $# -ne 1 ]; then + echo "usage: $0 <dtrace>" >&2 + exit 2 +fi + +dtrace=$1 + +tmpdir=$(mktemp -d) +cleanup() { + rm -rf "$tmpdir" +} +trap cleanup EXIT + +cat >"$tmpdir"/script.d <<EOF +#!/usr/bin/env python3 +from pathlib import Path +from subprocess import Popen + +from dtrace import DTraceSession + +prog = r""" +syscall:::entry +{ + @counts[execname, probefunc] = count(); +} +""" + +with DTraceSession() as dt: + p = dt.compile(prog) + dt.enable(p) + dt.go() + pid = Popen(["/bin/sleep", "1"]).wait() + dt.stop() + dt.agg_snap() + rows = dt.agg_walk() + +if not rows: + raise SystemExit("no rows returned") + +entry = rows[0] +if "keys" not in entry or "value" not in entry: + raise SystemExit("missing keys or value") + +print("keys=", str(entry["keys"]), "value=", str(entry["value"])) +EOF + +chmod +x "$tmpdir/script.d" +PATH="$tmpdir:$PATH" + +$tmpdir/script.d diff --git a/test/unittest/python/tst.proc-create.sh b/test/unittest/python/tst.proc-create.sh new file mode 100755 index 00000000..e9d2d466 --- /dev/null +++ b/test/unittest/python/tst.proc-create.sh @@ -0,0 +1,56 @@ +#!/bin/bash +# +# Oracle Linux DTrace. +# Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. +# Licensed under the Universal Permissive License v 1.0 as shown at +# http://oss.oracle.com/licenses/upl. +# +# Validate tracing of a spawned command. + +if [ $# -ne 1 ]; then + echo "usage: $0 <dtrace>" >&2 + exit 2 +fi + +dtrace=$1 + +tmpdir=$(mktemp -d) +cleanup() { + rm -rf "$tmpdir" +} +trap cleanup EXIT + +cat >"$tmpdir"/script.py <<'EOF' +#!/usr/bin/env python3 +from subprocess import Popen +from dtrace import DTraceSession + +prog = r""" +syscall::read:entry +{ + @calls[execname] = count(); +} +""" + +with DTraceSession() as dt: + p = dt.compile(prog) + dt.enable(p) + dt.go() + proc = dt.proc_create(["/bin/echo", "hello"]) + dt.proc_continue(proc) + dt.proc_release(proc) + dt.stop() + dt.agg_snap() + rows = dt.agg_walk() + +if not rows: + raise SystemExit("no aggregation rows") + +names = {tuple(entry["keys"]) for entry in rows} +if not any("echo" in key for key in names): + raise SystemExit("expected echo entry in aggregation") +EOF + +chmod +x "$tmpdir/script.py" + +$tmpdir/script.py diff --git a/test/unittest/python/tst.proc-grab.sh b/test/unittest/python/tst.proc-grab.sh new file mode 100755 index 00000000..21faca65 --- /dev/null +++ b/test/unittest/python/tst.proc-grab.sh @@ -0,0 +1,81 @@ +#!/bin/bash +# +# Oracle Linux DTrace. +# Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. +# Licensed under the Universal Permissive License v 1.0 as shown at +# http://oss.oracle.com/licenses/upl. +# +# Ensure Python bindings can grab an existing process and trace its syscalls. + +if [ $# -ne 1 ]; then + echo "usage: $0 <dtrace>" >&2 + exit 2 +fi + +dtrace=$1 + +tmpdir=$(mktemp -d) +cleanup() { + rm -rf "$tmpdir" +} +trap cleanup EXIT + +# Start a long-lived helper shell to grab. +sleep_inf="$tmpdir/sleep.sh" +cat >"$sleep_inf" <<'EOF' +#!/bin/bash +while :; do + sleep 1 +done +EOF +chmod +x "$sleep_inf" +"$sleep_inf" & +helper=$! + +cat >"$tmpdir"/script.py <<'EOF' +#!/usr/bin/env python3 +import os +import sys +from subprocess import Popen +from dtrace import DTraceSession + +prog = r""" +syscall:::entry +/ pid == $target / +{ + @counts[execname, probefunc] = count(); +} +""" + +pid = int(os.environ["TARGET_PID"]) + +with DTraceSession() as dt: + proc = dt.proc_grab_pid(pid) + if proc.getpid() != pid: + raise SystemExit("grabbed PID mismatch") + p = dt.compile(prog) + dt.enable(p) + dt.go() + dt.proc_continue(proc) + Popen(["/bin/sleep", "5"]).wait() + dt.stop() + dt.proc_release(proc) + dt.agg_snap() + rows = dt.agg_walk() + +if not rows: + raise SystemExit("no rows returned") + +entry = rows[0] +if "keys" not in entry or "value" not in entry: + raise SystemExit("missing keys or value") +EOF + +chmod +x "$tmpdir/script.py" +export TARGET_PID=$helper +$tmpdir/script.py +ret=$? + +kill $helper +wait $helper 2>/dev/null || true +exit $ret -- 2.43.5