Skip to content

Commit 2b65d6b

Browse files
committed
gh-136336: add tests for PySys_Audit() and PySys_AuditTuple()
1 parent 8ac7613 commit 2b65d6b

File tree

2 files changed

+181
-5
lines changed

2 files changed

+181
-5
lines changed

Lib/test/test_capi/test_sys.py

Lines changed: 136 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,6 @@
1212
NULL = None
1313

1414
class CAPITest(unittest.TestCase):
15-
# TODO: Test the following functions:
16-
#
17-
# PySys_Audit()
18-
# PySys_AuditTuple()
19-
2015
maxDiff = None
2116

2217
@unittest.skipIf(_testlimitedcapi is None, 'need _testlimitedcapi module')
@@ -211,6 +206,142 @@ def test_sys_writestderr(self):
211206
# Test PySys_WriteStderr()
212207
self._test_sys_writestream('PySys_WriteStderr', 'stderr')
213208

209+
@unittest.skipIf(_testlimitedcapi is None, 'need _testlimitedcapi module')
210+
def test_sys_audit(self):
211+
sys_audit = _testlimitedcapi.sys_audit
212+
213+
audit_events = []
214+
def audit_hook(event, args):
215+
audit_events.append((event, args))
216+
return None
217+
218+
import sys
219+
sys.addaudithook(audit_hook)
220+
221+
try:
222+
result = sys_audit("cpython.run_command", "")
223+
self.assertEqual(result, 0)
224+
self.assertEqual(len(audit_events), 1)
225+
self.assertEqual(audit_events[-1][0], "cpython.run_command")
226+
self.assertEqual(audit_events[-1][1], ())
227+
228+
result = sys_audit("open", "OOO", "test.txt", "r", 0)
229+
self.assertEqual(result, 0)
230+
self.assertEqual(len(audit_events), 2)
231+
self.assertEqual(audit_events[-1][0], "open")
232+
self.assertEqual(len(audit_events[-1][1]), 3)
233+
self.assertEqual(audit_events[-1][1][0], "test.txt")
234+
self.assertEqual(audit_events[-1][1][1], "r")
235+
self.assertEqual(audit_events[-1][1][2], 0)
236+
237+
test_dict = {"key": "value"}
238+
test_list = [1, 2, 3]
239+
result = sys_audit("test.objects", "OO", test_dict, test_list)
240+
self.assertEqual(result, 0)
241+
self.assertEqual(len(audit_events), 3)
242+
self.assertEqual(audit_events[-1][0], "test.objects")
243+
self.assertEqual(audit_events[-1][1][0], test_dict)
244+
self.assertEqual(audit_events[-1][1][1], test_list)
245+
246+
result = sys_audit("test.mixed_types", "OOO", "string", 42, 123456789)
247+
self.assertEqual(result, 0)
248+
self.assertEqual(len(audit_events), 4)
249+
self.assertEqual(audit_events[-1][0], "test.mixed_types")
250+
self.assertEqual(audit_events[-1][1][0], "string")
251+
self.assertEqual(audit_events[-1][1][1], 42)
252+
self.assertEqual(audit_events[-1][1][2], 123456789)
253+
254+
finally:
255+
sys.audit_hooks = []
256+
257+
result = sys_audit("cpython.run_file", "")
258+
self.assertEqual(result, 0)
259+
260+
result = sys_audit("os.chdir", "(O)", "/tmp")
261+
self.assertEqual(result, 0)
262+
263+
result = sys_audit("ctypes.dlopen", "O", "libc.so.6")
264+
self.assertEqual(result, 0)
265+
266+
self.assertRaises(TypeError, sys_audit, 123, "O", "arg")
267+
self.assertRaises(TypeError, sys_audit, None, "O", "arg")
268+
self.assertRaises(TypeError, sys_audit, ["not", "a", "string"], "O", "arg")
269+
270+
self.assertRaises(TypeError, sys_audit, "test.event", 456, "arg")
271+
self.assertRaises(TypeError, sys_audit, "test.event", None, "arg")
272+
self.assertRaises(TypeError, sys_audit, "test.event", {"format": "string"}, "arg")
273+
274+
@unittest.skipIf(_testlimitedcapi is None, 'need _testlimitedcapi module')
275+
def test_sys_audittuple(self):
276+
sys_audittuple = _testlimitedcapi.sys_audittuple
277+
278+
# Test with audit hook to verify internal behavior
279+
audit_events = []
280+
def audit_hook(event, args):
281+
audit_events.append((event, args))
282+
return None
283+
284+
import sys
285+
sys.addaudithook(audit_hook)
286+
287+
try:
288+
result = sys_audittuple("cpython.run_command", ())
289+
self.assertEqual(result, 0)
290+
self.assertEqual(len(audit_events), 1)
291+
self.assertEqual(audit_events[-1][0], "cpython.run_command")
292+
self.assertEqual(audit_events[-1][1], ())
293+
294+
result = sys_audittuple("os.chdir", ("/tmp",))
295+
self.assertEqual(result, 0)
296+
self.assertEqual(len(audit_events), 2)
297+
self.assertEqual(audit_events[-1][0], "os.chdir")
298+
self.assertEqual(audit_events[-1][1], ("/tmp",))
299+
300+
result = sys_audittuple("open", ("test.txt", "r", 0))
301+
self.assertEqual(result, 0)
302+
self.assertEqual(len(audit_events), 3)
303+
self.assertEqual(audit_events[-1][0], "open")
304+
self.assertEqual(audit_events[-1][1], ("test.txt", "r", 0))
305+
306+
test_dict = {"key": "value"}
307+
test_list = [1, 2, 3]
308+
result = sys_audittuple("test.objects", (test_dict, test_list))
309+
self.assertEqual(result, 0)
310+
self.assertEqual(len(audit_events), 4)
311+
self.assertEqual(audit_events[-1][0], "test.objects")
312+
self.assertEqual(audit_events[-1][1][0], test_dict)
313+
self.assertEqual(audit_events[-1][1][1], test_list)
314+
315+
result = sys_audittuple("test.complex", ("text", 3.14, True, None))
316+
self.assertEqual(result, 0)
317+
self.assertEqual(len(audit_events), 5)
318+
self.assertEqual(audit_events[-1][0], "test.complex")
319+
self.assertEqual(audit_events[-1][1][0], "text")
320+
self.assertEqual(audit_events[-1][1][1], 3.14)
321+
self.assertEqual(audit_events[-1][1][2], True)
322+
self.assertEqual(audit_events[-1][1][3], None)
323+
324+
finally:
325+
sys.audit_hooks = []
326+
327+
result = sys_audittuple("cpython.run_file", ())
328+
self.assertEqual(result, 0)
329+
330+
result = sys_audittuple("ctypes.dlopen", ("libc.so.6",))
331+
self.assertEqual(result, 0)
332+
333+
result = sys_audittuple("sqlite3.connect", ("test.db",))
334+
self.assertEqual(result, 0)
335+
336+
self.assertRaises(TypeError, sys_audittuple, 123, ("arg",))
337+
self.assertRaises(TypeError, sys_audittuple, None, ("arg",))
338+
self.assertRaises(TypeError, sys_audittuple, ["not", "a", "string"], ("arg",))
339+
340+
self.assertRaises(TypeError, sys_audittuple, "test.event", "not_a_tuple")
341+
self.assertRaises(TypeError, sys_audittuple, "test.event", ["list", "not", "tuple"])
342+
self.assertRaises(TypeError, sys_audittuple, "test.event", {"dict": "not_tuple"})
343+
self.assertRaises(TypeError, sys_audittuple, "test.event", None)
344+
214345

215346
if __name__ == "__main__":
216347
unittest.main()

Modules/_testlimitedcapi/sys.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#endif
66
#include "parts.h"
77
#include "util.h"
8+
#include "audit.h"
89

910

1011
static PyObject *
@@ -106,6 +107,48 @@ sys_getxoptions(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(ignored))
106107
return Py_XNewRef(result);
107108
}
108109

110+
static PyObject *
111+
sys_audit(PyObject *Py_UNUSED(module), PyObject *args)
112+
{
113+
const char *event;
114+
const char *argFormat;
115+
PyObject *arg1 = NULL, *arg2 = NULL, *arg3 = NULL;
116+
117+
if (!PyArg_ParseTuple(args, "ss|OOO", &event, &argFormat, &arg1, &arg2, &arg3)) {
118+
return NULL;
119+
}
120+
121+
int result;
122+
if (arg1 == NULL) {
123+
result = PySys_Audit(event, argFormat);
124+
} else if (arg2 == NULL) {
125+
result = PySys_Audit(event, argFormat, arg1);
126+
} else if (arg3 == NULL) {
127+
result = PySys_Audit(event, argFormat, arg1, arg2);
128+
} else {
129+
result = PySys_Audit(event, argFormat, arg1, arg2, arg3);
130+
}
131+
132+
RETURN_INT(result);
133+
}
134+
135+
static PyObject *
136+
sys_audittuple(PyObject *Py_UNUSED(module), PyObject *args)
137+
{
138+
const char *event;
139+
PyObject *tuple_args;
140+
141+
if (!PyArg_ParseTuple(args, "sO", &event, &tuple_args)) {
142+
return NULL;
143+
}
144+
145+
if (!PyTuple_Check(tuple_args)) {
146+
PyErr_SetString(PyExc_TypeError, "second argument must be a tuple");
147+
return NULL;
148+
}
149+
150+
RETURN_INT(PySys_AuditTuple(event, tuple_args));
151+
}
109152

110153
static PyMethodDef test_methods[] = {
111154
{"sys_getattr", sys_getattr, METH_O},
@@ -115,6 +158,8 @@ static PyMethodDef test_methods[] = {
115158
{"sys_getobject", sys_getobject, METH_O},
116159
{"sys_setobject", sys_setobject, METH_VARARGS},
117160
{"sys_getxoptions", sys_getxoptions, METH_NOARGS},
161+
{"sys_audit", sys_audit, METH_VARARGS},
162+
{"sys_audittuple", sys_audittuple, METH_VARARGS},
118163
{NULL},
119164
};
120165

0 commit comments

Comments
 (0)