Skip to content

gh-136336: add tests for PySys_Audit() and PySys_AuditTuple() #136337

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

alex-semenyuk
Copy link
Contributor

@alex-semenyuk alex-semenyuk commented Jul 6, 2025

Cover by tests PySys_Audit() and PySys_AuditTuple() as mentioned at TODO

Copy link
Contributor

@LamentXU123 LamentXU123 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Edited: In general (or at least formar test functions) we put a comment of the tested function at the first line

Comment on lines 276 to 278
sys_audittuple = _testlimitedcapi.sys_audittuple

# Test with audit hook to verify internal behavior
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
sys_audittuple = _testlimitedcapi.sys_audittuple
# Test with audit hook to verify internal behavior
# Test PySys_AuditTuple()
sys_audittuple = _testlimitedcapi.sys_audittuple
# Test with audit hook to verify internal behavior
return NULL;
}

if (!PyTuple_Check(tuple_args)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't check the argument here. Let PySys_AuditTuple() to check it. And test it with wrong type of argument.

const char *event;
PyObject *tuple_args;

if (!PyArg_ParseTuple(args, "sO", &event, &tuple_args)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make the second argument optional and NULL by default. This will allow you to test with NULL.

Use z# for the first argument. This will allow you to test with non-UTF-8 bytestring and with NULL.

const char *argFormat;
PyObject *arg1 = NULL, *arg2 = NULL, *arg3 = NULL;

if (!PyArg_ParseTuple(args, "ss|OOO", &event, &argFormat, &arg1, &arg2, &arg3)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use z# for even and format. Test with non-UTF-8 bytestring and with NULL.

Comment on lines 336 to 343
self.assertRaises(TypeError, sys_audittuple, 123, ("arg",))
self.assertRaises(TypeError, sys_audittuple, None, ("arg",))
self.assertRaises(TypeError, sys_audittuple, ["not", "a", "string"], ("arg",))

self.assertRaises(TypeError, sys_audittuple, "test.event", "not_a_tuple")
self.assertRaises(TypeError, sys_audittuple, "test.event", ["list", "not", "tuple"])
self.assertRaises(TypeError, sys_audittuple, "test.event", {"dict": "not_tuple"})
self.assertRaises(TypeError, sys_audittuple, "test.event", None)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These tests don't test PySys_AuditTuple. They test the wrapper.

Comment on lines 327 to 334
result = sys_audittuple("cpython.run_file", ())
self.assertEqual(result, 0)

result = sys_audittuple("ctypes.dlopen", ("libc.so.6",))
self.assertEqual(result, 0)

result = sys_audittuple("sqlite3.connect", ("test.db",))
self.assertEqual(result, 0)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do these test add in comparison with the above tests?

audit_events = []
def audit_hook(event, args):
audit_events.append((event, args))
return None
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is redundant.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return None
audit_events.append((event, args))
return None

import sys
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Import it at the top level.

Comment on lines 288 to 322
result = sys_audittuple("cpython.run_command", ())
self.assertEqual(result, 0)
self.assertEqual(len(audit_events), 1)
self.assertEqual(audit_events[-1][0], "cpython.run_command")
self.assertEqual(audit_events[-1][1], ())

result = sys_audittuple("os.chdir", ("/tmp",))
self.assertEqual(result, 0)
self.assertEqual(len(audit_events), 2)
self.assertEqual(audit_events[-1][0], "os.chdir")
self.assertEqual(audit_events[-1][1], ("/tmp",))

result = sys_audittuple("open", ("test.txt", "r", 0))
self.assertEqual(result, 0)
self.assertEqual(len(audit_events), 3)
self.assertEqual(audit_events[-1][0], "open")
self.assertEqual(audit_events[-1][1], ("test.txt", "r", 0))

test_dict = {"key": "value"}
test_list = [1, 2, 3]
result = sys_audittuple("test.objects", (test_dict, test_list))
self.assertEqual(result, 0)
self.assertEqual(len(audit_events), 4)
self.assertEqual(audit_events[-1][0], "test.objects")
self.assertEqual(audit_events[-1][1][0], test_dict)
self.assertEqual(audit_events[-1][1][1], test_list)

result = sys_audittuple("test.complex", ("text", 3.14, True, None))
self.assertEqual(result, 0)
self.assertEqual(len(audit_events), 5)
self.assertEqual(audit_events[-1][0], "test.complex")
self.assertEqual(audit_events[-1][1][0], "text")
self.assertEqual(audit_events[-1][1][1], 3.14)
self.assertEqual(audit_events[-1][1][2], True)
self.assertEqual(audit_events[-1][1][3], None)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are too many tests which don't add much to coverage. You only need one test with non-empty tuple, one test with NULL as the second argument, one test with non-tuple as the second argument, and few tests for the event argument: non-ASCII string, non-UTF-8 bytes string, NULL.

Copy link
Member

@serhiy-storchaka serhiy-storchaka left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your update. Here is a new batch of comments.

Comment on lines 152 to 160
if (event == NULL) {
RETURN_INT(0);
}

if (tuple_args != NULL && !PyTuple_Check(tuple_args)) {
PyErr_SetString(PyExc_TypeError, "second argument must be a tuple");
return NULL;
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should test how PySys_AuditTuple() handles this.

Suggested change
if (event == NULL) {
RETURN_INT(0);
}
if (tuple_args != NULL && !PyTuple_Check(tuple_args)) {
PyErr_SetString(PyExc_TypeError, "second argument must be a tuple");
return NULL;
}
audit_events = []
def audit_hook(event, args):
audit_events.append((event, args))
return None
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return None
with self.assertRaises(UnicodeDecodeError):
sys_audittuple(b"test.non_utf8\xff", (1,))
finally:
sys.audit_hooks = []
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, this does not work. There is no way to remove the audit hook. This is why these functions remained untested -- because the only way to test them is to use a subprocess. Look like other audit tests are implemented.

Comment on lines 123 to 126
if (event == NULL) {
RETURN_INT(0);
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (event == NULL) {
RETURN_INT(0);
}

with self.assertRaises(UnicodeDecodeError):
sys_audit(b"test.non_utf8\xff", "O", 1)
finally:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add also tests for sys_audit("test.event", "("), sys_audit("test.event", "&"), sys_audit("test.event", b"\xff") and sys_audit("test.event", "{OO}", [], []).

Add also tests for sys_audit(NULL, "O", 1) and sys_audit("test.event", NULL). If they crash, just add comments.


with self.assertRaises(UnicodeDecodeError):
sys_audittuple(b"test.non_utf8\xff", (1,))
finally:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add also test for sys_audittuple(NULL, (1,)). If it crashes, just add a comment, like in other tests above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment